ZT/sources/Modbus/ModbusSEIMgr.cpp
2019-10-08 10:46:34 -04:00

291 lines
9.0 KiB
C++

#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_WATCHDOG_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();
}
}