/*******************************************************************************
*                                                                              *
* Société de Transports de Montréal.                                    	   *
* 2012 - 2013                                                                        *
*                                                                              *
* Projet Zones Tests                                                           *
*                                                                              *
*                                                                              *
*                                                                              *
*******************************************************************************/
/*
	Description:
	Cette classe est un thread qui roule en parallèle au programme.  Elle est
	responsable de l'analyse en temps réel du passage d'un train.  Elle fait la
	lecture des entrées sur la carte PCI et détecte les déclenchements au fur
	et à mesure qu'un train chemine sur la ZT1
	
*/

/* ************************************************************************** */
/* Revision:
### YYYMMDD JFM
	Verision d'origine.
	
### YYYYMMDD Description du besoin ou du bug
	Description du changement.
 */

/* ************************************************************************** */

#include "GlobalDefine.h"
#include "ZT1AnalysisThread.h"
#include "PCIIOMgr.h"
#include "AbstractLazerProbe.h"
#include <QElapsedTimer>
#include "ZTconfigmgr.h"
#include <QDebug>


CZT1AnalysisThread::CZT1AnalysisThread()
{
	mLastInputs = 0;
    mLastPGIntValue = mLastPGExtValue = mLastSDFValue = 0;
	mZT1TrainState = ZT1_WAIT_FOR_S1_STATE;

	mPGIntHandle = 0;
	mPGExtHandle = 0;
	mPCIInputsHandle = 0;
    mSDFAnalogInterface = 0;
	mExitLoop = false;
    mZT1Analyzing = false;
	mPGCalibration = false;

}

unsigned int CZT1AnalysisThread::Init(CPCIIOMgr *PCIIOHandle,GenericInputMasks_t *InputMasks, CAbstractLazerProbe* PGExtHandle,CAbstractLazerProbe* PGIntHandle,QElapsedTimer *RefTimer,CAnalogInputModule *AnalogInterface)
{
	mPCIInputsHandle = PCIIOHandle;
	mInputMasksPtr = InputMasks;
	mPGIntHandle = PGIntHandle;
	mPGExtHandle = PGExtHandle;
	mReferenceTimer = RefTimer;
    mSDFAnalogInterface = AnalogInterface;

	return RET_OK;
}

void CZT1AnalysisThread::SetPGTreshold(qint32 PGTreshold)
{
	mMutex.lock();
		mPGTreshold = PGTreshold;
	mMutex.unlock();
}

bool CZT1AnalysisThread::SetPGCalibration(bool CalibON)
{
	mMutex.lock();
		if(mZT1Analyzing)
		{
			mMutex.unlock();
			return false;
		}
		mPGCalibration = CalibON;
	mMutex.unlock();

	return true;
}

