Version 1.21 -Correction d'un bug dans le calcul de l'adresse IP du Gateway -Ajout de la désactivation du log d'ingénierie dans le script de mise à jour -Correction d'un bug d'écriture dans un registre SEI -Ajout de la composition du train dans le fichier LOG -Suite au passage du train test, changement des CDV d'acquitement des alarmes à Montmorency. 12A -> (12A & 11A) et 22A -> (22A & 21B).
291 lines
9.0 KiB
C++
Executable File
291 lines
9.0 KiB
C++
Executable File
#include "ModbusSEIMgr.h"
|
|
#include <QTcpSocket>
|
|
#include "ModbusCCDefs.h"
|
|
#include "ModbusSEIDefs.h"
|
|
#include "GlobalDefine.h"
|
|
#include <ZTLog.h>
|
|
|
|
CModbusSEIMgr::CModbusSEIMgr(CModbusRepository *SEIRepo, CModbusRepository *CCRepo, QHostAddress ServerIP, int ModbusPort, int DevID):
|
|
CModbusBackend(SEIRepo)
|
|
{
|
|
// connect(mModbusTCPSocketHandle,SIGNAL(readyRead()),this,SLOT(ModbusDataReady()));
|
|
mModbusMode = MODBUS_MASTER_MODE;
|
|
mModbusPort = ModbusPort;
|
|
mDeviceID = DevID;
|
|
mSEIIPAddress = ServerIP;
|
|
|
|
mCCRepoHandle = CCRepo;
|
|
|
|
mZTWatchdog = false;
|
|
|
|
mConnectionTimer = new QTimer();
|
|
mConnectionTimer->setInterval(SEI_CLIENT_RECONNECT_TIMEOUT);
|
|
mConnectionTimer->setSingleShot(false);
|
|
mConnectionTimer->stop();
|
|
|
|
mSEIModbusUpdateTimer = new QTimer();
|
|
mSEIModbusUpdateTimer->setInterval(1000);
|
|
mSEIModbusUpdateTimer->setSingleShot(true);
|
|
mSEIModbusUpdateTimer->stop();
|
|
|
|
mSEIWatchdogTimer = new QTimer();
|
|
mSEIWatchdogTimer->setInterval(SEI_MODBUS_WATCHDOG_TIMEOUT);
|
|
mSEIWatchdogTimer->setSingleShot(true);
|
|
mSEIWatchdogTimer->stop();
|
|
|
|
|
|
mSEILinkState = false;
|
|
mSEIWatchdogState = 0;
|
|
|
|
|
|
mModbusTCPSocketHandle = new QTcpSocket();
|
|
connect(mModbusTCPSocketHandle,SIGNAL(readyRead()),this,SLOT(ModbusDataReady()));
|
|
connect(mModbusTCPSocketHandle,SIGNAL(disconnected()),this,SLOT(SocketDisconnected()));
|
|
connect(mModbusTCPSocketHandle,SIGNAL(connected()),this,SLOT(SocketConnected()));
|
|
connect(mConnectionTimer,SIGNAL(timeout()),this,SLOT(ConnectionTimerExpired()));
|
|
connect(mSEIModbusUpdateTimer,SIGNAL(timeout()),this,SLOT(SEIModbusUpdateTimerExpired()));
|
|
connect(mSEIWatchdogTimer,SIGNAL(timeout()),this,SLOT(SEIModbusWatchdogtimerExpired()));
|
|
}
|
|
|
|
CModbusSEIMgr::~CModbusSEIMgr()
|
|
{
|
|
if(mModbusTCPSocketHandle->state() != QAbstractSocket::UnconnectedState)
|
|
{
|
|
mModbusTCPSocketHandle->disconnectFromHost();
|
|
mModbusTCPSocketHandle->waitForDisconnected(1000);
|
|
}
|
|
delete mModbusTCPSocketHandle;
|
|
|
|
if(mConnectionTimer)
|
|
delete mConnectionTimer;
|
|
if(mSEIModbusUpdateTimer)
|
|
delete mSEIModbusUpdateTimer;
|
|
if(mSEIWatchdogTimer)
|
|
delete mSEIWatchdogTimer;
|
|
}
|
|
|
|
int CModbusSEIMgr::StartSEICommunication()
|
|
{
|
|
mConnectionTimer->start();
|
|
return RET_OK;
|
|
}
|
|
|
|
int CModbusSEIMgr::ConnectToSlave(QHostAddress SlaveIP, int SlavePort)
|
|
{
|
|
if(mModbusTCPSocketHandle->state() != QAbstractSocket::UnconnectedState)
|
|
{
|
|
return RET_ERROR;
|
|
}
|
|
|
|
mModbusTCPSocketHandle->connectToHost(SlaveIP,SlavePort);
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
int CModbusSEIMgr::DisconnectFromSlave()
|
|
{
|
|
mModbusTCPSocketHandle->disconnectFromHost();
|
|
mConnectionTimer->start();
|
|
|
|
return 1;
|
|
}
|
|
|
|
void CModbusSEIMgr::SocketConnected()
|
|
{
|
|
emit ModbusMasterConnected(mModbusTCPSocketHandle->localAddress().toIPv4Address(),mModbusTCPSocketHandle->peerAddress().toIPv4Address());
|
|
// qDebug("Master: Connection established with NetTrac");
|
|
// CZTLog::instance()->AddLogString("Connection Modbus (Ethernet) avec NetTrac établi",true);
|
|
CZTLog::instance()->AddLogString(QString("Connection Modbus (Ethernet) avec la NetTrac établie. IP locale [%1] - IP NetTrac [%2]").arg(mModbusTCPSocketHandle->localAddress().toString()).arg(mModbusTCPSocketHandle->peerAddress().toString()),true);
|
|
mConnectionTimer->stop();
|
|
mSEIModbusUpdateTimer->start();
|
|
mSEIWatchdogTimer->start(SEI_MODBUS_WATCHDOG_TIMEOUT*2); //allow twice the time for the first watchdog to come in
|
|
}
|
|
|
|
void CModbusSEIMgr::SocketDisconnected()
|
|
{
|
|
ModbusLinkDisconnected();
|
|
emit ModbusMasterDisconnected();
|
|
emit SEIModbusLinkLost();
|
|
mConnectionTimer->start();
|
|
mSEIModbusUpdateTimer->stop();
|
|
mSEILinkState = false;
|
|
mSEIWatchdogState = 0xBEEF;
|
|
CZTLog::instance()->AddLogString("Connection Modbus (Ethernet) avec NetTrac rompue",true);
|
|
}
|
|
|
|
int CModbusSEIMgr::ReadModbusRegisters()
|
|
{
|
|
//return SendReadHoldingRegistersRequest(ZT_DATA_BASE_REGISTER_ADDRESS,4); //Read all 3 registers from ZT (2000 - 2003)
|
|
return RET_OK;
|
|
}
|
|
|
|
void CModbusSEIMgr::ConnectionTimerExpired()
|
|
{
|
|
//Establish connection only if not connected
|
|
if(mModbusTCPSocketHandle->state() == QAbstractSocket::UnconnectedState)
|
|
{
|
|
ConnectToSlave(mSEIIPAddress,mModbusPort);
|
|
}
|
|
}
|
|
|
|
int CModbusSEIMgr::SEISettingsChanged(QHostAddress ServerIP, int ModbusPort, int DevID)
|
|
{
|
|
if(DevID > 255)
|
|
{
|
|
return RET_ERROR;
|
|
}
|
|
|
|
|
|
mSEIIPAddress = ServerIP;
|
|
mModbusPort = ModbusPort;
|
|
mDeviceID = DevID;
|
|
|
|
//Make shure we are disconnected. Connection timer will do the reconnection.
|
|
DisconnectFromSlave();
|
|
|
|
return RET_OK;
|
|
|
|
}
|
|
|
|
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()).
|
|
//Just update the watchdog and send the current table.
|
|
mZTWatchdog = !mZTWatchdog;
|
|
|
|
if(mZTWatchdog)
|
|
{
|
|
mModbusRepo->WriteSingleReg(SEI_MODBUS_ZT_WATCHDOG_REG,0x01);
|
|
}
|
|
else
|
|
{
|
|
mModbusRepo->WriteSingleReg(SEI_MODBUS_ZT_WATCHDOG_REG,0);
|
|
}
|
|
|
|
SendWriteHoldingRegistersRequest(SEI_MODBUS_ZT_DATA_BASE_REG,SEI_MODBUS_ZT_TABLE_DATA_SIZE);
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
|
|
//This signal is emitted by TKTransport when a changed happened in the TK after the CC modbus table has been updated.
|
|
//We just need to copy the relevant info from the CC repo...
|
|
//As per specification, we must also send an update on change to the SEI
|
|
void CModbusSEIMgr::ZTTKUpdated()
|
|
{
|
|
//Copy data from CC modbus table to SEI modbus table.
|
|
mModbusRepo->WriteHRData(SEI_MODBUS_ZT_DATA_BASE_REG,SEI_MODBUS_ZT_TABLE_DATA_SIZE,mCCRepoHandle->GetHRData(MODBUS_ZT_DATA_BASE_REG,SEI_MODBUS_ZT_TABLE_DATA_SIZE));
|
|
|
|
//Keep our actual watchdog value..
|
|
if(mZTWatchdog)
|
|
{
|
|
mModbusRepo->WriteSingleReg(SEI_MODBUS_ZT_WATCHDOG_REG,0x01);
|
|
}
|
|
else
|
|
{
|
|
mModbusRepo->WriteSingleReg(SEI_MODBUS_ZT_WATCHDOG_REG,0);
|
|
}
|
|
|
|
//Send the data now to NetTrac
|
|
SendWriteHoldingRegistersRequest(SEI_MODBUS_ZT_DATA_BASE_REG,SEI_MODBUS_ZT_TABLE_DATA_SIZE);
|
|
|
|
}
|
|
|
|
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)
|
|
{
|
|
Q_UNUSED(StartAddress)
|
|
Q_UNUSED(Length)
|
|
static bool FirstUpdate = true;
|
|
|
|
|
|
qint16 WD = mModbusRepo->GetSingleReg(SEI_MODBUS_SEI_WATCHDOG_REG);
|
|
WD = (WD & SEI_MODBUS_SEI_WATCHDOG_MASK);
|
|
// qDebug("WD = %d",WD);
|
|
if(FirstUpdate)
|
|
{
|
|
mSEIWatchdogState = WD;
|
|
FirstUpdate = false;
|
|
}
|
|
else 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
|
|
{
|
|
bool OK;
|
|
qint16 AlarmsReg = mModbusRepo->GetSingleReg(SEI_MODBUS_SEI_ALARMS_RESET_REG,&OK);
|
|
bool ZT1Clear, ZT2Clear;
|
|
|
|
if(OK)
|
|
{
|
|
ZT1Clear = (AlarmsReg & SEI_MODBUS_SEI_ZT1_ALARM_RESET_MASK) != 0;
|
|
|
|
ZT2Clear = (AlarmsReg & SEI_MODBUS_SEI_ZT2_ALARM_RESET_MASK) != 0;
|
|
|
|
emit SEIAlarmClearUpdate(ZT1Clear,ZT2Clear);
|
|
}
|
|
else
|
|
{
|
|
CEngLog::instance()->AddLogString(qPrintable(QString("Erreur de logique dans ModbusSEIMgr::RegistersDatabaseUpdated, impossible de lire la table modbus à l'adresse %1").arg(SEI_MODBUS_SEI_ALARMS_RESET_REG)));
|
|
}
|
|
}
|
|
|
|
SendZTRegistersToSEI();
|
|
|
|
|
|
}
|
|
|
|
void CModbusSEIMgr::ModbusResponseException(quint8 ExceptionCode, quint8 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();
|
|
}
|
|
}
|