Modbus dev...

This commit is contained in:
jfmartel 2019-10-02 14:13:14 -04:00
parent 9ef96c5db5
commit 8f046e4223
7 changed files with 138 additions and 18 deletions

View File

@ -70,7 +70,7 @@
#define USE_NETWORKING #define USE_NETWORKING
#define TCP_SERVER_PORT 1234 #define TCP_SERVER_PORT 1234
#define CUSTOM_KERNEL_INSTALLED //Custom kernel with modified serial.c to disable hardware FIFO. #define CUSTOM_KERNEL_INSTALLED //Custom kernel with modified serial.c to disable hardware FIFO.
#define COMPILE_MODBUS_TEST_MODE //Utilisé seulement pour les tests d'intégration Modbus. //#define COMPILE_MODBUS_TEST_MODE //Utilisé seulement pour les tests d'intégration Modbus.
//Debug defs //Debug defs

View File

@ -350,8 +350,8 @@ int CModbusBackend::AnalyzeModbusResponse(CModbusTransaction Transaction)
QByteArray RegisterValues = Transaction.mPDU.mData.right(ByteCount); QByteArray RegisterValues = Transaction.mPDU.mData.right(ByteCount);
qDebug("Master Rx Read Holding Registers Response."); // qDebug("Master Rx Read Holding Registers Response.");
qDebug("Data: %s",RegisterValues.toHex().data()); // qDebug("Data: %s",RegisterValues.toHex().data());
mModbusRepo->WriteHRData(Request->mStartAddress,Request->mNbRegisters,RegisterValues); mModbusRepo->WriteHRData(Request->mStartAddress,Request->mNbRegisters,RegisterValues);
RegistersDatabaseUpdated(Request->mStartAddress, Request->mNbRegisters); RegistersDatabaseUpdated(Request->mStartAddress, Request->mNbRegisters);
@ -374,8 +374,10 @@ int CModbusBackend::AnalyzeModbusResponse(CModbusTransaction Transaction)
delete Request; delete Request;
return RET_ERROR; return RET_ERROR;
} }
qDebug("Master Rx Write Single Register response. Address: %d,",RegAddress); // qDebug("Master Rx Write Single Register response. Address: %d,",RegAddress);
qDebug("Data: %s",Transaction.mPDU.mData.toHex().data()); // qDebug("Data: %s",Transaction.mPDU.mData.toHex().data());
ModbusWriteSingleRegsSuccess();
//Everything seems good. //Everything seems good.
@ -405,6 +407,7 @@ int CModbusBackend::AnalyzeModbusResponse(CModbusTransaction Transaction)
// qDebug("Master Rx Write Multiple Registers response. Address: %d, Nb Reg: %d",StartAdress, NbRegisters); // qDebug("Master Rx Write Multiple Registers response. Address: %d, Nb Reg: %d",StartAdress, NbRegisters);
// qDebug("Data: %s",Transaction.mPDU.mData.toHex().data()); // qDebug("Data: %s",Transaction.mPDU.mData.toHex().data());
ModbusWriteMultipleRegsSuccess();
//All is good. //All is good.
@ -414,7 +417,8 @@ int CModbusBackend::AnalyzeModbusResponse(CModbusTransaction Transaction)
{ {
//Received "Illegal function code" response //Received "Illegal function code" response
//TODO: Log this. //TODO: Log this.
qDebug("Master received illegal function code 0x%x",Transaction.mPDU.mFunctionCode); CEngLog::instance()->AddLogString(QString().sprintf("Modbus Maître, réception d'un code de fonction illégal: 0x%x",Transaction.mPDU.mFunctionCode));
// qDebug("Master received illegal function code 0x%x",Transaction.mPDU.mFunctionCode);
emit ModbusResponseException(MODBUS_EXCEPTION_ILLEGAL_FCT,MODBUS_FCT_WRITE_MULTIPLE_REGISTERS); emit ModbusResponseException(MODBUS_EXCEPTION_ILLEGAL_FCT,MODBUS_FCT_WRITE_MULTIPLE_REGISTERS);
break; break;
} }
@ -483,7 +487,7 @@ int CModbusBackend::SendReadHoldingRegistersRequest(quint16 StartAddress, quint1
//First, validate that the reading range is within our repo //First, validate that the reading range is within our repo
if(mModbusRepo->IsHRValid(StartAddress,RegisterCount) == false) if(mModbusRepo->IsHRValid(StartAddress,RegisterCount) == false)
{ {
CEngLog::instance()->AddLogString("Trying to send a read HR in an invalid range"); CEngLog::instance()->AddLogString("ModbusBackend: Tentative de lecture d'un registre hors de portée.");
return RET_ERROR; return RET_ERROR;
} }
@ -647,12 +651,12 @@ void CModbusBackend::RequestTimerExpired()
{ {
//The max number of retry has been reached. The device is probably offline. //The max number of retry has been reached. The device is probably offline.
CZTLog::instance()->AddLogString("Modbus Maître: Nombre maximal de tentatives sans réponse atteint avec le partenaire",true); // CZTLog::instance()->AddLogString("Modbus Maître: Nombre maximal de tentatives sans réponse atteint avec le partenaire",true);
delete mRequestsList[i]; delete mRequestsList[i];
mRequestsList.removeAt(i); mRequestsList.removeAt(i);
ModbusRequestMaxRetryReached();
//TODO: Manage this situation (log?) //TODO: Manage this situation (log?)
@ -734,3 +738,18 @@ void CModbusBackend::ModbusRequestException(quint8 ExceptionCode, quint8 FctCode
Q_UNUSED(FctCode) Q_UNUSED(FctCode)
CEngLog::instance()->AddLogString("ModbusResponseException called from within master object... weird stuff!"); CEngLog::instance()->AddLogString("ModbusResponseException called from within master object... weird stuff!");
} }
void CModbusBackend::ModbusWriteMultipleRegsSuccess()
{
qDebug("Weird! Default implementation of ModbusWriteMultipleRegsSuccess() called in CModbusBackend. This function should be reimplemented in the ModbusMaster child class");
}
void CModbusBackend::ModbusWriteSingleRegsSuccess()
{
qDebug("Weird! Default implementation of ModbusWriteSingleRegsSuccess() called in CModbusBackend. This function should be reimplemented in the ModbusMaster child class");
}
void CModbusBackend::ModbusRequestMaxRetryReached()
{
qDebug("Weird! Default implementation of ModbusRequestMaxRetryReached() called in CModbusBackend. This function should be reimplemented in the ModbusMaster child class");
}

View File

@ -137,16 +137,21 @@ public:
virtual void RegistersDatabaseUpdated(quint16 StartAdderss, quint16 Length) = 0; //Fonction virtuelle à être implémentée par le parent virtual void RegistersDatabaseUpdated(quint16 StartAdderss, quint16 Length) = 0; //Fonction virtuelle à être implémentée par la classe dérivée
//Appelée lorsque de nouvelles données ont été reçues du réseau Modbus et écrites dans le registre //Appelée lorsque de nouvelles données ont été reçues du réseau Modbus et écrites dans le registre
virtual void ModbusWriteMultipleRegsSuccess(); //Fonction virtuelle à être implémentée par la classe dérivée (Modbus Master seulement). Appelée suite à la réception d'une réponse à une requête d'écriture multiple.
virtual void ModbusWriteSingleRegsSuccess(); //Fonction virtuelle à être implémentée par la classe dérivée (Modbus Master seulement). Appelée suite à la réception d'une réponse à une requête d'écriture simple.
virtual void ModbusRequestMaxRetryReached(); //Fonction virtuelle à être implémentée par la classe dérivée (Modbus Master seulement). Appelée lors de l'atteinte du nombre maximal d'essai de transmission d'une requête.
//Master Exception //Master Exception
virtual void ModbusResponseException(quint8 ExceptionCode, quint8 FctCode); //Fonction virtuelle à être implémentée par le parent virtual void ModbusResponseException(quint8 ExceptionCode, quint8 FctCode) = 0; //Fonction virtuelle à être implémentée par la classe dérivée
//Sert à informer le parent lorsqu'une exception se produit dans la communication Modbus (réponse) //Sert à informer la classe dérivée lorsqu'une exception se produit dans la communication Modbus (réponse)
//Slave Exception //Slave Exception
virtual void ModbusRequestException(quint8 ExceptionCode, quint8 FctCode); //Fonction virtuelle à être implémentée par le parent virtual void ModbusRequestException(quint8 ExceptionCode, quint8 FctCode) = 0; //Fonction virtuelle à être implémentée par la classe dérivée
//Sert à informer le parent lorsqu'une exception se produit dans la communication Modbus (requête) //Sert à informer le parent lorsqu'une exception se produit dans la communication Modbus (requête)

View File

@ -10,7 +10,9 @@
#define SEI_MODBUS_ZT_WATCHDOG_REG 2027 #define SEI_MODBUS_ZT_WATCHDOG_REG 2027
#define SEI_MODBUS_SEI_WATCHDOG_REG 2038 #define SEI_MODBUS_SEI_WATCHDOG_REG 2038
#define SEI_MODBUS_SEI_WATCHDOG_MASK 0x0001
#define SEI_MODBUS_SEI_ALARMS_RESET_REG 2037
#define SEI_MODBUS_SEI_ZT1_ALARM_RESET_MASK 0X0001 #define SEI_MODBUS_SEI_ZT1_ALARM_RESET_MASK 0X0001
#define SEI_MODBUS_SEI_ZT2_ALARM_RESET_MASK 0X0002 #define SEI_MODBUS_SEI_ZT2_ALARM_RESET_MASK 0X0002

View File

@ -25,9 +25,18 @@ CModbusSEIMgr::CModbusSEIMgr(CModbusRepository *SEIRepo, CModbusRepository *CCRe
mSEIModbusUpdateTimer = new QTimer(); mSEIModbusUpdateTimer = new QTimer();
mSEIModbusUpdateTimer->setInterval(1000); mSEIModbusUpdateTimer->setInterval(1000);
mSEIModbusUpdateTimer->setSingleShot(false); mSEIModbusUpdateTimer->setSingleShot(true);
mSEIModbusUpdateTimer->stop(); mSEIModbusUpdateTimer->stop();
mSEIWatchdogTimer = new QTimer();
mSEIWatchdogTimer->setInterval(SEI_MODBUS_WATCHDOG_TIMEOUT);
mSEIWatchdogTimer->setSingleShot(true);
mSEIWatchdogTimer->stop();
mSEILinkState = false;
mSEIWatchdogState = 0;
mModbusTCPSocketHandle = new QTcpSocket(); mModbusTCPSocketHandle = new QTcpSocket();
connect(mModbusTCPSocketHandle,SIGNAL(readyRead()),this,SLOT(ModbusDataReady())); connect(mModbusTCPSocketHandle,SIGNAL(readyRead()),this,SLOT(ModbusDataReady()));
@ -35,6 +44,7 @@ CModbusSEIMgr::CModbusSEIMgr(CModbusRepository *SEIRepo, CModbusRepository *CCRe
connect(mModbusTCPSocketHandle,SIGNAL(connected()),this,SLOT(SocketConnected())); connect(mModbusTCPSocketHandle,SIGNAL(connected()),this,SLOT(SocketConnected()));
connect(mConnectionTimer,SIGNAL(timeout()),this,SLOT(ConnectionTimerExpired())); connect(mConnectionTimer,SIGNAL(timeout()),this,SLOT(ConnectionTimerExpired()));
connect(mSEIModbusUpdateTimer,SIGNAL(timeout()),this,SLOT(SEIModbusUpdateTimerExpired())); connect(mSEIModbusUpdateTimer,SIGNAL(timeout()),this,SLOT(SEIModbusUpdateTimerExpired()));
connect(mSEIWatchdogTimer,SIGNAL(timeout()),this,SLOT(SEIModbusWatchdogtimerExpired()));
} }
CModbusSEIMgr::~CModbusSEIMgr() CModbusSEIMgr::~CModbusSEIMgr()
@ -50,6 +60,8 @@ CModbusSEIMgr::~CModbusSEIMgr()
delete mConnectionTimer; delete mConnectionTimer;
if(mSEIModbusUpdateTimer) if(mSEIModbusUpdateTimer)
delete mSEIModbusUpdateTimer; delete mSEIModbusUpdateTimer;
if(mSEIWatchdogTimer)
delete mSEIWatchdogTimer;
} }
int CModbusSEIMgr::StartSEICommunication() int CModbusSEIMgr::StartSEICommunication()
@ -85,16 +97,18 @@ void CModbusSEIMgr::SocketConnected()
CZTLog::instance()->AddLogString("Connection Modbus (Ethernet) avec NetTrac établi",true); CZTLog::instance()->AddLogString("Connection Modbus (Ethernet) avec NetTrac établi",true);
mConnectionTimer->stop(); mConnectionTimer->stop();
mSEIModbusUpdateTimer->start(); mSEIModbusUpdateTimer->start();
mSEIWatchdogTimer->start(SEI_MODBUS_WATCHDOG_TIMEOUT*2); //allow twice the time for the first watchdog to come in
} }
void CModbusSEIMgr::SocketDisconnected() void CModbusSEIMgr::SocketDisconnected()
{ {
ModbusLinkDisconnected(); ModbusLinkDisconnected();
emit ModbusMasterDisconnected(); emit ModbusMasterDisconnected();
emit SEIModbusLinkLost();
mConnectionTimer->start(); mConnectionTimer->start();
mSEIModbusUpdateTimer->stop(); mSEIModbusUpdateTimer->stop();
// qDebug("Disconnected from NetTrac"); mSEILinkState = false;
// CZTLog::instance()->AddLogString("Connexion avec NetTrac établi",true); mSEIWatchdogState = 0xBEEF;
CZTLog::instance()->AddLogString("Connection Modbus (Ethernet) avec NetTrac rompue",true); CZTLog::instance()->AddLogString("Connection Modbus (Ethernet) avec NetTrac rompue",true);
} }
@ -133,6 +147,13 @@ int CModbusSEIMgr::SEISettingsChanged(QHostAddress ServerIP, int ModbusPort, int
} }
void CModbusSEIMgr::SEIModbusUpdateTimerExpired() void CModbusSEIMgr::SEIModbusUpdateTimerExpired()
{
//Read the SEI data...
SendReadHoldingRegistersRequest(SEI_MODBUS_SEI_DATA_BASE_REG,SEI_MODBUS_SEI_TABLE_DATA_SIZE);
}
int CModbusSEIMgr::SendZTRegistersToSEI()
{ {
//The SEI Modbus table is updated on event, triggered by the TKTransport object (see ZTTKUpdated()). //The SEI Modbus table is updated on event, triggered by the TKTransport object (see ZTTKUpdated()).
//Just update the watchdog and send the current table. //Just update the watchdog and send the current table.
@ -149,6 +170,7 @@ void CModbusSEIMgr::SEIModbusUpdateTimerExpired()
SendWriteHoldingRegistersRequest(SEI_MODBUS_ZT_DATA_BASE_REG,SEI_MODBUS_ZT_TABLE_DATA_SIZE); SendWriteHoldingRegistersRequest(SEI_MODBUS_ZT_DATA_BASE_REG,SEI_MODBUS_ZT_TABLE_DATA_SIZE);
return RET_OK;
} }
@ -175,11 +197,42 @@ void CModbusSEIMgr::ZTTKUpdated()
} }
void CModbusSEIMgr::SEIModbusWatchdogtimerExpired()
{
CZTLog::instance()->AddLogString("Perte du lien de communication avec la NetTrac: Watchdog NetTrac Expiré",true);
emit SEIModbusLinkLost();
mSEILinkState = false;
// mSEIWatchdogState = 0;
}
void CModbusSEIMgr::RegistersDatabaseUpdated(quint16 StartAddress, quint16 Length) void CModbusSEIMgr::RegistersDatabaseUpdated(quint16 StartAddress, quint16 Length)
{ {
Q_UNUSED(StartAddress) Q_UNUSED(StartAddress)
Q_UNUSED(Length) Q_UNUSED(Length)
qint16 WD = mModbusRepo->GetSingleReg(SEI_MODBUS_SEI_WATCHDOG_REG);
WD = (WD & SEI_MODBUS_SEI_WATCHDOG_MASK);
// qDebug("WD = %d",WD);
if(WD != mSEIWatchdogState)
{
mSEIWatchdogTimer->start(SEI_MODBUS_WATCHDOG_TIMEOUT); //The watchdog has toggled. Kick the timer.
mSEIWatchdogState = WD;
if(mSEILinkState == false)
{
mSEILinkState = true;
emit SEIModbusLinkRecovered();
CZTLog::instance()->AddLogString("Lien de communication (Watchdog) avec NetTrac rétabli",true);
}
}
if(mSEILinkState == true) //only consider data when link is healthy
{
}
SendZTRegistersToSEI();
emit ModbusMasterRepositoryUpdated(); emit ModbusMasterRepositoryUpdated();
} }
@ -187,3 +240,28 @@ void CModbusSEIMgr::ModbusResponseException(quint8 ExceptionCode, quint8 FctCode
{ {
qDebug("Modbus MASTER exception: code:%d Fct:%d",ExceptionCode,FctCode); qDebug("Modbus MASTER exception: code:%d Fct:%d",ExceptionCode,FctCode);
} }
void CModbusSEIMgr::ModbusWriteMultipleRegsSuccess()
{
if(mModbusTCPSocketHandle->state() == QAbstractSocket::ConnectedState)
{
mSEIModbusUpdateTimer->start();
}
}
void CModbusSEIMgr::ModbusWriteSingleRegsSuccess()
{
if(mModbusTCPSocketHandle->state() == QAbstractSocket::ConnectedState)
{
mSEIModbusUpdateTimer->start();
}
}
void CModbusSEIMgr::ModbusRequestMaxRetryReached()
{
//The server did not respond to last request... Retry...
if(mModbusTCPSocketHandle->state() == QAbstractSocket::ConnectedState)
{
mSEIModbusUpdateTimer->start();
}
}

View File

@ -8,7 +8,7 @@
#include <QElapsedTimer> #include <QElapsedTimer>
#include <QHostAddress> #include <QHostAddress>
#define SEI_MODBUS_WATCHDOG_TIMEOUT 7000 //ms
class CModbusSEIMgr : public CModbusBackend class CModbusSEIMgr : public CModbusBackend
@ -23,13 +23,17 @@ public:
int ReadModbusRegisters(); int ReadModbusRegisters();
int StartSEICommunication(); int StartSEICommunication();
int SEISettingsChanged(QHostAddress ServerIP, int ModbusPort, int DevID); int SEISettingsChanged(QHostAddress ServerIP, int ModbusPort, int DevID);
int SendZTRegistersToSEI();
virtual void RegistersDatabaseUpdated(quint16 StartAddress, quint16 Length); virtual void RegistersDatabaseUpdated(quint16 StartAddress, quint16 Length);
virtual void ModbusResponseException(quint8 ExceptionCode, quint8 FctCode); virtual void ModbusResponseException(quint8 ExceptionCode, quint8 FctCode);
virtual void ModbusWriteMultipleRegsSuccess();
virtual void ModbusWriteSingleRegsSuccess();
virtual void ModbusRequestMaxRetryReached();
QTimer *mConnectionTimer; QTimer *mConnectionTimer;
// QTimer *mSEIWatchdogTimer; QTimer *mSEIWatchdogTimer;
QTimer *mSEIModbusUpdateTimer; QTimer *mSEIModbusUpdateTimer;
private: private:
@ -37,11 +41,19 @@ private:
QHostAddress mSEIIPAddress; QHostAddress mSEIIPAddress;
CModbusRepository *mCCRepoHandle; CModbusRepository *mCCRepoHandle;
bool mZTWatchdog; bool mZTWatchdog;
bool mSEILinkState;
int mSEIWatchdogState;
signals: signals:
void ModbusMasterConnected(qint32 LocalIP, qint32 RemoteIP); void ModbusMasterConnected(qint32 LocalIP, qint32 RemoteIP);
void ModbusMasterDisconnected(); void ModbusMasterDisconnected();
void ModbusMasterRepositoryUpdated(); void ModbusMasterRepositoryUpdated();
void SEIModbusLinkLost();
void SEIModbusLinkRecovered();
public slots: public slots:
void SocketConnected(); void SocketConnected();
@ -49,6 +61,8 @@ public slots:
void ConnectionTimerExpired(); void ConnectionTimerExpired();
void SEIModbusUpdateTimerExpired(); void SEIModbusUpdateTimerExpired();
void ZTTKUpdated(); void ZTTKUpdated();
void SEIModbusWatchdogtimerExpired();
}; };
#endif // CMODBUSSEIMGR_H #endif // CMODBUSSEIMGR_H

