525 lines
15 KiB
C++
525 lines
15 KiB
C++
#include "ModbusCCMgr.h"
|
|
#include "ZTLog.h"
|
|
#include "EngLog.h"
|
|
#include "ModbusCCDefs.h"
|
|
#include <QDateTime>
|
|
#include "ZTData.h"
|
|
#include "GlobalDefine.h"
|
|
|
|
CModbusCCMgr::CModbusCCMgr(CModbusRepository *Repo, int ModbusPort, int DevID) :
|
|
CModbusBackend(Repo)
|
|
{
|
|
mModbusServer = new QTcpServer();
|
|
mDeviceID = DevID;
|
|
mModbusPort = ModbusPort;
|
|
mZTWatchdogEnabled = true;
|
|
|
|
connect(mModbusServer,SIGNAL(newConnection()),this,SLOT(NewModbusConnection()));
|
|
mModbusMode = MODBUS_SLAVE_MODE;
|
|
|
|
mZTWatchdogTimer = new QTimer;
|
|
mZTWatchdogTimer->setSingleShot(false);
|
|
mZTWatchdogTimer->setInterval(MODBUS_ZT_WATCHDOG_TIMEOUT);
|
|
connect(mZTWatchdogTimer,SIGNAL(timeout()),this,SLOT(ModbusZTWatchdogTimeout()));
|
|
|
|
mCCWatchdogTimer = new QTimer;
|
|
mCCWatchdogTimer->setSingleShot(true);
|
|
mCCWatchdogTimer->setInterval(MODBUS_CC_WATCHDOG_TIMEOUT);
|
|
connect(mCCWatchdogTimer,SIGNAL(timeout()),this,SLOT(ModbusCCWatchdogTimeout()));
|
|
|
|
mZTWatchdog = 0;
|
|
mCCWatchdogState = 0;
|
|
mCCLinkState = false;
|
|
mLastDateTime = 0;
|
|
|
|
ResetCCRepository();
|
|
}
|
|
|
|
CModbusCCMgr::~CModbusCCMgr()
|
|
{
|
|
delete mModbusServer;
|
|
|
|
delete mZTWatchdogTimer;
|
|
delete mCCWatchdogTimer;
|
|
if(mLastDateTime != 0)
|
|
{
|
|
delete mLastDateTime;
|
|
}
|
|
}
|
|
|
|
int CModbusCCMgr::StartModbusCCServer()
|
|
{
|
|
mModbusServer->listen(QHostAddress::Any,mModbusPort);
|
|
CZTLog::instance()->AddLogString(QString("Serveur Modbus Commande Centralisée démarré sur le port %1").arg(mModbusPort),true);
|
|
return 1;
|
|
}
|
|
|
|
|
|
bool CModbusCCMgr::CheckForCCPartner(const int msTimeout, const int port)
|
|
{
|
|
QTcpServer *DummyServer = new QTcpServer();
|
|
DummyServer->listen(QHostAddress::Any,port);
|
|
|
|
if(DummyServer->waitForNewConnection(msTimeout) == true)
|
|
{
|
|
QTcpSocket* DummySocket = DummyServer->nextPendingConnection();
|
|
DummySocket->disconnectFromHost();
|
|
DummySocket->waitForDisconnected(1000);
|
|
delete DummySocket;
|
|
DummyServer->close();
|
|
delete DummyServer;
|
|
return true;
|
|
}
|
|
DummyServer->close();
|
|
delete DummyServer;
|
|
return false;
|
|
}
|
|
|
|
int CModbusCCMgr::CloseModbusCCServer()
|
|
{
|
|
mModbusServer->close();
|
|
if(mModbusTCPSocketHandle != 0)
|
|
{
|
|
mModbusTCPSocketHandle->flush();
|
|
|
|
if(mModbusTCPSocketHandle->state() != QAbstractSocket::UnconnectedState)
|
|
{
|
|
// qDebug("Disconnecting socket");
|
|
mModbusTCPSocketHandle->disconnectFromHost();
|
|
if(mModbusTCPSocketHandle->waitForDisconnected(1000) == false)
|
|
{
|
|
// qDebug("Could not disconnect socket");
|
|
}
|
|
}
|
|
mModbusTCPSocketHandle->close();
|
|
delete mModbusTCPSocketHandle;
|
|
}
|
|
|
|
CZTLog::instance()->AddLogString(QString("Serveur Modbus Commande Centralisée fermé"),true);
|
|
return 1;
|
|
}
|
|
|
|
void CModbusCCMgr::NewModbusConnection()
|
|
{
|
|
mModbusTCPSocketHandle = mModbusServer->nextPendingConnection();
|
|
if(mModbusTCPSocketHandle != 0)
|
|
{
|
|
mDataLinkValid = true;
|
|
connect(mModbusTCPSocketHandle,SIGNAL(readyRead()),this,SLOT(ModbusDataReady()));
|
|
connect(mModbusTCPSocketHandle,SIGNAL(disconnected()),this,SLOT(ConnectionLost()));
|
|
//qDebug("ModbusCC: Connection with CC established");
|
|
CZTLog::instance()->AddLogString(QString("Connection Modbus avec la CC établie. IP locale [%1] - IP HPC [%2]").arg(mModbusTCPSocketHandle->localAddress().toString()).arg(mModbusTCPSocketHandle->peerAddress().toString()),true);
|
|
mZTWatchdogTimer->start();
|
|
mCCWatchdogTimer->start(MODBUS_CC_WATCHDOG_TIMEOUT*2); //Allow twice the time for the first watchdog reset.
|
|
mCCLinkState = false;
|
|
mCCWatchdogState = 0xBEEF;
|
|
|
|
emit ModbusCCConnected(mModbusTCPSocketHandle->localAddress().toIPv4Address(),mModbusTCPSocketHandle->peerAddress().toIPv4Address());
|
|
//emit ModbusCCLinkRecovered();
|
|
}
|
|
}
|
|
|
|
void CModbusCCMgr::ConnectionLost()
|
|
{
|
|
ModbusLinkDisconnected();
|
|
mZTWatchdogTimer->stop();
|
|
mCCWatchdogTimer->stop();
|
|
emit ModbusCCDisconnected();
|
|
emit ModbusCCLinkLost();
|
|
ResetCCRepository();
|
|
CZTLog::instance()->AddLogString(QString("Connection Modbus (Ethernet) avec la CC rompue."),true);
|
|
}
|
|
|
|
bool CModbusCCMgr::IsModbusConnected()
|
|
{
|
|
return mDataLinkValid;
|
|
}
|
|
|
|
void CModbusCCMgr::RegistersDatabaseUpdated(quint16 StartAddress, quint16 Length)
|
|
{
|
|
Q_UNUSED(StartAddress)
|
|
Q_UNUSED(Length)
|
|
|
|
|
|
qint16 WD = mModbusRepo->GetSingleReg(MODBUS_CC_WATCHDOG_BASE_REG_ADD);
|
|
// qDebug("WD = %d",WD);
|
|
if(WD != mCCWatchdogState)
|
|
{
|
|
mCCWatchdogTimer->start(MODBUS_CC_WATCHDOG_TIMEOUT); //The watchdog has toggled. Kick the timer.
|
|
mCCWatchdogState = WD;
|
|
if(mCCLinkState == false)
|
|
{
|
|
mCCLinkState = true;
|
|
emit ModbusCCLinkRecovered();
|
|
CZTLog::instance()->AddLogString("Lien de communication (Watchdog) avec la CC rétabli",true);
|
|
}
|
|
}
|
|
|
|
if(mCCLinkState == true) //Ignore incoming data if the link is not healty (Watchdog).
|
|
{
|
|
qint16 NTPWrite = mModbusRepo->GetSingleReg(MODBUS_CC_CLK_UPDATE_BASE_REG_ADD);
|
|
if((NTPWrite & MODBUS_CC_CLK_UPDATE_FLAG_MASK) != 0)
|
|
{
|
|
//Update date & time...
|
|
bool OK;
|
|
QList<qint16> DateTime = mModbusRepo->GetRegs(MODUBS_CC_CLK_SEC_BASE_REG_ADD,4,&OK);
|
|
if(OK)
|
|
{
|
|
qDebug("Registres: [%d][%d][%d][%d]",DateTime.at(0),DateTime.at(1),DateTime.at(2),DateTime.at(3));
|
|
quint8 Secs, Minutes, Hours, Month, Day;
|
|
quint8 temp;
|
|
temp = (quint8)(DateTime.at(0) >> 8);
|
|
Secs = BCDToDecByte(temp);
|
|
|
|
temp = (quint8)(DateTime.at(1) & 0x00FF);
|
|
Minutes = BCDToDecByte(temp);
|
|
|
|
temp = (qint8)(DateTime.at(1) >> 8);
|
|
Hours = BCDToDecByte(temp);
|
|
|
|
temp = (quint8)(DateTime.at(2) & 0x00FF);
|
|
Day = BCDToDecByte(temp);
|
|
|
|
temp = (quint8)(DateTime.at(2) >> 8);
|
|
Month = BCDToDecByte(temp);
|
|
|
|
quint16 Year = DateTime.at(3);
|
|
Year = BCDToDecWord(Year);
|
|
|
|
qDebug("Secs [%d], Minutes[%d], Hours[%d], Month[%d], Day[%d], Year[%d]",Secs,Minutes,Hours,Month,Day,Year);
|
|
|
|
QDateTime NetworkTime;
|
|
NetworkTime.setTimeSpec(Qt::UTC);
|
|
NetworkTime.setDate(QDate(Year,Month,Day));
|
|
NetworkTime.setTime(QTime(Hours,Minutes,Secs));
|
|
// QDateTime MyTime = NetworkTime.toLocalTime();
|
|
|
|
if(mLastDateTime != 0)
|
|
{
|
|
delete mLastDateTime;
|
|
}
|
|
mLastDateTime = new QDateTime(NetworkTime.toLocalTime()); //The QDateTime object will be deleted by the slot function...
|
|
emit ModbusDateTimeReceived(mLastDateTime);
|
|
|
|
qDebug("Date & Heure reçue du SACL: %s",mLastDateTime->toString("yyyy-MM-dd hh:mm:ss").toAscii().data());
|
|
mModbusRepo->WriteSingleReg(MODBUS_CC_CLK_UPDATE_BASE_REG_ADD,0);
|
|
}
|
|
|
|
}
|
|
#ifdef COMPILE_MODBUS_TEST_MODE
|
|
static quint16 VehTypeZT1 = 1024, VehTypeZT2 = 1024;
|
|
qint16 Reg = mModbusRepo->GetSingleReg(MODBUS_CC_ZT1_TRAIN_TYPE_REG_ADD);
|
|
if(VehTypeZT1 != Reg)
|
|
{
|
|
VehTypeZT1 = Reg;
|
|
qDebug("Type de train ZT1 = %d",VehTypeZT1);
|
|
}
|
|
Reg = mModbusRepo->GetSingleReg(MODBUS_CC_ZT2_TRAIN_TYPE_REG_ADD);
|
|
if(VehTypeZT2 != Reg)
|
|
{
|
|
VehTypeZT2 = Reg;
|
|
qDebug("Type de train ZT2 = %d",VehTypeZT2);
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
emit RepoHasChanged();
|
|
}
|
|
|
|
quint8 CModbusCCMgr::BCDToDecByte(const quint8 byte)
|
|
{
|
|
quint8 out = 0;
|
|
quint8 temp = 0;
|
|
|
|
out += byte & 0x0F;
|
|
temp = (byte >> 4) & 0x0F;
|
|
out += (temp * 10);
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
quint16 CModbusCCMgr::BCDToDecWord(const quint16 word)
|
|
{
|
|
quint16 out = 0;
|
|
quint16 temp = 0;
|
|
|
|
out += word & 0x000F;
|
|
temp = (word >> 4) & 0x000F;
|
|
out += (temp * 10);
|
|
temp = (word >> 8) & 0x000F;
|
|
out += (temp * 100);
|
|
temp = (word >> 12) & 0x000F;
|
|
out += (temp * 1000);
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
void CModbusCCMgr::ModbusRequestException(quint8 ExceptionCode, quint8 FctCode)
|
|
{
|
|
//qDebug("Modbus CC: Request exception occured. ExceptCode: [%d], FctCode: [%d]",ExceptionCode,FctCode);
|
|
CEngLog::instance()->AddLogString(QString("Modbus CC: Exception de requête. ExceptionCode[%1], FctCode[%2]").arg(ExceptionCode).arg(FctCode));
|
|
}
|
|
|
|
void CModbusCCMgr::ModbusCCWatchdogTimeout()
|
|
{
|
|
CZTLog::instance()->AddLogString("Perte du lien de communication avec la CC: Watchdog CC Expiré",true);
|
|
ResetCCRepository();
|
|
// emit ModbusCCDisconnected();
|
|
emit ModbusCCLinkLost();
|
|
mCCLinkState = false;
|
|
mCCWatchdogState = 0xBEEF;
|
|
}
|
|
|
|
void CModbusCCMgr::ModbusZTWatchdogTimeout()
|
|
{
|
|
|
|
if(mZTWatchdogEnabled)
|
|
{
|
|
quint16 WD = mZTWatchdog;
|
|
// qDebug("WD = 0x%x",WD);
|
|
mModbusRepo->WriteSingleReg(MODBUS_ZT_WATCHDOG_REG_ADD,WD);
|
|
if(mZTWatchdog == ZT_WATCHDOG_ON_VALUE)
|
|
{
|
|
mZTWatchdog = ZT_WATCHDOG_OFF_VALUE;
|
|
}
|
|
else
|
|
{
|
|
mZTWatchdog = ZT_WATCHDOG_ON_VALUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
int CModbusCCMgr::ResetCCRepository()
|
|
{
|
|
//Clear read registers
|
|
mModbusRepo->WriteSingleReg(MODBUS_CC_WATCHDOG_BASE_REG_ADD,0);
|
|
mModbusRepo->WriteSingleReg(MODBUS_CC_AN_BASE_REG_ADD,0);
|
|
mModbusRepo->WriteSingleReg(MODBUS_CC_ZT1_TRAIN_TYPE_REG_ADD, MODBUS_CC_TRAIN_TYPE_INVALID_SACL_OFFLINE);
|
|
mModbusRepo->WriteSingleReg(MODBUS_CC_ZT2_TRAIN_TYPE_REG_ADD, MODBUS_CC_TRAIN_TYPE_INVALID_SACL_OFFLINE);
|
|
QList<qint16> ResetValues;
|
|
ResetValues << 0 << 0 << 0 //Train compo ZT1
|
|
<< 0 << 0 << 0 //Train compo ZT2
|
|
<< 0 << 0 << 0 << 0 << 0; //Date & Time update registers
|
|
|
|
mModbusRepo->WriteMultipleRegs(MODBUS_CC_ZT1_TRAIN_ID_1_REG_ADD,ResetValues);
|
|
|
|
//Do not clear the TK (write) regisers, they will clear themselves when needed.
|
|
return RET_OK;
|
|
}
|
|
|
|
bool CModbusCCMgr::GetZT1InhibitionFlag()
|
|
{
|
|
bool OK = false;
|
|
|
|
if(mCCLinkState == false)//Ignore registers data if link is with SACL is not healthy
|
|
{
|
|
return false;
|
|
}
|
|
|
|
qint16 Reg = mModbusRepo->GetSingleReg(MODBUS_CC_AN_BASE_REG_ADD,&OK);
|
|
|
|
if(OK)
|
|
{
|
|
if((Reg & MODBUS_CC_INHIBIT_ZT1_FLAG_MASK) != 0)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int CModbusCCMgr::ClearZT1InhibitionFlag()
|
|
{
|
|
bool OK = false;
|
|
qint16 Reg = mModbusRepo->GetSingleReg(MODBUS_CC_AN_BASE_REG_ADD,&OK);
|
|
|
|
if(OK)
|
|
{
|
|
Reg &= ~MODBUS_CC_INHIBIT_ZT1_FLAG_MASK;
|
|
mModbusRepo->WriteSingleReg(MODBUS_CC_AN_BASE_REG_ADD,Reg);
|
|
return RET_OK;
|
|
|
|
}
|
|
return RET_ERROR;
|
|
}
|
|
|
|
bool CModbusCCMgr::GetZT2InhibitionFlag()
|
|
{
|
|
bool OK = false;
|
|
|
|
if(mCCLinkState == false)//Ignore registers data if link is with SACL is not healthy
|
|
{
|
|
return false;
|
|
}
|
|
|
|
qint16 Reg = mModbusRepo->GetSingleReg(MODBUS_CC_AN_BASE_REG_ADD,&OK);
|
|
|
|
if(OK)
|
|
{
|
|
if((Reg & MODBUS_CC_INHIBIT_ZT2_FLAG_MASK) != 0)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
int CModbusCCMgr::ClearZT2InhibitionFlag()
|
|
{
|
|
bool OK = false;
|
|
qint16 Reg = mModbusRepo->GetSingleReg(MODBUS_CC_AN_BASE_REG_ADD,&OK);
|
|
|
|
if(OK)
|
|
{
|
|
Reg &= ~MODBUS_CC_INHIBIT_ZT2_FLAG_MASK;
|
|
mModbusRepo->WriteSingleReg(MODBUS_CC_AN_BASE_REG_ADD,Reg);
|
|
return RET_OK;
|
|
|
|
}
|
|
return RET_ERROR;
|
|
}
|
|
|
|
QList<qint16> CModbusCCMgr::GetZT1TrainComposition()
|
|
{
|
|
bool OK = false;
|
|
QList<qint16> Compo;
|
|
Compo = mModbusRepo->GetRegs(MODBUS_CC_ZT1_TRAIN_ID_1_REG_ADD,3,&OK);
|
|
|
|
if(OK == false || mCCLinkState == false) //Ignore registers data if link is with SACL is not healthy
|
|
{
|
|
Compo << 0 << 0 << 0;
|
|
}
|
|
|
|
return Compo;
|
|
}
|
|
|
|
QList<qint16> CModbusCCMgr::GetZT2TrainComposition()
|
|
{
|
|
bool OK = false;
|
|
QList<qint16> Compo;
|
|
Compo = mModbusRepo->GetRegs(MODBUS_CC_ZT2_TRAIN_ID_1_REG_ADD,3,&OK);
|
|
|
|
if(OK == false || mCCLinkState == false)//Ignore registers data if link is with SACL is not healthy
|
|
{
|
|
Compo << 0 << 0 << 0;
|
|
}
|
|
|
|
return Compo;
|
|
}
|
|
|
|
|
|
qint16 CModbusCCMgr::GetZT1TrainType()
|
|
{
|
|
bool OK = false;
|
|
qint16 Reg = mModbusRepo->GetSingleReg(MODBUS_CC_ZT1_TRAIN_TYPE_REG_ADD,&OK);
|
|
int Type = TRAIN_TYPE_UNKNOWN;
|
|
if(OK)
|
|
{
|
|
if(Reg == MODBUS_CC_TRAIN_TYPE_MR63)
|
|
{
|
|
Type = TRAIN_TYPE_MR63;
|
|
}
|
|
else if(Reg == MODBUS_CC_TRAIN_TYPE_MR73)
|
|
{
|
|
Type = TRAIN_TYPE_MR73;
|
|
}
|
|
else if(Reg == MODBUS_CC_TRAIN_TYPE_MPM10)
|
|
{
|
|
Type = TRAIN_TYPE_MPM10;
|
|
}
|
|
else if(Reg == MODBUS_CC_TRAIN_TYPE_MAINTENANCE)
|
|
{
|
|
Type = TRAIN_TYPE_MAINTENANCE_VEHICLE;
|
|
}
|
|
else if(Reg == MODBUS_CC_TRAIN_TYPE_INVALID_SACL_OFFLINE)
|
|
{
|
|
Type = TRAIN_TYPE_UNKNOWN;
|
|
}
|
|
else
|
|
{
|
|
CEngLog::instance()->AddLogString(QString("MODBUS: Réception d'un type de train ZT1 invalide du SACL [%1]").arg(Reg));
|
|
Type = TRAIN_TYPE_UNKNOWN;
|
|
}
|
|
}
|
|
if(mCCLinkState == false)//Ignore registers data if link is with SACL is not healthy
|
|
{
|
|
Type = TRAIN_TYPE_UNKNOWN;
|
|
}
|
|
return Type;
|
|
}
|
|
|
|
qint16 CModbusCCMgr::GetZT2TrainType()
|
|
{
|
|
bool OK = false;
|
|
qint16 Reg = mModbusRepo->GetSingleReg(MODBUS_CC_ZT2_TRAIN_TYPE_REG_ADD,&OK);
|
|
int Type = TRAIN_TYPE_UNKNOWN;
|
|
if(OK)
|
|
{
|
|
if(Reg == MODBUS_CC_TRAIN_TYPE_MR63)
|
|
{
|
|
Type = TRAIN_TYPE_MR63;
|
|
}
|
|
else if(Reg == MODBUS_CC_TRAIN_TYPE_MR73)
|
|
{
|
|
Type = TRAIN_TYPE_MR73;
|
|
}
|
|
else if(Reg == MODBUS_CC_TRAIN_TYPE_MPM10)
|
|
{
|
|
Type = TRAIN_TYPE_MPM10;
|
|
}
|
|
else if(Reg == MODBUS_CC_TRAIN_TYPE_MAINTENANCE)
|
|
{
|
|
Type = TRAIN_TYPE_MAINTENANCE_VEHICLE;
|
|
}
|
|
else if(Reg == MODBUS_CC_TRAIN_TYPE_INVALID_SACL_OFFLINE)
|
|
{
|
|
Type = TRAIN_TYPE_UNKNOWN;
|
|
}
|
|
else
|
|
{
|
|
CEngLog::instance()->AddLogString(QString("MODBUS: Réception d'un type de train ZT2 invalide du SACL [%1]").arg(Reg));
|
|
Type = TRAIN_TYPE_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
if(mCCLinkState == false) //Ignore registers data if link is with SACL is not healthy
|
|
{
|
|
Type = TRAIN_TYPE_UNKNOWN;
|
|
}
|
|
return Type;
|
|
}
|
|
|
|
int CModbusCCMgr::SetZTWatchdogEnabled(bool Enabled)
|
|
{
|
|
mZTWatchdogEnabled = Enabled;
|
|
return RET_OK;
|
|
}
|
|
|
|
int CModbusCCMgr::SetActivatedITI(int ITI)
|
|
{
|
|
bool OK = false;
|
|
quint16 Reg = mModbusRepo->GetSingleReg(MODBUS_MISC_DATA_BASE_REG_ADD,&OK);
|
|
if(OK == true)
|
|
{
|
|
if(ITI == ZT_SECONDARY_ITI)
|
|
{
|
|
Reg |= ZT_ACTIVATED_ITI_FLAG_MASK;
|
|
}
|
|
else
|
|
{
|
|
Reg &= ~ZT_ACTIVATED_ITI_FLAG_MASK;
|
|
}
|
|
|
|
return mModbusRepo->WriteSingleReg(MODBUS_MISC_DATA_BASE_REG_ADD,Reg);
|
|
}
|
|
else
|
|
{
|
|
return RET_ERROR;
|
|
}
|
|
}
|