/******************************************************************************* * * * Société de Transports de Montréal. * * 2012 * * * * Projet Zones Tests * * * * * * * *******************************************************************************/ /* Description: Machine à état principale de la ZT. Elle lit les entrées des CDV et des CI et démarre le thread d'analyse lorsqu'un train procède sur la ZT. La classe gère aussi la compilation des déclenchements et des logs de passage. */ /* ************************************************************************** */ /* Revision: ### YYYMMDD JFM Verision d'origine. ### YYYYMMDD Description du besoin ou du bug Description du changement. */ /* ************************************************************************** */ #include "ZTStateMachine.h" #include "ZTSimulator.h" #include #include #include #include "ZTLog.h" #include "math.h" #include "MaintenancePage.h" #include "RamMonitor.h" #include "ModbusCCDefs.h" CZTStateMachine::CZTStateMachine(QObject *parent) : QObject(parent) { QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); mZT1State = ZT1_WAIT_FOR_CI_STATE; mZT2State = ZT2_WAIT_FOR_CI_STATE; mZTState = ZT_INIT_STATE; mZT2Present = true; // mZTDataPtr = new CZTData; mZTStationPtr = 0; mZTDetectionConfig = 0; mLastInputs = 0; mZtSimPtr = 0; mLogMgr = 0; mCalibrationPassagesCount = 0; mCCModbusRepo = 0; //mExtIOInterface = 0; mNbPassages = 0; mNbTriggers = 0; // mZT1Active = false; //JFM ztstatus // mZT2Active = false; mZT1ActiveStatus = SB_ZT_INACTIVE_STATUS; mZT2ActiveStatus = SB_ZT_INACTIVE_STATUS; mCIZT1Active = false; mLogDelay = ZT_SM_DEFAULT_LOG_DELAY; mAutoExportZT1CSV = false; mAutoExportZT2CSV = false; //mTKGenerator = new CTKGenerator(); mIsPGCalibON = false; mIsMaintenanceModeON = false; //Create the ZT1 train analysis thread mZT1SMThread = new QThread; mZT1WorkerThread = new CZT1AnalysisThread(); mZT1WorkerThread->moveToThread(mZT1SMThread); connect(mZT1SMThread,SIGNAL(started()),mZT1WorkerThread,SLOT(AnalyzeZT1Train())); connect(mZT1WorkerThread,SIGNAL(ZT1DataUpdate(CZT1ThreadData*,bool,int)),this,SLOT(ZT1StateChanged(CZT1ThreadData*,bool,int))); connect(mZT1WorkerThread,SIGNAL(DetectionTriggered(CZTDetectionData*)),this,SLOT(ZT1NewDetection(CZTDetectionData*))); connect(mZT1WorkerThread,SIGNAL(NewPGCalibrationData(CZTPGCalibrationData*)),this,SLOT(NewPGCalibrationData(CZTPGCalibrationData*))); connect(mZT1WorkerThread,SIGNAL(NewZT1Flag(int,CZT1FlagsData*)),this,SLOT(ZT1NewFlag(int,CZT1FlagsData*))); connect(mZT1WorkerThread,SIGNAL(AddLogString(QString)),this,SLOT(AddLogStringFromThread(QString))); //Create the ZT2 train analysis thread (even if the station has no ZT2... it doesn't hurt anyone) mZT2SMThread = new QThread; mZT2WorkerThread = new CZT2AnalysisThread(); mZT2WorkerThread->moveToThread(mZT2SMThread); connect(mZT2SMThread,SIGNAL(started()),mZT2WorkerThread,SLOT(AnalyzeZT2Train())); connect(mZT2WorkerThread,SIGNAL(ZT2DataUpdate(CZT2ThreadData*)),this,SLOT(ZT2StateChanged(CZT2ThreadData*))); connect(mZT2WorkerThread,SIGNAL(DetectionTriggered(CZTDetectionData*)),this,SLOT(ZT2NewDetection(CZTDetectionData*))); connect(mZT2WorkerThread,SIGNAL(AddLogString(QString)),this,SLOT(AddLogStringFromThread(QString))); mZT1LogDelayTimer.start(); mTimeToForceSyncFS = false; mFSSyncTimer.start(); } CZTStateMachine::~CZTStateMachine() { mZT1SMThread->quit(); mZT1SMThread->wait(1000); delete mZT1SMThread; delete mZT1WorkerThread; mZT2SMThread->quit(); mZT2SMThread->wait(1000); delete mZT2SMThread; delete mZT2WorkerThread; //delete mTKGenerator; DestroyZT1Log(); DestroyZT2Log(); DestroyCalibrationData(); } unsigned int CZTStateMachine::ZTStateMachine(unsigned int Event, unsigned int SubEvent) { mCurInputs = mInputModule->GetInputs(); switch(mZTState) { case ZT_INIT_STATE: { //mZTPagePTr->SetZTStatus(mNbPassages,mNbTriggers,mZT1Active,mZT2Active); mZTPagePTr->SetZTStatus(mNbPassages,mNbTriggers,mZT1ActiveStatus,mZT2ActiveStatus); mZTStationPtr->UpdateStationMasks(mCurInputs); mZTStationPtr->UpdateCDVs(mCurInputs); //Wait for ZT1 and ZT2 CDVs to be free before starting the State Machine... if(!mZTStationPtr->IsZT1CDVOccupied() && !mZTStationPtr->IsZT2CDVOccupied()) { mZTState = ZT_EXECUTE_STATE; } else { mZTPagePTr->UpdateCDVDisplay(); if(mZtSimPtr != 0) //ptr will be 0 if not in sim mode { mZtSimPtr->UpdateSimulatorDisplay(); } } break; } case ZT_EXECUTE_STATE: { if(mCurInputs != mLastInputs) { //Update masks mZTStationPtr->UpdateStationMasks(mCurInputs); //Update variables according to new inputs mZTStationPtr->UpdateCDVs(mCurInputs); mCIZT1Active = ((mCurInputs & mZTInputMasks->InputZT1ITIMask) != 0); mCIZT2Active = ((mCurInputs & mZTInputMasks->InputZT2ITIMask) != 0); bool AN1State, AN2State; //If the mCCModbusRepo is not 0, then it has to be used (Modbus connection is used as CC interface) if(mCCModbusRepo == 0) { AN1State = (mCurInputs & mZTInputMasks->InputZT1ANMask) != 0; AN2State = (mCurInputs &mZTInputMasks->InputZT2ANMask) != 0; } // else // { // AN1State = (mCCModbusRepo->GetSingleReg(MODBUS_CC_AN_BASE_REG_ADD) & MODBUS_CC_AN1_FLAG_MASK) != 0; // AN2State = (mCCModbusRepo->GetSingleReg(MODBUS_CC_AN_BASE_REG_ADD) & MODBUS_CC_AN2_FLAG_MASK) != 0; // } // mTKGenerator->SetInputStates((mCurInputs & mZTInputMasks->InputZT1ANMask) != 0, // mZTStationPtr->IsZT1AlarmAutoAcquireCDVOccupied(), // (mCurInputs &mZTInputMasks->InputZT2ANMask) != 0, // mZTStationPtr->IsZT2AlarmAutoAcquireCDVOccupied()); mTKGenerator->SetInputStates(AN1State,mZTStationPtr->IsZT1AlarmAutoAcquireCDVOccupied(), AN2State,mZTStationPtr->IsZT2AlarmAutoAcquireCDVOccupied()); } if(mIsMaintenanceModeON == false) { ZT1StateMachine(Event,SubEvent); if(mZT2Present) //if there is no ZT2, don't execute the ZT2 SM { ZT2StateMachine(Event,SubEvent); } } else { //Do the data acquisition for the PP detection while in maintenance mode. unsigned int Inputs = mPCIIOPtr->GetInputs(); if((Inputs & mZTInputMasks->InputZT1PIMask) == 0) { if(mMaintenancePPIZT1Latch == false) { emit MaintenancePPActivated(MAINTENANCE_PPI_ZT1_ID); SendTKToPCC(DETECTION_PPI_DETECTION, 27); mMaintenancePPIZT1Latch = true; } } if((Inputs & mZTInputMasks->InputZT1PEMask) == 0) { if(mMaintenancePPEZT1Latch == false) { SendTKToPCC(DETECTION_PPE_DETECTION, 18); emit MaintenancePPActivated(MAINTENANCE_PPE_ZT1_ID); mMaintenancePPEZT1Latch = true; } } if(mZT2Present) //if there is no ZT2, don't check the pedals { if((Inputs & mZTInputMasks->InputZT2PIMask) == 0) { if(mMaintenancePPIZT2Latch == false) { SendTKToPCC(DETECTION_ZT2_PPI_DETECTION, 27); emit MaintenancePPActivated(MAINTENANCE_PPI_ZT2_ID); mMaintenancePPIZT2Latch = true; } } if((Inputs & mZTInputMasks->InputZT2PEMask) == 0) { if(mMaintenancePPEZT2Latch == false) { SendTKToPCC(DETECTION_ZT2_PPE_DETECTION, 18); emit MaintenancePPActivated(MAINTENANCE_PPE_ZT2_ID); mMaintenancePPEZT2Latch = true; } } } } mZTPagePTr->UpdateCDVDisplay(); if(mZtSimPtr != 0) //ptr will be 0 if not in sim mode { mZtSimPtr->UpdateSimulatorDisplay(); } if(mTimeToForceSyncFS == true) { mFSSyncTimer.start(); system("sync"); mTimeToForceSyncFS = false; qDebug() << "Sync FS took: " << mFSSyncTimer.elapsed() << "ms"; mFSSyncTimer.start(); } break; } } if(mCurInputs != mLastInputs) mLastInputs = mCurInputs; return RET_OK; } unsigned int CZTStateMachine::ZT1StateMachine(unsigned int Event, unsigned int SubEvent) { Q_UNUSED(Event) Q_UNUSED(SubEvent) switch(mZT1State) { case ZT1_WAIT_FOR_CI_STATE: { if(mCIZT1Active) { mZT1State = ZT1_WAIT_FOR_TRAIN_STATE; } else { } break; } case ZT1_WAIT_FOR_TRAIN_STATE: { if(mCIZT1Active == false) { mZT1State = ZT1_WAIT_FOR_CI_STATE; } if(!mZTStationPtr->IsZT1ApproachPresent())//When there is no approach CDV (Montmorency), use the subsequent CDV to detect maintenance vehicles going backward { if(mZTStationPtr->IsZT1SubsequentCDVOccupied()) //If subsequent CDV is occupied when waiting for train = vehicle going backward { mZT1State = ZT1_WAIT_FOR_SUBSEQUENT_LIBERATION; } else if(mZTStationPtr->IsZT1CDVOccupied()) //since the approach is the ZT CDV, just consider the latter { DestroyZT1Log(); mEventsRefTimer.start(); mNbPassages++; InsertZT1LogItem(); mZT1Log.mZT1Flags.mPGCalibrationON = (mIsPGCalibON == true); mZT1State = ZT1_TRAIN_ON_APPROACH_CDV_STATE; } } else if(mZTStationPtr->IsZT1ApproachCDVOccupied() && !mZTStationPtr->IsZT1CDVOccupied()) //Normal situation { DestroyZT1Log(); mEventsRefTimer.start(); mNbPassages++; InsertZT1LogItem(); mZT1Log.mZT1Flags.mPGCalibrationON = (mIsPGCalibON == true); mZT1State = ZT1_TRAIN_ON_APPROACH_CDV_STATE; } break; } case ZT1_WAIT_FOR_SUBSEQUENT_LIBERATION: //Subsequent CDV should never be occupied before ZT CDV. { if(mCIZT1Active == false) { mZT1State = ZT1_WAIT_FOR_CI_STATE; } if(!mZTStationPtr->IsZT1CDVOccupied() && !mZTStationPtr->IsZT1SubsequentCDVOccupied()) { mZT1State = ZT1_WAIT_FOR_TRAIN_STATE; } break; } case ZT1_TRAIN_ON_APPROACH_CDV_STATE: { if(mCIZT1Active == false) { mZT1State = ZT1_WAIT_FOR_CI_STATE; } else if(!mZTStationPtr->IsZT1ApproachCDVOccupied()) { mZT1State = ZT1_WAIT_FOR_TRAIN_STATE; } else if(mZTStationPtr->IsZT1CDVOccupied()) { mZT1ActiveStatus = SB_ZT_ACTIVE_STATUS; mZTPagePTr->SetZTStatus(mNbPassages,mNbTriggers,mZT1ActiveStatus,mZT2ActiveStatus); mZTPagePTr->SetZT1ActivationState(true); mZTPagePTr->ResetZT1Stats(); InsertZT1LogItem(); mZT1WorkerThread->UpdateDetectionConfig(mZTDetectionConfig); mTKGenerator->UpdateDetectionConfig(mZTDetectionConfig); mZT1SMThread->start(QThread::NormalPriority); mZT1PassageTimeLimitTimer.start(); //CZTLog::instance()->AddLogString("ZT1 activée",true); CZTLog::instance()->ClearBufferString(); CZTLog::instance()->AddBufferString("ZT1 activée",true); if(mIsPGCalibON) { emit PGCalibrationStatus(mCalibrationPassagesCount+1,mPGNbTotalPassages); } mZT1State = ZT1_ANALYZE_TRAIN_STATE; } break; } case ZT1_ANALYZE_TRAIN_STATE: { if(mZTStationPtr->IsZT1AnalysisFinished()) //Normally, this is true when the train leaves CDV ZT1 (except in Snowdon)... { mZT1ActiveStatus = SB_ZT_INACTIVE_STATUS; mZTPagePTr->SetZTStatus(mNbPassages,mNbTriggers,mZT1ActiveStatus,mZT2ActiveStatus); //The train is leaving the ZT1 CDV. Stop the analysis thread. mZT1WorkerThread->TerminateAnalysis(); mZT1SMThread->quit(); InsertZT1LogItem(); CZTLog::instance()->AddBufferString("ZT1 désactivée",true); mZT1State = ZT1_POST_DETECTION_STATE; } else if(mZT1PassageTimeLimitTimer.elapsed() > ZT1_MAX_PASSAGE_DELAY) //Si le train prend plus de 5 minutes à passer = ignorer le passage. { mZT1ActiveStatus = SB_ZT_INACTIVE_STATUS; mZTPagePTr->SetZTStatus(mNbPassages,mNbTriggers,mZT1ActiveStatus,mZT2ActiveStatus); //Stop the analysis thread. mZT1WorkerThread->TerminateAnalysis(); mZT1SMThread->quit(); DestroyZT1Log(); CZTLog::instance()->AddLogString("Délai de passage expiré: ZT1 désactivée",true); mZT1State = ZT1_WAIT_FOR_CI_STATE; } break; } case ZT1_POST_DETECTION_STATE: { if(AnalyzeZT1PostDetection() == RET_POST_DETECTION_VALID) { SaveZT1EventsLog(&mZT1Log); mTKGenerator->BeginTKEmission(); if(mIsPGCalibON) { mCalibrationPassagesCount++; if(mCalibrationPassagesCount < mPGNbTotalPassages) { } else { ComputePGCalibration(); QuitPGCalibrationMode(); } } } else //We detected a véhicule travaux. { DestroyZT1Log(); } if(mZT2Present == false && (mFSSyncTimer.elapsed() > FILESYSTEM_FORCED_SYNC_TIMEOUT)) { mTimeToForceSyncFS = true; } mZT1State = ZT1_WAIT_FOR_CI_STATE; break; } default: { break; } } return RET_OK; } unsigned int CZTStateMachine::AnalyzeZT1PostDetection() { //Get useful information from detections log... bool MagSensorCountError = false; bool PEQ1Error = false; int NbPGDetections = 0; int NbFNDetections = 0; mZT1Log.mZT1Flags.mIsProblematicPassage = 0; for(int i = 0; i < mZT1DetectionsLog.size(); i++) { if(mZT1DetectionsLog.at(i)->mDetectionID == DETECTION_PG_DETECTION) { NbPGDetections++; } if(mZT1DetectionsLog.at(i)->mDetectionID == DETECTION_MAGNETIC_SENSOR_COUNT) { MagSensorCountError = true; CEngLog::instance()->AddLogString("[Post-Détection]--> Flag de détection d'erreur de comptage actif",3); } if(mZT1DetectionsLog.at(i)->mDetectionID == DETECTION_PEQ1_DETECTION) { CEngLog::instance()->AddLogString("[Post-Détection]--> Flag de détection PEQ1 actif",3); PEQ1Error = true; } } //2015-03-03 //Computer crash may be related to addition of this section ///START //If the thread did not detect any count error, check if the rank count is valid... if(MagSensorCountError == false) { quint32 S1Count = 0, S2Count = 0; for(int sample = 0; sample < mZT1Log.mZT1LogData.size(); sample++) { if(mZT1Log.mZT1LogData.at(sample)->mZT1ThreadData != 0) { if(mZT1Log.mZT1LogData.at(sample)->mZT1ThreadData->mS1Count > S1Count) { S1Count = mZT1Log.mZT1LogData.at(sample)->mZT1ThreadData->mS1Count; } if(mZT1Log.mZT1LogData.at(sample)->mZT1ThreadData->mS2Count > S2Count) { S2Count = mZT1Log.mZT1LogData.at(sample)->mZT1ThreadData->mS2Count; } } } //Thread should have detected S1 S2 count discrepancy but it's easy to re-check here. if(S1Count != S2Count) { MagSensorCountError = true; } else if(S1Count != 12 && S1Count != 24 && S1Count != 36) //Make shure we counted all the ranks { MagSensorCountError = true; } else if(S2Count != 12 && S2Count != 24 && S2Count != 36) //Make shure we counted all the ranks { MagSensorCountError = true; } } ///END bool PostAnalyseData = MagSensorCountError; //If we have a count error, do a post-analysis of the data if(PEQ1Error == true && mZTDetectionConfig->mZTDetectionConfig[DETECTION_FCT_ZT1].AnalysisActive) //If we have a PEQ1 detection, clear all other errors and emit PEQ1 only { //If we have a counting error AND the PEQ1 is FN stuck (most of the time this will happen because //of the sensor count error), then ignore the PEQ1... if(MagSensorCountError == true && mZT1PEQType == PEQ1_FN_STUCK_LOW_TYPE) { PostAnalyseData = true; } else { PostAnalyseData = false; ClearZT1DetectionsList(); NbPGDetections = 0; if(mZTDetectionConfig->mZTDetectionConfig[DETECTION_FCT_ZT1].AnalysisActive) { CZTLog::instance()->AddBufferString("Panne équipement ZT1: SDF à 1",true); CZTDetectionData *NewDetection = new CZTDetectionData(); NewDetection->mDetectionID = DETECTION_PEQ1_DETECTION; NewDetection->mTimeStamp = 0; NewDetection->mRank = ZT_DEFAULT_DETECTION_RANK; mZT1DetectionsLog.prepend(NewDetection); } } } if(PostAnalyseData == true) //check if we need to do a post-analysis of the data. { int S1Count = 0, S2Count = 0, FNCount = 0, PGCount = 0, PPICount = 0, PPECount = 0; int S1 = 0, S2 = 0, FN = 0, PPI = 0, PPE = 0; bool PGActive = false; bool PGCalibrationON = mZT1Log.mZT1Flags.mPGCalibrationON == 1; qint32 PGIOffset = mZT1Log.mZT1Flags.mIntPGOffset; qint32 PGEOffset = mZT1Log.mZT1Flags.mExtPGOffset; qint32 PGValueTreshold = mZT1Log.mZT1Flags.mPGTresholdValue; qint32 Quadra; int PGNonDetectionSampleCount = 0; CEngLog::instance()->AddLogString("[Post-Détection]--> Début de l'analyse en Post-Détection",3); //First, clear the detections list. ClearZT1DetectionsList(); CZT1ThreadData *Data; //Analyze the log and add detections to the list if any. for(int sample = 0; sample < mZT1Log.mZT1LogData.size(); sample++) { if(mZT1Log.mZT1LogData.at(sample)->mZT1ThreadData != 0) { Data = mZT1Log.mZT1LogData.at(sample)->mZT1ThreadData; //Count magnetic sensors. //Detect High to Low transitions if(S1 == 1 && Data->mS1 == 0) { S1Count++; } S1 = Data->mS1; //Detect High to Low transitions if(S2 == 1 && Data->mS2 == 0) { S2Count++; } S2 = Data->mS2; //Count FN occurences //Detect High to Low transitions if(FN == 1 && Data->mFN == 0) { FNCount++; } FN = Data->mFN; //If we were calibrating, ignore the PG data. if(PGCalibrationON == false) { //Compute and verify if the PG is detected. Quadra = ((Data->mPGIntValue - PGIOffset) * (Data->mPGExtValue - PGEOffset)); if(Quadra > PGValueTreshold) { if(PGActive == false) { PGCount++; PGActive = true; } PGNonDetectionSampleCount = 0; } else { if(PGActive == true) { if(PGNonDetectionSampleCount >= 3) //To avoid false detections when glitches or rebounds appear, we need to have at least 3 consecutive samples { //without detection to consider the PG inactive PGActive = false; } PGNonDetectionSampleCount++; } } } //Check for PP detections if needed if(mZTDetectionConfig->mZTDetectionConfig[DETECTION_FCT_PP].AnalysisActive == true) { if(PPI == 1 && Data->mPInt == 0) { PPICount++; //register the detection in the list. CZTDetectionData *NewDetection = new CZTDetectionData(); NewDetection->mDetectionID = DETECTION_PPI_DETECTION; NewDetection->mTimeStamp = Data->mTimeStamp; NewDetection->mRank = ZT_DEFAULT_DETECTION_RANK; mZT1DetectionsLog.append(NewDetection); } PPI = Data->mPInt; if(PPE == 1 && Data->mPExt == 0) { PPECount++; //register the detection in the list. CZTDetectionData *NewDetection = new CZTDetectionData(); NewDetection->mDetectionID = DETECTION_PPE_DETECTION; NewDetection->mTimeStamp = Data->mTimeStamp; NewDetection->mRank = ZT_DEFAULT_DETECTION_RANK; mZT1DetectionsLog.append(NewDetection); } PPE = Data->mPExt; } } } CEngLog::instance()->AddLogString(QString().sprintf("[Post-Détection]--> Résultat des données brutes: [S1Count = %d], [S2Count = %d], [PGCount = %d], [FNCount = %d], [PPICount = %d], [PPECount = %d]",S1Count,S2Count,PGCount,FNCount,PPICount,PPECount),3); //First, try to detect a véhicule travaux. If we have a PG count of 0, it is a véhicule travaux and we //just totally ignore this passage if(PGCalibrationON == false) { if(PGCount == 0) { CZTLog::instance()->AddLogString("[POST DETECTION]--> Véhicule travaux détecté. Annulation et fin de l'analyse ZT1",true); ClearZT1DetectionsList(); return RET_POST_DETECTION_WORK_VEHICLE; } } //Analyze the PG count if necessary if(mZTDetectionConfig->mZTDetectionConfig[DETECTION_FCT_PG].AnalysisActive == true) { if(PGCalibrationON == false) { if(PGCount == 12 || PGCount == 24 || PGCount == 36) { //Everything is fine with the PG. NbPGDetections = 0; } else { CEngLog::instance()->AddLogString(QString().sprintf("[Post-Détection]--> Compte PG invalide : PGCount = %d",PGCount),3); if(PGCount > 24) { NbPGDetections = 36 - PGCount; } else if(PGCount > 12) { NbPGDetections = 24 - PGCount; } else { NbPGDetections = 12 - PGCount; } } int alarms = NbPGDetections; if(alarms < 0) { alarms = -1 * alarms; } for(int i = 0; i < alarms; i++) { CZTDetectionData *NewDetection = new CZTDetectionData(); NewDetection->mDetectionID = DETECTION_PG_DETECTION; NewDetection->mTimeStamp = 0; NewDetection->mRank = ZT_DEFAULT_DETECTION_RANK; mZT1DetectionsLog.append(NewDetection); } } } //Analyze FN count if necessary if(mZTDetectionConfig->mZTDetectionConfig[DETECTION_FCT_FN].AnalysisActive == true) { if(FNCount == 6 || FNCount == 12 || FNCount == 18) { //Everything is fine with the FN. NbFNDetections = 0; } else { CEngLog::instance()->AddLogString(QString().sprintf("[Post-Détection]--> Compte FN invalide : FNCount = %d",FNCount),3); if(FNCount > 12) { NbFNDetections = 18 - FNCount; } else if(FNCount > 6) { NbFNDetections = 12 - FNCount; } else { NbFNDetections = 6 - FNCount; } } int alarms = NbFNDetections; if(alarms < 0) { alarms = -1 * alarms; } if(alarms != 0) { //Send two detections only (rank 1 & 18) when detecting FN errors while in V00 QString string; string.sprintf("[POST DETECTION]--> Déclenchement FN avec erreur de comptage (FNCount = %d). Envoi d'alarmes aux rangs 1 et 18.",FNCount); //CZTLog::instance()->AddBufferString("Déclenchement FN avec erreur de comptage. Envoi d'alarmes aux rangs 1 et 18.",true); CZTLog::instance()->AddBufferString(string,true); CZTDetectionData *NewDetection = new CZTDetectionData(); NewDetection->mDetectionID = DETECTION_FN_DETECTION; NewDetection->mTimeStamp = 0; NewDetection->mRank = 1; mZT1DetectionsLog.append(NewDetection); NewDetection = new CZTDetectionData(); NewDetection->mDetectionID = DETECTION_FN_DETECTION; NewDetection->mTimeStamp = 0; NewDetection->mRank = 18; mZT1DetectionsLog.append(NewDetection); } } if(mZT1DetectionsLog.size() != 0) { if(mZTDetectionConfig->mZTDetectionConfig[DETECTION_FCT_ZT1].AnalysisActive) { //If here, we had at least one detection. We must emit the V00 alarm. CZTDetectionData *NewDetection = new CZTDetectionData(); NewDetection->mDetectionID = DETECTION_MAGNETIC_SENSOR_COUNT; NewDetection->mTimeStamp = 0; NewDetection->mRank = ZT_DEFAULT_DETECTION_RANK; mZT1DetectionsLog.append(NewDetection); } } else { //If here, we did not detect other errors than mag. sensor count. //We can tolerate 2 miss if(mZTDetectionConfig->mZTDetectionConfig[DETECTION_FCT_ZT1].AnalysisActive) { int SensorCount = S1Count; if(SensorCount > S2Count) SensorCount = S2Count; //Use the least of the 2 counts... bool Error = false; if(S1Count > 36 || S2Count > 36) { //Counted more than 36 ranks on at least one sensor... Error = true; } if(SensorCount > 24 && SensorCount < 34) { //more than 2 miss for a 3 elements train Error = true; } else if(SensorCount > 12 && SensorCount < 22) { //more than 2 miss for a 2 elements train Error = true; } else if(SensorCount < 10) { //more than 2 miss for a 1 element train Error = true; } if(Error) { CZTDetectionData *NewDetection = new CZTDetectionData(); NewDetection->mDetectionID = DETECTION_MAGNETIC_SENSOR_COUNT; NewDetection->mTimeStamp = 0; NewDetection->mRank = ZT_DEFAULT_DETECTION_RANK; mZT1DetectionsLog.append(NewDetection); } else { QString string; string.sprintf("[POST DETECTION]--> Erreur de comptage ZT1 : [S1=%d] [S2=%d] essieux comptés (TK non émise au PCC car <= 2 essieux sans autre détection )",S1Count, S2Count); CZTLog::instance()->AddBufferString(string,true,true); mZT1Log.mZT1Flags.mIsProblematicPassage = 1; } } } } else//No magnetic sensors count error { //If we have more than 3 PG detections, check if they happened on consecutive ranks //if so, remove them from the list and emit a PEQ1 alarm instead. if(NbPGDetections >= 3 && mZT1DetectionsLog.size() >= 3) { //List the detections int DetectionIDs[1024/*NbPGDetections*/]; int index = 0; for(int i = 0; i < mZT1DetectionsLog.size(); i++) { if(mZT1DetectionsLog.at(i)->mDetectionID == DETECTION_PG_DETECTION) { DetectionIDs[index++] = i; } } //Now check if the ranks are consecutive. If so, remove the events from the list. if((mZT1DetectionsLog.at(DetectionIDs[0])->mRank+1 == mZT1DetectionsLog.at(DetectionIDs[1])->mRank) && (mZT1DetectionsLog.at(DetectionIDs[1])->mRank+1 == mZT1DetectionsLog.at(DetectionIDs[2])->mRank)) { //remove all PG detections. for(int i = NbPGDetections-1 ; i >= 0 ; i--) { delete mZT1DetectionsLog.at(DetectionIDs[i]); mZT1DetectionsLog.remove(DetectionIDs[i]); } CZTLog::instance()->AddBufferString("[POST DETECTION]--> Plus de 3 PG consécutifs détectés (TK non émise au PCC)",true,true); mZT1Log.mZT1Flags.mIsProblematicPassage = 1; } } //Check if the rank count is valid even without mag. sensor error unsigned int S1Count = 0, S2Count = 0; for(int i = 0; i < mZT1Log.mZT1LogData.size(); i++) { if(mZT1Log.mZT1LogData.at(i)->mZT1ThreadData != 0) { if(mZT1Log.mZT1LogData.at(i)->mZT1ThreadData->mS1Count > S1Count) { S1Count = mZT1Log.mZT1LogData.at(i)->mZT1ThreadData->mS1Count; } if(mZT1Log.mZT1LogData.at(i)->mZT1ThreadData->mS2Count > S2Count) { S2Count = mZT1Log.mZT1LogData.at(i)->mZT1ThreadData->mS2Count; } } } if((S1Count == 12 || S1Count == 24 || S1Count == 36) && (S2Count == 12 || S2Count == 24 || S2Count == 36)) { //Everything is fine, no sensor count error... } else { if(mZT1DetectionsLog.size() != 0) { //If here, we had at least one detection. We must emit the V00 alarm. CEngLog::instance()->AddLogString(QString().sprintf("[Post-Détection]--> Erreur de comptage sans flag en temps réel"),3); CZTDetectionData *NewDetection = new CZTDetectionData(); NewDetection->mDetectionID = DETECTION_MAGNETIC_SENSOR_COUNT; NewDetection->mTimeStamp = 0; NewDetection->mRank = ZT_DEFAULT_DETECTION_RANK; mZT1DetectionsLog.prepend(NewDetection); //Put the V00 alarm first (prepend) //Clear the detections rank of all the detections since it may not be valid. for(int i = 0; i < mZT1DetectionsLog.size(); i++) { mZT1DetectionsLog.at(i)->mRank = ZT_DEFAULT_DETECTION_RANK; } //JFM 20160112 V1.10 //If there was FN detection, replace it with two alarms at rank 1 and 18. bool FNDetection = false; int i = 0; while(i < mZT1DetectionsLog.size()) { if(mZT1DetectionsLog.at(i)->mDetectionID == DETECTION_FN_DETECTION) { CEngLog::instance()->AddLogString(QString().sprintf("[Post-Détection]--> Déclenchement FN détecté dans liste des alarmes"),3); FNDetection = true; delete mZT1DetectionsLog.at(i); mZT1DetectionsLog.remove(i); //remove this alarm } else { i++; } }; if(FNDetection == true) { CZTLog::instance()->AddBufferString("[Post-Détection]--> Déclenchement FN avec erreur de comptage. Envoi d'alarmes aux rangs 1 et 18.",true); CZTDetectionData *NewDetection = new CZTDetectionData(); NewDetection->mDetectionID = DETECTION_FN_DETECTION; NewDetection->mTimeStamp = 0; NewDetection->mRank = 1; mZT1DetectionsLog.append(NewDetection); NewDetection = new CZTDetectionData(); NewDetection->mDetectionID = DETECTION_FN_DETECTION; NewDetection->mTimeStamp = 0; NewDetection->mRank = 18; mZT1DetectionsLog.append(NewDetection); } } else { //If here, we did not detect other errors than mag. sensor count. //We can tolerate 2 miss unsigned int SensorCount = S1Count; if(SensorCount > S2Count) SensorCount = S2Count; //Use the least of the 2 counts... bool Error = false; if(S1Count > 36 || S2Count > 36) { //Counted more than 36 ranks... Error = true; } else if(SensorCount > 24 && SensorCount < 34) { //more than 2 miss for a 3 elements train Error = true; } else if(SensorCount > 12 && SensorCount < 22) { //more than 2 miss for a 2 elements train Error = true; } else if(SensorCount < 10) { //more than 2 miss for a 1 element train Error = true; } if(Error) { CZTDetectionData *NewDetection = new CZTDetectionData(); NewDetection->mDetectionID = DETECTION_MAGNETIC_SENSOR_COUNT; NewDetection->mTimeStamp = 0; NewDetection->mRank = ZT_DEFAULT_DETECTION_RANK; mZT1DetectionsLog.append(NewDetection); } else { QString string; string.sprintf("[POST DETECTION]--> Erreur de comptage ZT1 : [S1=%d] et [S2=%d] essieux comptés (TK non émise au PCC car <= 2 essieux sans autre détection )",S1Count, S2Count); CZTLog::instance()->AddBufferString(string,true,true); mZT1Log.mZT1Flags.mIsProblematicPassage =1; } } } } //Process detections and send TKs to PCC/PCM for(int i = 0; i < mZT1DetectionsLog.size(); i++) { mTKGenerator->ProcessDetectionsTK(mZT1DetectionsLog.at(i)); mNbTriggers++; QString str(""); if(mZT1DetectionsLog.at(i)->mDetectionID == DETECTION_FN_DETECTION) str.sprintf("[POST DETECTION]--> %s au bogie %d (rang %d ou %d)",CZTData::GetErrorString(mZT1DetectionsLog.at(i)->mDetectionID),mZT1DetectionsLog.at(i)->mRank,(mZT1DetectionsLog.at(i)->mRank*2)-1,mZT1DetectionsLog.at(i)->mRank*2); else str.sprintf("[POST DETECTION]--> %s au rang %d",CZTData::GetErrorString(mZT1DetectionsLog.at(i)->mDetectionID),mZT1DetectionsLog.at(i)->mRank); CZTLog::instance()->AddBufferString(str,true); } if(mZT1DetectionsLog.size() != 0 || CZTLog::instance()->IsWriteForced()) { CZTLog::instance()->WriteBufferToLog(); } else { CZTLog::instance()->ClearBufferString(); //2015-03-03 To avoid potention memory leak. Computer Crash problem resolution tentative... } mZTPagePTr->SetZTStatus(mNbPassages,mNbTriggers,mZT1ActiveStatus,mZT2ActiveStatus); return RET_POST_DETECTION_VALID; } unsigned int CZTStateMachine::ZT2StateMachine(unsigned int Event, unsigned int SubEvent) { Q_UNUSED(Event) Q_UNUSED(SubEvent) if(IsZT1Active() == false) { switch(mZT2State) { case ZT2_WAIT_FOR_CI_STATE: { if(mCIZT2Active) { if(mZTStationPtr->IsZT2CDVOccupied() == false) //the ZT2 CDV must be free. { mZT2State = ZT2_WAIT_FOR_TRAIN_STATE; } else { mZT2State = ZT2_WAIT_FOR_APPROACH_LIBERATION_STATE; } } break; } case ZT2_WAIT_FOR_APPROACH_LIBERATION_STATE: { if(mZTStationPtr->IsZT2ApproachCDVOccupied() == false) { mZT2State = ZT2_WAIT_FOR_CI_STATE; } break; } case ZT2_WAIT_FOR_TRAIN_STATE: { if(mCIZT2Active == false) { mZT2State = ZT2_WAIT_FOR_CI_STATE; } else if(mZTStationPtr->IsZT2ApproachCDVOccupied()) { DestroyZT2Log(); mEventsRefTimer.start(); mZTPagePTr->SetZT2ActivationSTate(true); mZT2ActiveStatus = SB_ZT_ACTIVE_STATUS; mZTPagePTr->SetZTStatus(mNbPassages,mNbTriggers,mZT1ActiveStatus,mZT2ActiveStatus); mZTPagePTr->ResetZT2Stats(); InsertZT2LogItem(); mZT2WorkerThread->UpdateDetectionConfig(mZTDetectionConfig); mTKGenerator->UpdateDetectionConfig(mZTDetectionConfig); mZT2SMThread->start(QThread::NormalPriority); mZT2PassageTimeLimitTimer.start(); mZT2State = ZT2_ANALYZE_TRAIN_STATE; CZTLog::instance()->ClearBufferString(); CZTLog::instance()->AddBufferString("ZT2 activée",true); } break; } case ZT2_ANALYZE_TRAIN_STATE: { if(!mZTStationPtr->IsZT2CDVOccupied() && !mZTStationPtr->IsZT2ApproachCDVOccupied()) //train quit the ZT2 cdv. { mZT2ActiveStatus = SB_ZT_INACTIVE_STATUS; mZTPagePTr->SetZTStatus(mNbPassages,mNbTriggers,mZT1ActiveStatus,mZT2ActiveStatus); //The train is leaving the ZT2 CDV. Stop the analysis thread. mZT2WorkerThread->TerminateAnalysis(); mZT2SMThread->quit(); InsertZT2LogItem(); CZTLog::instance()->AddBufferString("ZT2 désactivée",true); mZT2State = ZT2_POST_DETECTION_STATE; } if(mZT2PassageTimeLimitTimer.elapsed() > ZT2_MAX_PASSAGE_DELAY ) { mZT2ActiveStatus = SB_ZT_INACTIVE_STATUS; mZTPagePTr->SetZTStatus(mNbPassages,mNbTriggers,mZT1ActiveStatus,mZT2ActiveStatus); //Stop the analysis thread. mZT2WorkerThread->TerminateAnalysis(); mZT2SMThread->quit(); DestroyZT2Log(); CZTLog::instance()->AddLogString("Délai de passage expiré: Analyse ZT2 annulée. Attente de libération du CDV",true); mZT2State = ZT2_WAIT_FOR_CDV_LIBERATION_STATE; } break; } case ZT2_WAIT_FOR_CDV_LIBERATION_STATE: { if(!mZTStationPtr->IsZT2CDVOccupied() && !mZTStationPtr->IsZT2ApproachCDVOccupied()) { CZTLog::instance()->AddLogString("CDV ZT2 Libéré. ZT2 prête",true); mZT2State = ZT2_WAIT_FOR_CI_STATE; } break; } case ZT2_POST_DETECTION_STATE: { //InsertZT2LogItem(); //JFM 2014-06-11 Not sure if necessary... AnalyzeZT2PostDetection(); SaveZT2EventsLog(&mZT2Log); mTKGenerator->BeginTKEmission(); mZT2State = ZT2_WAIT_FOR_CI_STATE; if(mFSSyncTimer.elapsed() > FILESYSTEM_FORCED_SYNC_TIMEOUT) { mTimeToForceSyncFS = true; } break; } default: { break; } } } return RET_OK; } unsigned int CZTStateMachine::AnalyzeZT2PostDetection() { bool PEQ2 = false; qint64 PEQ2Timestamp = 0; mZT2Log.mZT2Flags.mIsProblematicPassage = 0; for(int i = 0; i < mZT2DetectionsLog.size(); i++) { if(mZT2DetectionsLog.at(i)->mDetectionID == DETECTION_PEQ2_DETECTION) { PEQ2 = true; PEQ2Timestamp = mZT2DetectionsLog.at(i)->mTimeStamp; } } //If we have a PEQ2, we remove all detections an leave only the PEQ2 one if(PEQ2 == true) { for(int i = 0; i < mZT2DetectionsLog.size(); i++) { delete mZT2DetectionsLog.at(i); } mZT2DetectionsLog.clear(); CZTDetectionData *NewDetection = new CZTDetectionData(); NewDetection->mDetectionID = DETECTION_PEQ2_DETECTION; NewDetection->mTimeStamp = PEQ2Timestamp; NewDetection->mRank = ZT_DEFAULT_DETECTION_RANK; mZT2DetectionsLog.prepend(NewDetection); } else { //Check for magnetic sensor count error. int S1Count = 0; for(int i = 0; i < mZT2Log.mZT2LogData.size(); i++) { if(mZT2Log.mZT2LogData.at(i)->mZT2ThreadData != 0) { if((int)mZT2Log.mZT2LogData.at(i)->mZT2ThreadData->mS1Count > S1Count) { S1Count = mZT2Log.mZT2LogData.at(i)->mZT2ThreadData->mS1Count; } } } if(S1Count == 12 || S1Count == 24 || S1Count == 36) { //Everything is fine ! } else { //We had a sensor count error. Emit V02 only if we also have a PP detection. if(mZT2DetectionsLog.size() == 0) { //No PP detection. QString string(""); string.sprintf("[POST DETECTION]--> Erreur de comptage ZT2 : %d essieux comptés (TK non émise au PCC car pas de déclenchement PP)",S1Count); CZTLog::instance()->AddBufferString(string,true,true); mZT2Log.mZT2Flags.mIsProblematicPassage = 1; } else { //There has been a PP detection. Add V02 alarm to the list (at the beginning) CZTDetectionData *NewDetection = new CZTDetectionData(); NewDetection->mDetectionID = DETECTION_ZT2_MAGNETIC_SENSOR_COUNT; NewDetection->mTimeStamp = 0; NewDetection->mRank = ZT_DEFAULT_DETECTION_RANK; mZT2DetectionsLog.append(NewDetection); //Clear the rank value for the other detections since it may not be valid for(int i = 0; i < mZT2DetectionsLog.size(); i++) { mZT2DetectionsLog.at(i)->mRank = ZT_DEFAULT_DETECTION_RANK; } } } } //Process detections and send TKs to PCC/PCM for(int i = 0; i < mZT2DetectionsLog.size(); i++) { mTKGenerator->ProcessDetectionsTK(mZT2DetectionsLog.at(i)); mNbTriggers++; QString str(""); str.sprintf("[POST DETECTION]--> %s au rang %d",CZTData::GetErrorString(mZT2DetectionsLog.at(i)->mDetectionID),mZT2DetectionsLog.at(i)->mRank); // CZTLog::instance()->AddLogString(str,true); CZTLog::instance()->AddBufferString(str,true); } if(mZT2DetectionsLog.size() != 0 || CZTLog::instance()->IsWriteForced()) { CZTLog::instance()->WriteBufferToLog(); } else { CZTLog::instance()->ClearBufferString(); //2015-03-03 To avoid potention memory leak. Computer Crash problem resolution tentative... } //mZTPagePTr->SetZTStatus(mNbPassages,mNbTriggers,mZT1Active,mZT2Active); mZTPagePTr->SetZTStatus(mNbPassages,mNbTriggers,mZT1ActiveStatus,mZT2ActiveStatus); return RET_OK; } bool CZTStateMachine::IsZT1Active() { if(mZT1State == ZT1_TRAIN_ON_APPROACH_CDV_STATE || mZT1State == ZT1_ANALYZE_TRAIN_STATE) { return true; } return false; } bool CZTStateMachine::IsZT2Active() { if(mZT2State == ZT2_WAIT_FOR_CI_STATE || mZT2State == ZT2_WAIT_FOR_TRAIN_STATE) { return false; } return true; } void CZTStateMachine::BindPointers(CStation *ptr,CInputModule *InputModule,COutputModule *OutputModule,CZTPage *ZTPagePTr,CPCIIOMgr *PCIIOPtr,CAbstractLazerProbe *PGIntProbePtr, CAbstractLazerProbe *PGExtProbePTr,CLogMgr *LogMgr,CTKTransportInterface *TKTransport,CZTSimulator *ZTSimPtr,CAnalogInputModule *DataQInterface) { Q_UNUSED(OutputModule) mZTStationPtr = ptr; mSDFAnalogMonitorInterface = DataQInterface; mInputModule = InputModule; mZTPagePTr = ZTPagePTr; mZtSimPtr = ZTSimPtr; mZTInputMasks = mZTStationPtr->GetInputMasks(); mPCIIOPtr = PCIIOPtr; mPGExtProbePtr = PGExtProbePTr; mPGIntProbePtr = PGIntProbePtr; mLogMgr = LogMgr; mZT1WorkerThread->Init(PCIIOPtr,mZTInputMasks,mPGExtProbePtr,mPGIntProbePtr,&mEventsRefTimer,mSDFAnalogMonitorInterface); mZT2WorkerThread->Init(PCIIOPtr,mZTInputMasks,&mEventsRefTimer); //mTKGenerator->BindPointers(mZTStationPtr->GetOutputMasks(),OutputModule); //mTKGenerator->BindTransportInterface(TKTransport); mTKGenerator = TKTransport; } void CZTStateMachine::BindCCRepoPtr(CModbusRepository *RepoPtr) { mCCModbusRepo = RepoPtr; } unsigned int CZTStateMachine::SetPGTreshold(qint32 PGTreshold) { mZT1WorkerThread->SetPGTreshold(PGTreshold); return RET_OK; } void CZTStateMachine::ResetNbTriggers() { mNbTriggers = 0; mZTPagePTr->SetZTStatus(mNbPassages,mNbTriggers,mZT1ActiveStatus,mZT2ActiveStatus); } void CZTStateMachine::ResetNbPassages() { mNbPassages = 0; mZTPagePTr->SetZTStatus(mNbPassages,mNbTriggers,mZT1ActiveStatus,mZT2ActiveStatus); } void CZTStateMachine::ZT1StateChanged(CZT1ThreadData *ZT1DataPtr,bool ProbesOnly,int SDF) { //We want to limit the sampling rate in the log file //BUT we want to log EVERY signal transition, except lazer probes (which sample at 1Khz). //JFM 2016-05-31 //Add this to avoid having queued signals processed after the S.M. finished, //causing data corruption in the train file. if(IsZT1Active() == false) return; if(ProbesOnly == true ) { //JFM 20140821 if(mLogDelay != 0) { if(mZT1LogDelayTimer.elapsed() < mLogDelay) { delete ZT1DataPtr; return; } } mZTPagePTr->SetZT1Data(ZT1DataPtr); //update display with the new data. } else { mZTPagePTr->SetZT1Data(ZT1DataPtr,true); //force update display with the new data. } InsertZT1LogItem(ZT1DataPtr,SDF); mZT1LogDelayTimer.start(); //qDebug("TimeStamp: %f",(float)ZT1DataPtr->mTimeStamp/1000000000); } void CZTStateMachine::ZT2StateChanged(CZT2ThreadData *ZT2DataPtr) { mZTPagePTr->SetZT2Data(ZT2DataPtr); InsertZT2LogItem(ZT2DataPtr); } void CZTStateMachine::SetZT2Presence(bool Presence) { mZT2Present = Presence; } void CZTStateMachine::ZT1NewDetection(CZTDetectionData *NewDetection) { mZT1DetectionsLog.append(NewDetection); QString str(""); if(NewDetection->mDetectionID == DETECTION_FN_DETECTION) str.sprintf("%s au bogie %d (rang %d ou %d)",CZTData::GetErrorString(NewDetection->mDetectionID),NewDetection->mRank,(NewDetection->mRank*2)-1,NewDetection->mRank*2); else str.sprintf("%s au rang %d",CZTData::GetErrorString(NewDetection->mDetectionID),NewDetection->mRank); // CZTLog::instance()->AddLogString(str,true); CZTLog::instance()->AddBufferString(str,true); } void CZTStateMachine::ZT2NewDetection(CZTDetectionData *NewDetection) { // mNbTriggers++; mZT2DetectionsLog.append(NewDetection); /* mZTPagePTr->SetZTStatus(mNbPassages,mNbTriggers,mZT1Active,mZT2Active); mTKGenerator->ProcessDetectionsTK(NewDetection); QString str("");*/ QString str(""); str.sprintf("%s au rang %d",CZTData::GetErrorString(NewDetection->mDetectionID),NewDetection->mRank); // CZTLog::instance()->AddLogString(str,true); CZTLog::instance()->AddBufferString(str,true); } unsigned int CZTStateMachine::DestroyZT1Log() { for(int i = 0; i < mZT1Log.mZT1LogData.size(); i++) { delete mZT1Log.mZT1LogData.at(i); } //qDeleteAll(mZT1Log.mZT1LogData); mZT1Log.mZT1LogData.clear(); // mZT1Log.mZT1LogData.squeeze(); ClearZT1DetectionsList(); // for(int i = 0; i < mZT1DetectionsLog.size(); i++) // { // delete mZT1DetectionsLog.at(i); // } // mZT1DetectionsLog.clear(); mZT1Log.mZT1Flags.mExtPGOffset = 0; mZT1Log.mZT1Flags.mIntPGOffset = 0; mZT1Log.mZT1Flags.mPGCalibrationON = false; mZT1Log.mZT1Flags.mPGTresholdValue = 0; mZT1Log.mZT1Flags.mAnalogTracePresent = (mSDFAnalogMonitorInterface != 0); mZT1Log.mZT1Flags.mIsProblematicPassage = 0; mZT1PEQType = PEQ1_UNKNOWN_TYPE; return RET_OK; } unsigned int CZTStateMachine::InsertZT1LogItem(CZT1ThreadData *ThreadData,int SDFReading) { CZT1LogData *NewItem = new CZT1LogData(ThreadData); if(ThreadData == 0) //Avoid accessing mEventsRefTimer while thread is running ! NewItem->mTimestamp = mEventsRefTimer.nsecsElapsed(); else NewItem->mTimestamp = ThreadData->mTimeStamp; NewItem->mDateTime = QDateTime::currentDateTime(); NewItem->mCDVApproach_ZT1 = mZTStationPtr->IsZT1ApproachCDVOccupied(); NewItem->mCDVARM_ZT1 = mZTStationPtr->IsZT1CDVOccupied(); NewItem->mCIZT1 = (unsigned int)mCIZT1Active; NewItem->mAnalogData = SDFReading; mZT1Log.mZT1LogData.append(NewItem); return RET_OK; } unsigned int CZTStateMachine::InsertZT2LogItem(CZT2ThreadData *ThreadData) { CZT2LogData *NewItem = new CZT2LogData(ThreadData); if(ThreadData == 0) //Avoid accessing mEventsRefTimer while thread is running ! NewItem->mTimestamp = mEventsRefTimer.nsecsElapsed(); else NewItem->mTimestamp = ThreadData->mTimeStamp; NewItem->mDateTime = QDateTime::currentDateTime(); NewItem->mCDVARM_ZT2 = mZTStationPtr->IsZT2CDVOccupied(); NewItem->mCDVApproach_ZT2 = mZTStationPtr->IsZT2ApproachCDVOccupied(); NewItem->mCIZT2 = (unsigned int)mCIZT2Active; mZT2Log.mZT2LogData.append(NewItem); return RET_OK; } unsigned int CZTStateMachine::DestroyZT2Log() { mZT2Log.mZT2Flags.mIsProblematicPassage = 0; for(int i = 0; i < mZT2Log.mZT2LogData.size(); i++) { delete mZT2Log.mZT2LogData.at(i); } mZT2Log.mZT2LogData.clear(); for(int i = 0; i < mZT2DetectionsLog.size(); i++) { delete mZT2DetectionsLog.at(i); } mZT2DetectionsLog.clear(); return RET_OK; } unsigned int CZTStateMachine::DestroyCalibrationData() { for(unsigned int j = 0; j < ZT_SM_MAX_NB_PG_CALIB_PASSAGES; j++) { for(int i = 0; i < mZTPGCalibrationData[j].size(); i++) { delete mZTPGCalibrationData[j].at(i); } mZTPGCalibrationData[j].clear(); } return RET_OK; } unsigned int CZTStateMachine::SaveZT1EventsLog(CZT1Log *Log) { QString FileName1 = "./Trains/LOGZT1_"; FileName1 += QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss-zzz"); QString FileName = FileName1 + ".bin"; qDebug("%s",FileName.toAscii().data()); CTrainLogFileMgr::instance()->SaveTrainLog(FileName,Log,&mZT1DetectionsLog,mZTStationPtr->GetStationTextualName()); mLogMgr->ParseNewLog(FileName); if(mAutoExportZT1CSV) { FileName = FileName1 + ".csv"; CTrainLogFileMgr::instance()->SaveCSVFile(FileName,Log,&mZT1DetectionsLog,mZTStationPtr->GetStationTextualName()); } DestroyZT1Log(); emit NewTrainLogSaved(); return RET_OK; } unsigned int CZTStateMachine::SaveZT2EventsLog(CZT2Log *Log) { QString FileName1 = "./Trains/LOGZT2_"; FileName1 += QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss-zzz"); QString FileName = FileName1 + ".bin"; qDebug("%s",FileName.toAscii().data()); CTrainLogFileMgr::instance()->SaveTrainLog(FileName,Log,&mZT2DetectionsLog,mZTStationPtr->GetStationTextualName()); mLogMgr->ParseNewLog(FileName); if(mAutoExportZT2CSV) { FileName = FileName1 + ".csv"; CTrainLogFileMgr::instance()->SaveCSVFile(FileName,Log,&mZT2DetectionsLog,mZTStationPtr->GetStationTextualName()); } DestroyZT2Log(); emit NewTrainLogSaved(); return RET_OK; } bool CZTStateMachine::EnterPGCalibrationMode(int NbPassages) { if(IsZT1Active()) return false; if(mZT1WorkerThread->SetPGCalibration(true) == false) return false; mIsPGCalibON = true; mCalibrationPassagesCount = 0; mPGNbTotalPassages = NbPassages; DestroyCalibrationData(); return true; } bool CZTStateMachine::QuitPGCalibrationMode() { if(IsZT1Active()) return false; if(mZT1WorkerThread->SetPGCalibration(false) == false) return false; mIsPGCalibON = false; mZT1WorkerThread->SetPGCalibration(false); DestroyCalibrationData(); return true; } void CZTStateMachine::NewPGCalibrationData(CZTPGCalibrationData *NewData) { // qDebug("NewData %d | %d",NewData->mPGExtValue,NewData->mPGIntValue); mZTPGCalibrationData[mCalibrationPassagesCount].append(NewData); } unsigned int CZTStateMachine::ComputePGCalibration() { //Pour déterminer le seuil de détection du pneu de guidage nous //appliquons la recette suivante. //Pour chaque pneu, on multiplie les valeurs intérieur et extérieur //Ensuite on fait moyenne de ce résultat pour tous les frotteurs d'un même train //On multiplie cette valeur par un facteur déterminé empiriquement (0.35) //On fait ensuite la moyenne de ce résultat pour tous les trains //La valeur que lon recherche correspond alors à la racine carrée de cette valeur double Treshold = 0.0; for(unsigned int i = 0; i < mPGNbTotalPassages; i++) { double Temp = 0; for(int sample = 0; sample < mZTPGCalibrationData[i].size(); sample++) { Temp += (mZTPGCalibrationData[i].at(sample)->mPGExtValue * mZTPGCalibrationData[i].at(sample)->mPGIntValue); //Multiply int and ext samples } Temp /= mZTPGCalibrationData[i].size(); //Compute the mean value for this train. Temp *= 0.35; //multiply by the scaling factor. Treshold += Temp; } Treshold /= mPGNbTotalPassages; //Compute the mean value for all the trains. Treshold = sqrt(Treshold); //Compute the square root, and we have the treshold value. int PGTreshold = (int)Treshold; qDebug("Calibration result: %d",PGTreshold); DestroyCalibrationData(); emit PGCalibrationFinished(PGTreshold); return RET_OK; } void CZTStateMachine::SetLogResolution(bool HighResON) { if(HighResON == true) { mLogDelay = 0; //Log each data sample. } else { mLogDelay = ZT_SM_DEFAULT_LOG_DELAY; } } void CZTStateMachine::ZT1NewFlag(int FlagID, CZT1FlagsData *FlagData) { switch(FlagID) { case ZT1_INT_PG_OFFSET_FLAG_ID: { mZT1Log.mZT1Flags.mIntPGOffset = FlagData->mIntPGOffset; break; } case ZT1_EXT_PG_OFFSET_FLAG_ID: { mZT1Log.mZT1Flags.mExtPGOffset = FlagData->mExtPGOffset; break; } case ZT1_PG_TRESHOLD_VALUE_FLAG_ID: { mZT1Log.mZT1Flags.mPGTresholdValue = FlagData->mPGTresholdValue; break; } case ZT1_PG_CALIB_ON_FLAG_ID: { mZT1Log.mZT1Flags.mPGCalibrationON = FlagData->mPGCalibrationON; break; } case ZT1_PEQ_TYPE_FLAG_ID: { mZT1PEQType = FlagData->mPEQ1Type; break; } } delete FlagData; //We MUST delete this pointer, because the thread will not. } unsigned int CZTStateMachine::SendTKToPCC(int DetectionID, int Rank) { CZTDetectionData *Detection = new CZTDetectionData(); Detection->mDetectionID = DetectionID; Detection->mRank = Rank; mTKGenerator->UpdateDetectionConfig(mZTDetectionConfig); mTKGenerator->ProcessDetectionsTK(Detection); delete Detection; mTKGenerator->BeginTKEmission(); return RET_OK; } unsigned int CZTStateMachine::EnterMaintenanceMode() { if(IsZT1Active() || IsZT2Active()) { return RET_ERROR; } if(mIsPGCalibON == true) { return RET_ERROR; } if(mTKGenerator->EnterMaintenance() == RET_ERROR) { return RET_ERROR; } mIsMaintenanceModeON = true; mZT1ActiveStatus = SB_ZT_DISABLED_STATUS; mZT2ActiveStatus = SB_ZT_DISABLED_STATUS; mZTPagePTr->SetZTStatus(mNbPassages,mNbTriggers,mZT1ActiveStatus,mZT2ActiveStatus); mMaintenancePPIZT1Latch = false; mMaintenancePPEZT1Latch = false; mMaintenancePPIZT2Latch = false; mMaintenancePPEZT2Latch = false; return RET_OK; } unsigned int CZTStateMachine::QuitMaintenanceMode() { mIsMaintenanceModeON = false; mTKGenerator->ExitMaintenance(); mZT1ActiveStatus = SB_ZT_INACTIVE_STATUS; mZT2ActiveStatus = SB_ZT_INACTIVE_STATUS; mZTPagePTr->SetZTStatus(mNbPassages,mNbTriggers,mZT1ActiveStatus,mZT2ActiveStatus); return RET_OK; } unsigned int CZTStateMachine::ClearMaintenanceCurrentTK() { return mTKGenerator->CancelMaintenanceCurrentTK(); } void CZTStateMachine::ClearZT1DetectionsList() { for(int i = 0; i < mZT1DetectionsLog.size(); i++) { delete mZT1DetectionsLog.at(i); } mZT1DetectionsLog.clear(); } void CZTStateMachine::AddLogStringFromThread(QString logstring) { CZTLog::instance()->AddLogString(logstring,true); } void CZTStateMachine::ModbusCCANUpdate() { // bool AN1State = false, AN2State = false; // AN1State = (mCCModbusRepo->GetSingleReg(MODBUS_CC_AN_BASE_REG_ADD) & MODBUS_CC_AN1_FLAG_MASK) != 0; // AN2State = (mCCModbusRepo->GetSingleReg(MODBUS_CC_AN_BASE_REG_ADD) & MODBUS_CC_AN2_FLAG_MASK) != 0; // mTKGenerator->SetInputStates(AN1State,mZTStationPtr->IsZT1AlarmAutoAcquireCDVOccupied(), // AN2State,mZTStationPtr->IsZT2AlarmAutoAcquireCDVOccupied()); // qDebug("Modbus changes: AN1 = %d, AN2 = %d",AN1State,AN2State); }