#include "ModbusCCMgr.h" #include "ZTLog.h" #include "EngLog.h" #include "ModbusCCDefs.h" #include #include "ZTData.h" CModbusCCMgr::CModbusCCMgr(CModbusRepository *Repo, int ModbusPort, int DevID) : CModbusBackend(Repo) { mModbusServer = new QTcpServer(); mDeviceID = DevID; mModbusPort = ModbusPort; 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; } 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; } 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[%1]").arg(mModbusTCPSocketHandle->peerAddress().toString()),true); mZTWatchdogTimer->start(); mCCWatchdogTimer->start(MODBUS_CC_WATCHDOG_TIMEOUT*2); //Allow twice the time for the first watchdog reset. mCCLinkState = true; emit ModbusCCConnected(); } } void CModbusCCMgr::ConnectionLost() { ModbusLinkDisconnected(); mZTWatchdogTimer->stop(); mCCWatchdogTimer->stop(); emit ModbusCCDisconnected(); 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; 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 == 1) { //Update date & time... bool OK; QList DateTime = mModbusRepo->GetRegs(MODUBS_CC_CLK_SEC_BASE_REG_ADD,4,&OK); if(OK) { qint8 Secs, Minutes, Hours, Month, Day; Secs = (qint8)(DateTime.at(0) >> 8); Minutes = (qint8)(DateTime.at(1) & 0x00FF); Hours = (qint8)(DateTime.at(1) >> 8); Day = (qint8)(DateTime.at(2) & 0x00FF); Month = (qint8)(DateTime.at(2) >> 8); qint16 Year = DateTime.at(3); 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()); 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); } } } emit RepoHasChanged(); } 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(); mCCLinkState = false; } void CModbusCCMgr::ModbusZTWatchdogTimeout() { qint16 WD = mZTWatchdog; mModbusRepo->WriteSingleReg(MODBUS_ZT_WATCHDOG_REG_ADD,WD); if(mZTWatchdog == 1) { mZTWatchdog = 0; } else { mZTWatchdog = 1; } } 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 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; } 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; } QList CModbusCCMgr::GetZT1TrainComposition() { bool OK = false; QList 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 CModbusCCMgr::GetZT2TrainComposition() { bool OK = false; QList 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; }