void CZT1AnalysisThread::AnalyzeZT1Train()
{

 //   qDebug("ZT1 Thread started!");
	mExitLoop = false;
    mZT1Analyzing = true;
	mPEQDetectionLatch = false;


	mZT1TrainState = ZT1_PRE_DETECTION_STATE;
	unsigned int PCIInputs = 0;
	bool Run = true;
	QElapsedTimer TrainSpeedTimer1,TrainSpeedTimer2,AcquisitionTimer;

	AcquisitionTimer.start();

	//inputs
	unsigned int S1 = 0, S2 = 0, Pint = 0, Pext = 0, FN = 0;
	qint32 PGint,PGExt;
	int SDFAnalog = 0;


	//Train analysis variables
    float TrainSpeed = 0;
	unsigned int Bogie = 0;
	unsigned int Rank = 0;
	unsigned int CountS1 = 0;
	unsigned int CountS2 = 0;
	unsigned int CountFN = 0;
	unsigned int TrainType = TRAIN_TYPE_UNKNOWN;
	mMutex.lock();
		qint32 PGValueTreshold = mPGTreshold;
		bool PGCalibration = mPGCalibration;
	mMutex.unlock();

    mLastInputs = 0;
    mLastSDFValue = 0;


	bool FNDetected = false;
	bool PPIDetected = false;
	bool PPEDetected = false;
	bool PGActive = false;

	bool LazerProbesTransitOnly = false;

	qint32 PGIOffset,PGEOffset;
    qint32 Quadra;
	qint32 PGICalibValue = 0, PGECalibValue = 0;

	PGValueTreshold *= PGValueTreshold;	//use square value...
    PGIOffset = mPGIntHandle->GetLastData();
    PGEOffset = mPGExtHandle->GetLastData();

	CZT1FlagsData *Flag = new CZT1FlagsData();
	Flag->mIntPGOffset = PGIOffset;
	emit NewZT1Flag(ZT1_INT_PG_OFFSET_FLAG_ID,Flag);

	Flag = new CZT1FlagsData();	//the state machine deletes the pointer, we must create a new one.
	Flag->mExtPGOffset = PGEOffset;
	emit NewZT1Flag(ZT1_EXT_PG_OFFSET_FLAG_ID,Flag);

	Flag = new CZT1FlagsData();	//the state machine deletes the pointer, we must create a new one.
	Flag->mPGTresholdValue = PGValueTreshold;
	emit NewZT1Flag(ZT1_PG_TRESHOLD_VALUE_FLAG_ID,Flag);

	while(Run == true)
	{
		{
			AcquisitionTimer.start();

			PCIInputs = mPCIInputsHandle->GetInputs();

			PGint = mPGIntHandle->GetLastData();
			PGExt = mPGExtHandle->GetLastData();
            if(mSDFAnalogInterface != 0)
				mSDFAnalogInterface->GetAnalogInput(0,&SDFAnalog);

			if(PCIInputs != mLastInputs)
			{
				LazerProbesTransitOnly = false;
			}
			else
			{
				LazerProbesTransitOnly = true;
			}

			if(PCIInputs != mLastInputs ||
			   PGint != mLastPGIntValue ||
               PGExt != mLastPGExtValue ||
			   SDFAnalog != mLastSDFValue     )
			{
				//Extract useful flags

				S1 = ((PCIInputs & mInputMasksPtr->InputZT1S1Mask)   != 0);
				S2 = ((PCIInputs & mInputMasksPtr->InputZT1S2Mask)   != 0);
				Pint = ((PCIInputs & mInputMasksPtr->InputZT1PIMask) == 0);	//PP are active low
				Pext = ((PCIInputs & mInputMasksPtr->InputZT1PEMask) == 0);
				FN = ((PCIInputs & mInputMasksPtr->InputZT1FNMask)   == 0);   //FN is active low

				switch(mZT1TrainState)
				{
					case ZT1_PRE_DETECTION_STATE:	//Get in this state only once at the beginning.
					{
						//Pre-detection : Check if SDF is not active.
						if(FN == 1 || Pint == 1 || Pext == 1)
						{
							RegisterDetection(DETECTION_PEQ1_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
							if(FN == 1)
							{
                                emit AddLogString(QString("Panne équipement ZT1: Pré détection Frotteur négatif = 1"));
                                CZT1FlagsData *Flag = new CZT1FlagsData();
                                Flag->mPEQ1Type = PEQ1_FN_PREDETECTION_TYPE;
                                emit NewZT1Flag(ZT1_PEQ_TYPE_FLAG_ID,Flag);
							}
							if(Pint == 1)
							{
								emit AddLogString(QString("Panne équipement ZT1: Pré détection Pneu porteur intérieur = 1"));
                                CZT1FlagsData *Flag = new CZT1FlagsData();
                                Flag->mPEQ1Type = PEQ1_PINT_PREDETECTION_TYPE;
                                emit NewZT1Flag(ZT1_PEQ_TYPE_FLAG_ID,Flag);
							}
							if(Pext == 1)
							{
								emit AddLogString(QString("Panne équipement ZT1: Pré détection Pneu porteur extérieur = 1"));
                                CZT1FlagsData *Flag = new CZT1FlagsData();
                                Flag->mPEQ1Type = PEQ1_PEXT_PREDETECTION_TYPE;
                                emit NewZT1Flag(ZT1_PEQ_TYPE_FLAG_ID,Flag);
							}
						}
						if(S1 == 1 || S2 == 1)
						{
							RegisterDetection(DETECTION_PEQ1_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
							RegisterDetection(DETECTION_MAGNETIC_SENSOR_COUNT,Rank,mReferenceTimer->nsecsElapsed());
							mZT1TrainState = ZT1_POST_ANALYSIS_MODE_STATE;
							if(S1 == 1)
							{
								emit AddLogString(QString("Panne équipement ZT1: Pré détection S1 = 1"));
                                CZT1FlagsData *Flag = new CZT1FlagsData();
                                Flag->mPEQ1Type = PEQ1_MAG_SENSOR_S1_PREDETECTION_TYPE;
                                emit NewZT1Flag(ZT1_PEQ_TYPE_FLAG_ID,Flag);
							}
							if(S2 == 1)
							{
								emit AddLogString(QString("Panne équipement ZT1: Pré détection S2 = 1"));
                                CZT1FlagsData *Flag = new CZT1FlagsData();
                                Flag->mPEQ1Type = PEQ1_MAG_SENSOR_S2_PREDETECTION_TYPE;
                                emit NewZT1Flag(ZT1_PEQ_TYPE_FLAG_ID,Flag);
							}
						}
						if(mPGIntHandle->IsProbeAlive() == false)
						{
							RegisterDetection(DETECTION_PEQ1_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
							emit AddLogString(QString("Panne équipement ZT1: Pré détection Sonde lazer intérieure défectueuse"));
                            CZT1FlagsData *Flag = new CZT1FlagsData();
                            Flag->mPEQ1Type = PEQ1_LAZER_SENSOR_INT_PREDETECTION_TYPE;
                            emit NewZT1Flag(ZT1_PEQ_TYPE_FLAG_ID,Flag);
						}
						if(mPGExtHandle->IsProbeAlive() == false)
						{
							RegisterDetection(DETECTION_PEQ1_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
							emit AddLogString(QString("Panne équipement ZT1: Pré détection Sonde lazer extérieure défectueuse"));
                            CZT1FlagsData *Flag = new CZT1FlagsData();
                            Flag->mPEQ1Type = PEQ1_LAZER_SENSOR_EXT_PREDETECTION_TYPE;
                            emit NewZT1Flag(ZT1_PEQ_TYPE_FLAG_ID,Flag);
						}

						mZT1TrainState = ZT1_WAIT_FOR_S1_STATE;
						break;
					}
					case ZT1_WAIT_FOR_S1_STATE:	//1
					{
						FNDetected = false;
						PPEDetected = false;
						PPIDetected = false;
						PGActive = false;

						if(FN == 1)// The SDF should not detect any FN at this step (no bogie on the ZT).
						{
                            if(mPEQDetectionLatch == false)
                            {
                           //     emit AddLogString(QString("Panne équipement ZT1: SDF <collé> à 1"));
                                CZT1FlagsData *Flag = new CZT1FlagsData();
                                Flag->mPEQ1Type = PEQ1_FN_STUCK_LOW_TYPE;
                                emit NewZT1Flag(ZT1_PEQ_TYPE_FLAG_ID,Flag);
                            }
							RegisterDetection(DETECTION_PEQ1_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}

						if(S1 == 0 && S2 == 0)
						{
							break;
						}
						else if(S1 == 1 && S2 == 0)
						{
							Bogie++;
							Rank++;
							CountS1++;
							if(PGCalibration)
							{
								PGICalibValue = PGIOffset;
								PGECalibValue = PGEOffset;
							}

							TrainSpeedTimer1.start();
							mZT1TrainState = ZT1_S1_ACTIVE_STATE;
						}
						else
						{
							RegisterDetection(DETECTION_MAGNETIC_SENSOR_COUNT,Rank,mReferenceTimer->nsecsElapsed());
							mZT1TrainState = ZT1_POST_ANALYSIS_MODE_STATE;
						}
						break;
					}
					case ZT1_S1_ACTIVE_STATE:	//2
					{
						if(Pint == 1 && PPIDetected == false)
						{
							PPIDetected = true;
                            RegisterDetection(DETECTION_PPI_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
                        if(Pext == 1 && PPEDetected == false)
						{
							PPEDetected = true;
                            RegisterDetection(DETECTION_PPE_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
						if(FN == 1)
						{
							FNDetected = true;
						}

						if(PGCalibration)
						{

                            qint32 Value = PGint - PGIOffset;
                            if(Value < PGICalibValue)
                                PGICalibValue = Value;

                            Value = PGExt - PGEOffset;
                            if(Value < PGECalibValue)
                                PGECalibValue = Value;
						}
						else if(PGActive == false)
						{
							//Compute and verify if the PG is detected.
                            Quadra = ((PGint - PGIOffset) * (PGExt - PGEOffset));

                            if(Quadra > PGValueTreshold)
							{
								//The PG has been detected, stop sampling...
								PGActive = true;
							}
						}

						if(S1 == 1 && S2 == 0)
						{
							break;
						}
						else if(S1 == 0 && S2 == 0)
						{
							if(PGCalibration)
							{
								CZTPGCalibrationData *Data = new CZTPGCalibrationData();
								Data->mTimestamp = mReferenceTimer->nsecsElapsed();
								Data->mPGExtValue = PGECalibValue;
								Data->mPGIntValue = PGICalibValue;

                                emit NewPGCalibrationData(Data);
								PGICalibValue = PGIOffset;
								PGECalibValue = PGEOffset;
							}
							else if(PGActive == false)	//The PG has not been detected...
							{
								RegisterDetection(DETECTION_PG_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
							}
							PGActive = false;


							if(TrainType == TRAIN_TYPE_UNKNOWN)			//First bogie, the train type is unknown
							{
								mZT1TrainState = ZT1_S1_TRANSIT_STATE;	//goto state 3 to determine train type...
							}
							else if(TrainType == TRAIN_TYPE_MR63_MR73)
							{
								mZT1TrainState = ZT1_S1_TANSIT_MR_STATE;	//goto state 3_MR
							}
							else if(TrainType == TRAIN_TYPE_MPM10)
							{
								mZT1TrainState = ZT1_S1_TRANSIT_MPM_STATE;	//goto state3_MPM
							}
							else
								CEngLog::instance()->AddLogString("LOGIC ERROR IN ZT1AnalysysThread.CPP - ZT1_ACTIVE_STATE: invalid train type",1);
						}
						else
						{
							RegisterDetection(DETECTION_MAGNETIC_SENSOR_COUNT,Rank,mReferenceTimer->nsecsElapsed());
							mZT1TrainState = ZT1_POST_ANALYSIS_MODE_STATE;
						}
						break;
					}
					case ZT1_S1_TRANSIT_STATE:	//3
					{
                        if(Pint == 1 && PPIDetected == false)
						{
							PPIDetected = true;
                            RegisterDetection(DETECTION_PPI_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
                        if(Pext == 1 && PPEDetected == false)
						{
							PPEDetected = true;
                            RegisterDetection(DETECTION_PPE_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
						if(FN == 1)
						{
							FNDetected = true;
						}


						if(S1 == 0 && S2 == 0)
						{
							break;
						}
						else if(S1 == 1 && S2 == 0)
						{
							CountS1++;
							TrainType = TRAIN_TYPE_MR63_MR73;
							TrainSpeed = (MR_BOGIE_LENGTH / TrainSpeedTimer1.elapsed()) * 1000;	// m/s
							TrainSpeed *= 2.23694;	// Mph
							mZT1TrainState = ZT1_MR_S1_SECOND_PULSE_STATE;	//goto state 4
						}
						else if(S1 == 0 && S2 == 1)
						{
							CountS2++;
							TrainType = TRAIN_TYPE_MPM10;
							TrainSpeedTimer2.start();
							Rank++;
							PPEDetected = false;
							PPIDetected = false;
							mZT1TrainState = ZT1_MPM10_S2_ACTIVE_STATE;	//goto state 8
						}
						else
						{
							RegisterDetection(DETECTION_MAGNETIC_SENSOR_COUNT,Rank,mReferenceTimer->nsecsElapsed());
							mZT1TrainState = ZT1_POST_ANALYSIS_MODE_STATE;
						}
						break;
					}
					case ZT1_S1_TANSIT_MR_STATE:	//3_MR
					{
                        if(Pint == 1 && PPIDetected == false)
						{
							PPIDetected = true;
                            RegisterDetection(DETECTION_PPI_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
                        if(Pext == 1 && PPEDetected == false)
						{
							PPEDetected = true;
                            RegisterDetection(DETECTION_PPE_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
						if(FN == 1)
						{
							FNDetected = true;
						}


						if(S1 == 0 && S2 == 0)
						{
							break;
						}
						else if(S1 == 1 && S2 == 0)
						{
							CountS1++;
							TrainSpeed = (MR_BOGIE_LENGTH / TrainSpeedTimer1.elapsed()) * 1000;	// m/s
							TrainSpeed *= 2.23694;	// Mph
							mZT1TrainState = ZT1_MR_S1_SECOND_PULSE_STATE;	//goto state 4
						}
						else
						{
							RegisterDetection(DETECTION_MAGNETIC_SENSOR_COUNT,Rank,mReferenceTimer->nsecsElapsed());
							mZT1TrainState = ZT1_POST_ANALYSIS_MODE_STATE;
						}
						break;
					}
					case ZT1_S1_TRANSIT_MPM_STATE:	//3_MPM
					{
                        if(Pint == 1 && PPIDetected == false)
						{
							PPIDetected = true;
                            RegisterDetection(DETECTION_PPI_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
                        if(Pext == 1 && PPEDetected == false)
						{
							PPEDetected = true;
                            RegisterDetection(DETECTION_PPE_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
						if(FN == 1)
						{
							FNDetected = true;
						}


						if(S1 == 0 && S2 == 0)
						{
							break;
						}
						else if(S1 == 0 && S2 == 1)
						{
							CountS2++;
							TrainSpeedTimer2.start();
							Rank++;
							PPEDetected = false;
							PPIDetected = false;
							mZT1TrainState = ZT1_MPM10_S2_ACTIVE_STATE;	//goto state 8
						}
						else
						{
							RegisterDetection(DETECTION_MAGNETIC_SENSOR_COUNT,Rank,mReferenceTimer->nsecsElapsed());
							mZT1TrainState = ZT1_POST_ANALYSIS_MODE_STATE;
						}
						break;
					}
					case ZT1_MR_S1_SECOND_PULSE_STATE:	//4
					{
                        if(Pint == 1 && PPIDetected == false)
						{
							PPIDetected = true;
                            RegisterDetection(DETECTION_PPI_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
                        if(Pext == 1 && PPEDetected == false)
						{
							PPEDetected = true;
                            RegisterDetection(DETECTION_PPE_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
						if(FN == 1)
						{
							FNDetected = true;
						}


						if(S2 == 0)
						{
							break;
						}
						else if(S2 == 1)
						{
							CountS2++;
							TrainSpeedTimer2.start();
							Rank++;
							PPEDetected = false;
							PPIDetected = false;
							mZT1TrainState = ZT1_MR_S2_ACTIVE_STATE;
						}
						else
						{
							RegisterDetection(DETECTION_MAGNETIC_SENSOR_COUNT,Rank,mReferenceTimer->nsecsElapsed());
							mZT1TrainState = ZT1_POST_ANALYSIS_MODE_STATE;
						}
						break;
					}
					case ZT1_MR_S2_ACTIVE_STATE:	//5
					{
                        if(Pint == 1 && PPIDetected == false)
						{
							PPIDetected = true;
                            RegisterDetection(DETECTION_PPI_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
                        if(Pext == 1 && PPEDetected == false)
						{
							PPEDetected = true;
                            RegisterDetection(DETECTION_PPE_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
						if(FN == 1)
						{
							FNDetected = true;
						}


						if(S2 == 1)
						{
							break;
						}
						else if(S1 == 0 && S2 == 0)
						{
							mZT1TrainState = ZT1_MR_S2_TRANSIT_STATE;
						}
						else
						{
							RegisterDetection(DETECTION_MAGNETIC_SENSOR_COUNT,Rank,mReferenceTimer->nsecsElapsed());
							mZT1TrainState = ZT1_POST_ANALYSIS_MODE_STATE;
						}
						break;
					}
					case ZT1_MR_S2_TRANSIT_STATE:	//6
					{
                        if(Pint == 1 && PPIDetected == false)
						{
							PPIDetected = true;
                            RegisterDetection(DETECTION_PPI_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
                        if(Pext == 1 && PPEDetected == false)
						{
							PPEDetected = true;
                            RegisterDetection(DETECTION_PPE_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
						if(FN == 1)
						{
							FNDetected = true;
						}


						if(S1 == 0 && S2 == 0)
						{
							break;
						}
						else if(S1 == 0 && S2 == 1)
						{
							CountS2++;

							TrainSpeed = (MR_BOGIE_LENGTH / TrainSpeedTimer2.elapsed()) * 1000;	// m/s
							TrainSpeed *= 2.23694;	// Mph
							mZT1TrainState = ZT1_MR_S2_SECOND_PULSE_STATE;
						}
						else
						{
							RegisterDetection(DETECTION_MAGNETIC_SENSOR_COUNT,Rank,mReferenceTimer->nsecsElapsed());
							mZT1TrainState = ZT1_POST_ANALYSIS_MODE_STATE;
						}
						break;
					}
					case ZT1_MR_S2_SECOND_PULSE_STATE:	//7
					{
                        if(Pint == 1 && PPIDetected == false)
						{
							PPIDetected = true;
                            RegisterDetection(DETECTION_PPI_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
                        if(Pext == 1 && PPEDetected == false)
						{
							PPEDetected = true;
                            RegisterDetection(DETECTION_PPE_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
						if(FN == 1)
						{
							FNDetected = true;
						}

						if(PGCalibration)
						{

                            qint32 Value = PGint - PGIOffset;
                            if(Value < PGICalibValue)
                                PGICalibValue = Value;

                            Value = PGExt - PGEOffset;
                            if(Value < PGECalibValue)
                                PGECalibValue = Value;
						}
						else if(PGActive == false)
						{
							//Compute and verify if the PG is detected.
                            Quadra = ((PGint - PGIOffset) * (PGExt - PGEOffset));
							if(Quadra > PGValueTreshold)
							{
								//The PG has been detected, stop sampling...
								PGActive = true;
							}
						}

						if(S1 == 0 && S2 == 1)
						{
							break;
						}
						else if(S1 == 0 && S2 == 0)
						{
							if(PGCalibration)
							{
								CZTPGCalibrationData *Data = new CZTPGCalibrationData();
								Data->mTimestamp = mReferenceTimer->nsecsElapsed();
								Data->mPGExtValue = PGECalibValue;
								Data->mPGIntValue = PGICalibValue;

								emit NewPGCalibrationData(Data);
                                PGICalibValue = PGIOffset;
								PGECalibValue = PGEOffset;

                            }
							else if(PGActive == false)	//The PG has not been detected...
							{
								RegisterDetection(DETECTION_PG_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
							}
							PGActive = false;

							if(FNDetected == false)
							{
								RegisterDetection(DETECTION_FN_DETECTION,Bogie,mReferenceTimer->nsecsElapsed());
							}
							else
							{
								CountFN++;
							}

							mZT1TrainState = ZT1_WAIT_FOR_S1_STATE;	//bogie is passed entirely, go back to state ZT1_WAIT_FOR_S1_STATE (state 1)
						}
						else
						{
							RegisterDetection(DETECTION_MAGNETIC_SENSOR_COUNT,Rank,mReferenceTimer->nsecsElapsed());
							mZT1TrainState = ZT1_POST_ANALYSIS_MODE_STATE;
						}
						break;
					}
					case ZT1_MPM10_S2_ACTIVE_STATE:	//8
					{
                        if(Pint == 1 && PPIDetected == false)
						{
							PPIDetected = true;
                            RegisterDetection(DETECTION_PPI_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
                        if(Pext == 1 && PPEDetected == false)
						{
							PPEDetected = true;
                            RegisterDetection(DETECTION_PPE_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
						if(FN == 1)
						{
							FNDetected = true;
						}


						if(S1 == 0)
						{
							break;
						}
						else if(S1 == 1)
						{
							CountS1++;
							TrainSpeed = (MPM_BOGIE_LENGTH / TrainSpeedTimer1.elapsed()) * 1000;	// m/s
							TrainSpeed *= 2.23694;	// Mph
							mZT1TrainState = ZT1_MPM10_S1_SECOND_PULSE_STATE;
							//						qDebug("Goto state 9");
						}
						else
						{
							RegisterDetection(DETECTION_MAGNETIC_SENSOR_COUNT,Rank,mReferenceTimer->nsecsElapsed());
							mZT1TrainState = ZT1_POST_ANALYSIS_MODE_STATE;
						}
						break;
					}
					case ZT1_MPM10_S1_SECOND_PULSE_STATE:	//9
					{
                        if(Pint == 1 && PPIDetected == false)
						{
							PPIDetected = true;
                            RegisterDetection(DETECTION_PPI_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
                        if(Pext == 1 && PPEDetected == false)
						{
							PPEDetected = true;
                            RegisterDetection(DETECTION_PPE_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}

						if(FN == 1)
						{
							FNDetected = true;
						}


						if(S1 == 1)
						{
							break;
						}
						else if(S1 == 0 && S2 == 0)
						{
							mZT1TrainState = ZT1_MPM10_S1_S2_TRAINSIT_STATE;
						}
						else	//S1 = 0 & S2 = 1
						{
							RegisterDetection(DETECTION_MAGNETIC_SENSOR_COUNT,Rank,mReferenceTimer->nsecsElapsed());
							mZT1TrainState = ZT1_POST_ANALYSIS_MODE_STATE;
						}
						break;
					}
					case ZT1_MPM10_S1_S2_TRAINSIT_STATE://10
					{
                        if(Pint == 1 && PPIDetected == false)
						{
							PPIDetected = true;
                            RegisterDetection(DETECTION_PPI_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
                        if(Pext == 1 && PPEDetected == false)
						{
							PPEDetected = true;
                            RegisterDetection(DETECTION_PPE_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
						if(FN == 1)
						{
							FNDetected = true;

						}


						if(S1 == 0 && S2 == 0)
						{
							break;
						}
						else if(S1 == 0 && S2 == 1)
						{
							CountS2++;

                            TrainSpeed = (MPM_BOGIE_LENGTH / TrainSpeedTimer2.elapsed()) * 1000;	// m/s
							TrainSpeed *= 2.23694;	// Mph
							mZT1TrainState = ZT1_MPM10_S2_SECOND_PULSE_STATE;
						}
						else
						{
							RegisterDetection(DETECTION_MAGNETIC_SENSOR_COUNT,Rank,mReferenceTimer->nsecsElapsed());
							mZT1TrainState = ZT1_POST_ANALYSIS_MODE_STATE;
						}
						break;
					}
					case ZT1_MPM10_S2_SECOND_PULSE_STATE:	//11
					{

                        if(Pint == 1 && PPIDetected == false)
						{
							PPIDetected = true;
                            RegisterDetection(DETECTION_PPI_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
                        if(Pext == 1 && PPEDetected == false)
						{
							PPEDetected = true;
                            RegisterDetection(DETECTION_PPE_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
						}
						if(FN == 1)
						{
							FNDetected = true;
						}

						if(PGCalibration)
						{

                            qint32 Value = PGint - PGIOffset;
                            if(Value < PGICalibValue)
                                PGICalibValue = Value;

                            Value = PGExt - PGEOffset;
                            if(Value < PGECalibValue)
                                PGECalibValue = Value;
						}
						else if(PGActive == false)
						{
							//Compute and verify if the PG is detected.
                            Quadra = ((PGint - PGIOffset) * (PGExt - PGEOffset));
							if(Quadra > PGValueTreshold)
							{
								//The PG has been detected, stop sampling...
								PGActive = true;
							}
						}

						if(S1 == 0 && S2 == 1)
						{
							break;
						}
						else if(S1 == 0 && S2 == 0)
						{
							if(PGCalibration)
							{
								CZTPGCalibrationData *Data = new CZTPGCalibrationData();
								Data->mTimestamp = mReferenceTimer->nsecsElapsed();
								Data->mPGExtValue = PGECalibValue;
								Data->mPGIntValue = PGICalibValue;

								emit NewPGCalibrationData(Data);
                                PGICalibValue = PGIOffset;
								PGECalibValue = PGEOffset;

                            }
							else if(PGActive == false)	//The PG has not been detected...
							{
								RegisterDetection(DETECTION_PG_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
							}
							PGActive = false;

							if(FNDetected == false)
							{
								RegisterDetection(DETECTION_FN_DETECTION,Bogie,mReferenceTimer->nsecsElapsed());
							}
							else
							{
								CountFN++;
							}

							mZT1TrainState = ZT1_WAIT_FOR_S1_STATE;	//bogie is passed entirely, go back to state ZT1_WAIT_FOR_S1_STATE (state 1)
						}
						else
						{
							RegisterDetection(DETECTION_MAGNETIC_SENSOR_COUNT,Rank,mReferenceTimer->nsecsElapsed());
							mZT1TrainState = ZT1_POST_ANALYSIS_MODE_STATE;
						}
						break;
					}
					case ZT1_POST_ANALYSIS_MODE_STATE:
					{
						//In this mode, there is no "Real Time" analysis.  Data is stored and will be treated after
						//the train has passed.
						Bogie = 0;
						CountFN = 0;
						Rank = 0;
						TrainSpeed = 0;
						TrainType = TRAIN_TYPE_UNKNOWN;
						CountS1 = 0;
						CountS2 = 0;

						break;
					}

				} //switch(mZT1TrainState)

				mLastInputs = PCIInputs;
				mLastPGIntValue = PGint;
				mLastPGExtValue = PGExt;
				mLastSDFValue = SDFAnalog;

				CZT1ThreadData *Data = new CZT1ThreadData();
				Data->mTimeStamp = mReferenceTimer->nsecsElapsed();
				Data->mS1 = S1;
				Data->mS2 = S2;
				Data->mFN = FN;
				Data->mPExt = Pext;
				Data->mPInt = Pint;
				Data->mPG = (PGActive == true);
                Data->mPGIntValue = PGint;
				Data->mPGExtValue = PGExt;

				Data->mBogie = Bogie;
				Data->mFNCount = CountFN;
				Data->mRank = Rank;
				Data->mTrainSpeed = TrainSpeed;
				Data->mTrainType = TrainType;
				Data->mS1Count = CountS1;
				Data->mS2Count = CountS2;

				emit ZT1DataUpdate(Data,LazerProbesTransitOnly,SDFAnalog);

			}//if(PCIInputs != mLastInputs)


			mMutex.lock();
			if(mExitLoop == true)
				Run = false;
			mMutex.unlock();

		}//if loop timeout expired

	}//while

    mZT1Analyzing = false;

}

void CZT1AnalysisThread::TerminateAnalysis()
{
	mMutex.lock();
	mExitLoop = true;
	mMutex.unlock();
}

bool CZT1AnalysisThread::UpdateDetectionConfig(CZTDetectionFunctionConfig *NewConfig)
{
    //do not update in the middle of a train analysis.
    bool Go;
    mMutex.lock();
    Go = mZT1Analyzing;
    mMutex.unlock();

    if(Go == true)
        return false;

    //No need for a Mutex here since the thread is
    //not analyzing.
    mDetectionConfig = *NewConfig;


    return true;
}

void CZT1AnalysisThread::RegisterDetection(unsigned int DetectionID, unsigned int Rank,qint64 TimeStamp)
{
    if(mDetectionConfig.mZTDetectionConfig[DETECTION_FCT_ZT1].AnalysisActive == false)
        return;

	//Register an error only if the analysis is active
    switch(DetectionID)
    {
		case DETECTION_MAGNETIC_SENSOR_COUNT:
		{
			if(mDetectionConfig.mZTDetectionConfig[DETECTION_FCT_ZT1].AnalysisActive == false)
			{
				return;
			}
			break;
		}
		case DETECTION_PEQ1_DETECTION:
		{
			if(mDetectionConfig.mZTDetectionConfig[DETECTION_FCT_ZT1].AnalysisActive == false)
			{
				return;
			}
			else
			{
				//If PEQ1 was already registered, ignore this occurence.
				if(mPEQDetectionLatch == true)
				{
					return;
				}
				mPEQDetectionLatch = true;
			}
            break;
        }
        case DETECTION_FN_DETECTION:
        {
            if(mDetectionConfig.mZTDetectionConfig[DETECTION_FCT_FN].AnalysisActive == false)
            {
                return;
            }
            break;
        }
		case DETECTION_PG_DETECTION:
        {
            if(mDetectionConfig.mZTDetectionConfig[DETECTION_FCT_PG].AnalysisActive == false)
            {
                return;
            }
            break;
        }
        case DETECTION_PPI_DETECTION:
        {
            if(mDetectionConfig.mZTDetectionConfig[DETECTION_FCT_PP].AnalysisActive == false)
            {
                return;
            }
            break;
        }
        case DETECTION_PPE_DETECTION:
        {
            if(mDetectionConfig.mZTDetectionConfig[DETECTION_FCT_PP].AnalysisActive == false)
            {
                return;
            }
            break;
        }
    }

	CZTDetectionData *DetectData = new CZTDetectionData;
    DetectData->mTimeStamp = TimeStamp;
	DetectData->mRank = Rank;
	DetectData->mDetectionID = DetectionID;

    emit DetectionTriggered(DetectData);


}

