#include "ModbusCCMgr.h" #include "ZTLog.h" #include "EngLog.h" #include "ModbusCCDefs.h" #include #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 = 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; emit ModbusCCConnected(); 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 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 = BCDToIntByte(temp); temp = (quint8)(DateTime.at(1) & 0x00FF); Minutes = BCDToIntByte(temp); temp = (qint8)(DateTime.at(1) >> 8); Hours = BCDToIntByte(temp); temp = (quint8)(DateTime.at(2) & 0x00FF); Day = BCDToIntByte(temp); temp = (quint8)(DateTime.at(2) >> 8); Month = BCDToIntByte(temp); quint16 Year = DateTime.at(3); Year = BCDToIntWord(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::BCDToIntByte(const quint8 byte) { quint8 out = 0; quint8 temp = 0; out += byte & 0x0F; temp = (byte >> 4) & 0x0F; out += (temp * 10); return out; } quint16 CModbusCCMgr::BCDToIntWord(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(); mCCLinkState = false; } 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 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 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; } 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; } }