OutilModbus/Sources/ModbusBackend.cpp
2022-06-13 09:16:01 -04:00

708 lines
23 KiB
C++

#include "ModbusBackend.h"
#include "QBuffer"
#include <QDataStream>
CModbusBackend::CModbusBackend(CModbusRepository *Repo)
{
mModbusTCPSocketHandle = 0;
mDataLinkValid = false;
mModbusRepo = Repo;
mModbusMode = MODBUS_INVALID_MODE;
mTransactionIDCounter = 0;
mDeviceID = 1;//0xFF;
mModbusMaxRetry = MODBUS_RETRY_MAX_COUNT;
mModbusRequestTimeout = MODBUS_RETRY_DELAY;
}
CModbusBackend::~CModbusBackend()
{
}
void CModbusBackend::ModbusDataReady()
{
CModbusTransaction Transaction;
QByteArray InData = mModbusTCPSocketHandle->readAll();
QBuffer FileBuffer(&InData);
FileBuffer.open(QIODevice::ReadOnly);
FileBuffer.seek(0);
QDataStream *TransactionDataStrm = new QDataStream(&FileBuffer);
*TransactionDataStrm >> Transaction.mHeader;
*TransactionDataStrm >> Transaction.mPDU.mFunctionCode;
Transaction.mPDU.mData = InData.right(Transaction.mHeader.mMessageLength - 2); //-2 to remove Device ID and Function Code.
// qDebug("modbus data received %s",InData.toHex().data());
// qDebug("Transaction ID 0x%X",Transaction.mHeader.mTransactionID);
// qDebug("Message Length %d",Transaction.mHeader.mMessageLength);
// qDebug("Protocol ID 0x%X",Transaction.mHeader.mProtocolID);
// qDebug("Unit ID 0x%X",Transaction.mHeader.mUnitID);
// qDebug("Function Code 0x%X",Transaction.mPDU.mFunctionCode);
// qDebug("Data %s",Transaction.mPDU.mData.toHex().data());
if(mModbusMode == MODBUS_MASTER_MODE)
{
AnalyzeModbusResponse(Transaction);
}
else if( mModbusMode == MODBUS_SLAVE_MODE)
{
AnalyzeModbusRequest(Transaction);
}
else
{
qDebug("Illegal modbus backend mode...");
}
emit ModbusRX();
}
void CModbusBackend::ModbusLinkDisconnected()
{
qDebug("Modbus link disconnected");
mDataLinkValid = false;
}
//In client mode. This is the request from the master.
int CModbusBackend::AnalyzeModbusRequest(CModbusTransaction Transaction)
{
if(Transaction.mHeader.mProtocolID != 0)
{
//Invalid protocol... what can we do?
return 0;
}
switch(Transaction.mPDU.mFunctionCode)
{
case MODBUS_FCT_READ_HOLDING_REGISTERS:
{
bool ok = true;
unsigned short StartAdress = 0;
StartAdress = Transaction.mPDU.mData[0]&0xFF;
StartAdress <<= 8;
StartAdress += Transaction.mPDU.mData[1]&0xFF;
unsigned short NbRegisters = 0;
NbRegisters = Transaction.mPDU.mData[2]&0xFF;
NbRegisters <<= 8;
NbRegisters += Transaction.mPDU.mData[3]&0xFF;
//Validate nb of registers
if(NbRegisters < 1 || NbRegisters > MODBUS_MAX_NB_REGISTERS)
{
SendErrorResponse(Transaction,MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE);
// emit ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,MODBUS_FCT_READ_HOLDING_REGISTERS);
ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,MODBUS_FCT_READ_HOLDING_REGISTERS);
return 0;
}
//Validate data range
if(!mModbusRepo->IsHRValid(StartAdress,NbRegisters))
{
qDebug("Reg invalid");
//Send negative response
SendErrorResponse(Transaction,MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS);
// emit ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,MODBUS_FCT_READ_HOLDING_REGISTERS);
ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,MODBUS_FCT_READ_HOLDING_REGISTERS);
return 0;
}
QByteArray data = mModbusRepo->GetHRData(StartAdress,NbRegisters,&ok);
// qDebug("Slave Rx Read Holding Registers. Address: %d, Nb Reg: %d",StartAdress, NbRegisters);
// qDebug("Data: %s",data.toHex().data());
//The response to a HR reading needs the byte count before the data.
quint8 ByteCount = data.size();
data.prepend(ByteCount);
SendModbusResponse(Transaction, data);
//All OK
break;
}
case MODBUS_WRITE_SINGLE_REGISTER:
{
unsigned short StartAdress = 0;
StartAdress = Transaction.mPDU.mData[0]&0xFF;
StartAdress <<= 8;
StartAdress += Transaction.mPDU.mData[1]&0xFF;
//Validate data range
if(!mModbusRepo->IsHRValid(StartAdress,1))
{
qDebug("Reg invalid");
//Send negative response
SendErrorResponse(Transaction,MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS);
// emit ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,MODBUS_WRITE_SINGLE_REGISTER);
ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,MODBUS_WRITE_SINGLE_REGISTER);
return 0;
}
//Extract data.
QByteArray data = Transaction.mPDU.mData.right(2);
//Write register data
mModbusRepo->WriteHRData(StartAdress,1,data);
// qDebug("Slave Rx Write Single Register. Address: %d, Value: 0x%s",StartAdress, data.toHex().data());
// qDebug("Data: %s",data.toHex().data());
data = Transaction.mPDU.mData.left(4); //The response corresponds to the Reg. Address & the value. Which is the first 4 bytes of the initial request.
SendModbusResponse(Transaction, data);
// emit RegistersDatabaseUpdated(StartAdress,1);
RegistersDatabaseUpdated(StartAdress,1);
break;
}
case MODBUS_FCT_WRITE_MULTIPLE_REGISTERS:
{
unsigned short StartAdress = 0;
StartAdress = Transaction.mPDU.mData[0]&0xFF;
StartAdress <<= 8;
StartAdress += Transaction.mPDU.mData[1]&0xFF;
unsigned short NbRegisters = 0;
NbRegisters = Transaction.mPDU.mData[2]&0xFF;
NbRegisters <<= 8;
NbRegisters += Transaction.mPDU.mData[3]&0xFF;
quint8 ByteCount = Transaction.mPDU.mData[4];
//Validate nb of registers
if(NbRegisters < 1 || NbRegisters > 0x7D || ByteCount != (NbRegisters*2))
{
qDebug("Invalid register number or byte count ");
SendErrorResponse(Transaction,MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE);
// emit ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,MODBUS_FCT_WRITE_MULTIPLE_REGISTERS);
ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,MODBUS_FCT_WRITE_MULTIPLE_REGISTERS);
return 0;
}
//Validate data range
if(!mModbusRepo->IsHRValid(StartAdress,NbRegisters))
{
qDebug("Reg invalid");
//Send negative response
SendErrorResponse(Transaction,MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS);
// emit ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,MODBUS_FCT_WRITE_MULTIPLE_REGISTERS);
ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,MODBUS_FCT_WRITE_MULTIPLE_REGISTERS);
return 0;
}
//Extract data.
QByteArray data = Transaction.mPDU.mData.right(ByteCount);
//Write register data
mModbusRepo->WriteHRData(StartAdress,NbRegisters,data);
// qDebug("Slave Rx Write Multiple Registers. Address: %d, Nb Reg: %d",StartAdress, NbRegisters);
// qDebug("Data: %s",data.toHex().data());
data = Transaction.mPDU.mData.left(4); //The response corresponds to the Start Adress and Nb of Regs. Which is the first 4 bytes of the initial request.
SendModbusResponse(Transaction, data);
// emit RegistersDatabaseUpdated(StartAdress,NbRegisters);
RegistersDatabaseUpdated(StartAdress,NbRegisters);
break;
}
default:
{
//Received "Illegal function code". Send the exception code to master
//TODO: Log this.
qDebug("Slave received illegal function code from master: 0x%x",Transaction.mPDU.mFunctionCode);
SendErrorResponse(Transaction,MODBUS_EXCEPTION_ILLEGAL_FCT);
// emit ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_FCT,Transaction.mPDU.mFunctionCode);
ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_FCT,Transaction.mPDU.mFunctionCode);
break;
}
}
return 1;
}
int CModbusBackend::SendModbusResponse(CModbusTransaction RequestTransaction, QByteArray Data)
{
QByteArray ModbusPacket;
QBuffer Buffer(&ModbusPacket);
Buffer.open(QIODevice::WriteOnly|QIODevice::Unbuffered);
Buffer.seek(0);
QDataStream *PacketDataStrm = new QDataStream(&Buffer);
//For a response, the header will be the same as the original request, except for the msg. length.
//Set the appropriate msg length.
RequestTransaction.mHeader.mMessageLength = Data.size() + 2; //+2 to add function code & Unit ID.
RequestTransaction.mPDU.mData = Data;
*PacketDataStrm << RequestTransaction.mHeader;
*PacketDataStrm << RequestTransaction.mPDU.mFunctionCode;
Buffer.close();
ModbusPacket.append(Data);
// qDebug("Response packet: %s",ModbusPacket.toHex().data());
mModbusTCPSocketHandle->write(ModbusPacket);
delete PacketDataStrm;
return RET_OK;
}
//In Master mode. This is the response from slave to a previously sent request.
int CModbusBackend::AnalyzeModbusResponse(CModbusTransaction Transaction)
{
if(Transaction.mHeader.mProtocolID != 0)
{
//Invalid protocol... what can we do?
return RET_ERROR;
}
//Find matching request and remove it from the queue...
CModbusRequest *Request;
bool Found = false;
for(int i = 0; i < mRequestsList.size(); i++)
{
if(mRequestsList.at(i)->mHeader.mTransactionID == Transaction.mHeader.mTransactionID)
{
Request = mRequestsList.takeAt(i); //Remove from queue and keep a copy
Request->mRequestTimer->stop(); //Stop the resend timer
Found = true;
}
}
if(Found == false)
{
//Invalid request number. This should happen only if a very long delay exists in the comm.
//TODO: Log this...
qDebug("Master received response to a non existent request!!!");
return RET_ERROR;
}
//check if we have an exception response
if((Transaction.mPDU.mFunctionCode & MODBUS_EXCEPTION_FCT_MASK) != 0)
{
//we have an exception response... something went wrong.
quint8 ExceptionCode = Transaction.mPDU.mData[0];
//TODO: Manage this!
qDebug("Master Rx exception code %d to request %d",ExceptionCode,Request->mPDU.mFunctionCode);
emit ModbusResponseException(ExceptionCode,Request->mPDU.mFunctionCode);
delete Request;
return RET_ERROR;
}
switch(Transaction.mPDU.mFunctionCode)
{
case MODBUS_FCT_READ_HOLDING_REGISTERS:
{
quint8 ByteCount = 0;
ByteCount = Transaction.mPDU.mData.at(0);
if((Request->mNbRegisters*2) != ByteCount)
{
//Inconsistency between the data range and the data count.
//TODO: Log the error.
qDebug("Master eceived a wrong data size in response for a MODBUS_FCT_READ_HOLDING_REGISTERS request");
emit ModbusResponseException(MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,MODBUS_FCT_READ_HOLDING_REGISTERS);
delete Request;
return RET_ERROR;
}
QByteArray RegisterValues = Transaction.mPDU.mData.right(ByteCount);
// qDebug("Master Rx Read Holding Registers Response.");
// qDebug("Data: %s",RegisterValues.toHex().data());
mModbusRepo->WriteHRData(Request->mStartAddress,Request->mNbRegisters,RegisterValues);
RegistersDatabaseUpdated(Request->mStartAddress, Request->mNbRegisters);
break;
}
case MODBUS_WRITE_SINGLE_REGISTER:
{
quint16 RegAddress = 0;
RegAddress = Transaction.mPDU.mData[0]&0xFF;
RegAddress <<= 8;
RegAddress += Transaction.mPDU.mData[1]&0xFF;
if(Request->mStartAddress != RegAddress)
{
//Inconsistency between the request Adress and response Adress.
//TODO: Log the error.
qDebug("Master received a wrong Register Adress in response for a MODBUS_WRITE_SINGLE_REGISTER request. Expected [%d], Rx[%d]",Request->mStartAddress, RegAddress);
emit ModbusResponseException(MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,MODBUS_WRITE_SINGLE_REGISTER);
delete Request;
return RET_ERROR;
}
// qDebug("Master Rx Write Single Register response. Address: %d,",RegAddress);
// qDebug("Data: %s",Transaction.mPDU.mData.toHex().data());
//Everything seems good.
break;
}
case MODBUS_FCT_WRITE_MULTIPLE_REGISTERS:
{
unsigned short StartAdress = 0;
StartAdress = Transaction.mPDU.mData[0]&0xFF;
StartAdress <<= 8;
StartAdress += Transaction.mPDU.mData[1]&0xFF;
unsigned short NbRegisters = 0;
NbRegisters = Transaction.mPDU.mData[2]&0xFF;
NbRegisters <<= 8;
NbRegisters += Transaction.mPDU.mData[3]&0xFF;
if(StartAdress != Request->mStartAddress || NbRegisters != Request->mNbRegisters)
{
//Inconsistency between the request Adress or NbRegisters and response.
//TODO: Log the error.
qDebug("Master Received a wrong Register Adress or NbRegisters in response for a MODBUS_FCT_WRITE_MULTIPLE_REGISTERS request");
emit ModbusResponseException(MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,MODBUS_FCT_WRITE_MULTIPLE_REGISTERS);
delete Request;
return RET_ERROR;
}
// qDebug("Master Rx Write Multiple Registers response. Address: %d, Nb Reg: %d",StartAdress, NbRegisters);
// qDebug("Data: %s",Transaction.mPDU.mData.toHex().data());
//All is good.
break;
}
default:
{
//Received "Illegal function code" response
//TODO: Log this.
qDebug("Master received illegal function code 0x%x",Transaction.mPDU.mFunctionCode);
emit ModbusResponseException(MODBUS_EXCEPTION_ILLEGAL_FCT,MODBUS_FCT_WRITE_MULTIPLE_REGISTERS);
break;
}
}
delete Request;
return 1;
}
int CModbusBackend::SendModbusRequest(CModbusRequest *Request)
{
QByteArray ModbusPacket;
QBuffer Buffer(&ModbusPacket);
Buffer.open(QIODevice::WriteOnly|QIODevice::Unbuffered);
Buffer.seek(0);
QDataStream *PacketDataStrm = new QDataStream(&Buffer);
*PacketDataStrm << Request->mHeader;
*PacketDataStrm << Request->mPDU.mFunctionCode;
Buffer.close();
ModbusPacket.append(Request->mPDU.mData);
// qDebug("Request packet: %s",ModbusPacket.toHex().data());
mModbusTCPSocketHandle->write(ModbusPacket);
mModbusTCPSocketHandle->flush();
return RET_OK;
}
int CModbusBackend::SendErrorResponse(CModbusTransaction RequestTransaction, quint8 ErrorCode)
{
QByteArray ModbusPacket;
QBuffer Buffer(&ModbusPacket);
Buffer.open(QIODevice::WriteOnly|QIODevice::Unbuffered);
Buffer.seek(0);
QDataStream *PacketDataStrm = new QDataStream(&Buffer);
//For a response, the header will be the same as the original request, except for the msg. length.
//Set the appropriate msg length.
RequestTransaction.mHeader.mMessageLength = 3; //Unit ID, function code & Exception code.
*PacketDataStrm << RequestTransaction.mHeader;
Buffer.close();
ModbusPacket.append(RequestTransaction.mPDU.mFunctionCode + 0x80);
ModbusPacket.append(ErrorCode);
// qDebug("Sending error code %d. Error packet: %s",ErrorCode,ModbusPacket.toHex().data());
mModbusTCPSocketHandle->write(ModbusPacket);
delete PacketDataStrm;
return RET_OK;
}
int CModbusBackend::SendReadHoldingRegistersRequest(quint16 StartAddress, quint16 RegisterCount)
{
//First, validate that the reading range is within our repo
if(mModbusRepo->IsHRValid(StartAddress,RegisterCount) == false)
{
qDebug("Trying to send a read HR in an invalid range");
return RET_ERROR;
}
//Create a request.
CModbusRequest *NewRequest = new CModbusRequest;
NewRequest->mStartAddress = StartAddress;
NewRequest->mNbRegisters = RegisterCount;
connect(NewRequest->mRequestTimer,SIGNAL(timeout()),this,SLOT(RequestTimerExpired()));
NewRequest->mPDU.mData.clear();
NewRequest->mPDU.mFunctionCode = MODBUS_FCT_READ_HOLDING_REGISTERS;
quint8 HighByte, LowByte;
LowByte = StartAddress & 0x00FF;
HighByte = (StartAddress >> 8) & 0x00FF;
NewRequest->mPDU.mData.append(HighByte);
NewRequest->mPDU.mData.append(LowByte);
LowByte = RegisterCount & 0x00FF;
HighByte = (RegisterCount >> 8) & 0x00FF;
NewRequest->mPDU.mData.append(HighByte);
NewRequest->mPDU.mData.append(LowByte);
NewRequest->mHeader.mMessageLength = NewRequest->mPDU.mData.size() + 2;
NewRequest->mHeader.mProtocolID = 0;
NewRequest->mHeader.mTransactionID = (qint16)GetNewTransactionID();
NewRequest->mHeader.mUnitID = mDeviceID;
mRequestsList.append(NewRequest);
SendModbusRequest(NewRequest);
NewRequest->mRequestTimer->start(mModbusRequestTimeout);
return RET_OK;
}
int CModbusBackend::SendWriteHoldingRegistersRequest(quint16 StartAddress, quint16 RegisterCount)
{
//First, validate that the reading range is within our repo
if(mModbusRepo->IsHRValid(StartAddress,RegisterCount) == false)
{
qDebug("Trying to send a read HR in an invalid range");
return RET_ERROR;
}
if(RegisterCount > MODBUS_MAX_NB_REGISTERS)
{
return RET_ERROR;
}
//Get data.
bool OK;
QByteArray RegData = mModbusRepo->GetHRData(StartAddress,RegisterCount,&OK);
if(OK == false)
{
return RET_ERROR;
}
//Create a request.
CModbusRequest *NewRequest = new CModbusRequest;
NewRequest->mStartAddress = StartAddress;
NewRequest->mNbRegisters = RegisterCount;
connect(NewRequest->mRequestTimer,SIGNAL(timeout()),this,SLOT(RequestTimerExpired()));
NewRequest->mPDU.mData.clear();
NewRequest->mPDU.mFunctionCode = MODBUS_FCT_WRITE_MULTIPLE_REGISTERS;
//Start address
quint8 HighByte, LowByte;
LowByte = StartAddress & 0x00FF;
HighByte = (StartAddress >> 8) & 0x00FF;
NewRequest->mPDU.mData.append(HighByte);
NewRequest->mPDU.mData.append(LowByte);
//Nb registers
LowByte = RegisterCount & 0x00FF;
HighByte = (RegisterCount >> 8) & 0x00FF;
NewRequest->mPDU.mData.append(HighByte);
NewRequest->mPDU.mData.append(LowByte);
//Byte Count
NewRequest->mPDU.mData.append(RegData.size());
//Datal
NewRequest->mPDU.mData.append(RegData);
NewRequest->mHeader.mMessageLength = NewRequest->mPDU.mData.size() + 2;
NewRequest->mHeader.mProtocolID = 0;
NewRequest->mHeader.mTransactionID = (qint16)GetNewTransactionID();
NewRequest->mHeader.mUnitID = mDeviceID;
mRequestsList.append(NewRequest);
SendModbusRequest(NewRequest);
NewRequest->mRequestTimer->start(mModbusRequestTimeout);
return RET_OK;
}
int CModbusBackend::SendWriteSingleRegisterRequest(quint16 Address)
{
if(Address == 2000)
{
qDebug("Write single reg 2000");
}
//First, validate that the reading range is within our repo
if(mModbusRepo->IsHRValid(Address,1) == false)
{
qDebug("Trying to send a read HR in an invalid range");
return RET_ERROR;
}
//Get data.
bool OK;
QByteArray RegData = mModbusRepo->GetHRData(Address,1,&OK);
if(OK == false)
{
return RET_ERROR;
}
//Create a request.
CModbusRequest *NewRequest = new CModbusRequest;
NewRequest->mStartAddress = Address;
NewRequest->mNbRegisters = 1;
connect(NewRequest->mRequestTimer,SIGNAL(timeout()),this,SLOT(RequestTimerExpired()));
NewRequest->mPDU.mData.clear();
NewRequest->mPDU.mFunctionCode = MODBUS_WRITE_SINGLE_REGISTER;
quint8 HighByte, LowByte;
LowByte = Address & 0x00FF;
HighByte = (Address >> 8) & 0x00FF;
NewRequest->mPDU.mData.append(HighByte);
NewRequest->mPDU.mData.append(LowByte);
// LowByte = RegData & 0x00FF;
// HighByte = (RegData >> 8) & 0x00FF;
// NewRequest->mPDU.mData.append(HighByte);
// NewRequest->mPDU.mData.append(LowByte);
NewRequest->mPDU.mData.append(RegData);
NewRequest->mHeader.mMessageLength = NewRequest->mPDU.mData.size() + 2;
NewRequest->mHeader.mProtocolID = 0;
NewRequest->mHeader.mTransactionID = (qint16)GetNewTransactionID();
NewRequest->mHeader.mUnitID = mDeviceID;
mRequestsList.append(NewRequest);
SendModbusRequest(NewRequest);
NewRequest->mRequestTimer->start(mModbusRequestTimeout);
return RET_OK;
}
void CModbusBackend::RequestTimerExpired()
{
//find the expired request
for(int i = 0; i < mRequestsList.size(); i++)
{
if(mRequestsList.at(i)->mRequestTimer->isActive() == false)
{
if(mRequestsList.at(i)->mRetries >= mModbusMaxRetry)
{
//The max number of retry has been reached. The device is probably offline.
qDebug("Modbus Master: Request sent to slave without response");
delete mRequestsList[i];
mRequestsList.removeAt(i);
//TODO: Manage this situation (log?)
return;
}
else
{
SendModbusRequest(mRequestsList[i]);
mRequestsList.at(i)->mRequestTimer->start(mModbusRequestTimeout);
mRequestsList[i]->mRetries++;
}
}
}
}
quint16 CModbusBackend::GetNewTransactionID()
{
quint16 ID = mTransactionIDCounter++;
if(mTransactionIDCounter == 0xFFFF - 10)
{
mTransactionIDCounter = 0;
}
return ID;
}
CModbusRequest::CModbusRequest():
mRetries(0)
{
mRequestTimer = new QTimer;
mRequestTimer->setSingleShot(true);
}
CModbusRequest::~CModbusRequest()
{
delete mRequestTimer;
}
QDataStream &operator<<(QDataStream &out, const CModbusHeader &source)
{
out << source.mTransactionID
<< source.mProtocolID
<< source.mMessageLength
<< source.mUnitID
;
return out;
}
QDataStream &operator>>(QDataStream &in, CModbusHeader &dest)
{
in >> dest.mTransactionID
>> dest.mProtocolID
>> dest.mMessageLength
>> dest.mUnitID
;
return in;
}
//Virtual function that should not even get called...
void CModbusBackend::ModbusResponseException(quint8 ExceptionCode, quint8 FctCode)
{
qDebug("ModbusResponseException called from within slave object... weird stuff!");
}
//Virtual function that should not even get called...
void CModbusBackend::ModbusRequestException(quint8 ExceptionCode, quint8 FctCode)
{
qDebug("ModbusResponseException called from within master object... weird stuff!");
}