View File

@ -606,6 +606,8 @@ unsigned int CZoneTest::InitZT()
connect(mModbusSEIMgr,SIGNAL(ModbusMasterConnected(qint32,qint32)),panel.mSEISettingsPage,SLOT(ModbusSEIConnected(qint32,qint32))); connect(mModbusSEIMgr,SIGNAL(ModbusMasterConnected(qint32,qint32)),panel.mSEISettingsPage,SLOT(ModbusSEIConnected(qint32,qint32)));
connect(mModbusSEIMgr,SIGNAL(ModbusMasterDisconnected()),panel.mSEISettingsPage,SLOT(ModbusSEIDisconnected())); connect(mModbusSEIMgr,SIGNAL(ModbusMasterDisconnected()),panel.mSEISettingsPage,SLOT(ModbusSEIDisconnected()));
connect(mModbusSEIMgr,SIGNAL(SEIModbusLinkLost()),panel.mSEISettingsPage,SLOT(ModbusSEILinkDown()));
connect(mModbusSEIMgr,SIGNAL(SEIModbusLinkRecovered()),panel.mSEISettingsPage,SLOT(ModbusSEILinkUP()));
panel.mZTMainPage->ModbusSEIDisconnected(); panel.mZTMainPage->ModbusSEIDisconnected();