/**
* 
* @brief Initialize the main state machine.  
*/
void TestMgr::InitStateMachine(void) {
	// Set total number of states
	state_machine_init(&m_StateMachine, RUN_STATE_TOTAL);

	// Add state machine handlers
	state_machine_add_handler(&m_StateMachine, RUN_STATE_IDLE, TestMgr::RunStateIdle);
	state_machine_add_handler(&m_StateMachine, RUN_STATE_START, TestMgr::RunStateStart);
	state_machine_add_handler(&m_StateMachine, RUN_STATE_RAMP_TEMP, TestMgr::RunStateRampTemp);
	state_machine_add_handler(&m_StateMachine, RUN_STATE_WAIT_FOR_TEMP, TestMgr::RunStateWaitForTemp);
	state_machine_add_handler(&m_StateMachine, RUN_STATE_DONE, TestMgr::RunStateDone);

	// Set initial state
	state_machine_set_state(&m_StateMachine, RUN_STATE_START);

	// Call state machine to run the first state (IDLE)
	state_machine_run(&m_StateMachine, (uint32_t *)this, (uint32_t *)NULL);
}
void* FSM(void *data){
	state_t* state = (state_t*) data;
	state_machine_run(state);
	return NULL;
}
void TestMgr::RunWithPid(void) {

	bool doExit = false;
	float pwmDutyCycle = 0.0;

	// Initialize the state machine that runs the worker bees
	InitStateMachine();

	// Initialize the PID Loop
	// PidConstants_t pidConstants;
	// m_PidRange.ChangeRangeId(0);
	// m_PidRange.GetRangeConstants(pidConstants);
	// m_PidLoop.InitLoopUsingConstants(pidConstants, m_PidRange.GetRangeEndTemp());
	// p->m_PidLoop.SetLoopOnOff(PID_LOOP_ON);

	while (!doExit) {

		if (m_AbortFlag) {
			doExit = true;
			break;
		}

		// Get the elapsed time since the PID loop was run last
		m_PidLoopElapsedTime = m_PidLoopRunTimer.GetElapsedMillisec();

		// Run the PID loop at the specified interval
		if (m_PidLoopElapsedTime >= (m_PidLoopUpdateTimeInMs - 10)) {

			// Restart PID loop timer
			m_PidLoopRunTimer.ResetStartTimestamp();

			// Safety check
			if (m_PlateTempDegreesC > 100.0) {
				m_Sub20.HeaterPwmUpdate(0.0);
				m_Sub20.TurnOffHeater();
				std::cout << "Temperature exceeds max allowed. Turning off heater and exiting."  << std::endl;
				doExit = true;
			}

			// Read the plate temperature
			if (ReadTemp()) {

				// Run the state machine
				state_machine_run(&m_StateMachine, (uint32_t *)this, (uint32_t *)NULL);

				// Re-read the elapsed time since loop was run
				// uint64_t elapsedTimeInMs = m_PidLoopRunTimer.GetElapsedMillisec();

				// Run the PID loop
				pwmDutyCycle = m_PidLoop.Compute(m_PlateTempDegreesC, (m_PidLoopElapsedTime / ((float)1000.0)));
				if (m_PidLoop.IsLoopOn()) {
					// Update either the heater or the cooler PWM
					PidDirection_t pidDirection = m_PidLoop.GetDirection();
                    assert (pidDirection == PID_DIR_DIRECT || pidDirection == PID_DIR_REVERSE);
                    if (pidDirection == PID_DIR_DIRECT) {
						m_Sub20.HeaterPwmUpdate(pwmDutyCycle);
					} else {
						m_Sub20.CoolerPwmUpdate(pwmDutyCycle);
					}
				}
			}
		}

		// Get the elapsed time since the last voltage was logged
		m_LogVoltageElapsedTime = m_LogVoltageTimer.GetElapsedMillisec();

		// Log voltage at the specified interval.
		if (m_LogVoltageElapsedTime >= (m_VoltageLogUpdateTimeInMs - 10)) {

			// Restart Log Voltage timer
			m_LogVoltageTimer.ResetStartTimestamp();

			if (0 && m_FlukeSerial.ReadAcVoltage(m_AcVoltage)) {
				std::cout << "[" << std::dec << std::setfill('0') << std::setw(6) << m_LogVoltageElapsedTime << "] ";
				std::cout << "DC Voltage: ";
				std::cout << std::fixed << std::setw(11) << std::setprecision(6) << m_AcVoltage << std::endl;
				VoltageLogWriteData(m_RunTimer.GetElapsedMillisec());
			}
		}

		// Run the main loop at a 10ms rate
		QThread::msleep(10);
	}
}