nuclear@3: /************************************************************************************ nuclear@3: nuclear@3: Filename : Util_LatencyTest.cpp nuclear@3: Content : Wraps the lower level LatencyTester interface and adds functionality. nuclear@3: Created : February 14, 2013 nuclear@3: Authors : Lee Cooper nuclear@3: nuclear@3: Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved. nuclear@3: nuclear@3: Use of this software is subject to the terms of the Oculus license nuclear@3: agreement provided at the time of installation or download, or which nuclear@3: otherwise accompanies this software in either electronic or hard copy form. nuclear@3: nuclear@3: *************************************************************************************/ nuclear@3: nuclear@3: #include "Util_LatencyTest.h" nuclear@3: nuclear@3: #include "../Kernel/OVR_Log.h" nuclear@3: #include "../Kernel/OVR_Timer.h" nuclear@3: nuclear@3: namespace OVR { namespace Util { nuclear@3: nuclear@3: static const UInt32 TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION = 16*10; nuclear@3: static const UInt32 TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION = 16*10; nuclear@3: static const UInt32 TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT = 16*5; nuclear@3: static const UInt32 TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS = 16*5; nuclear@3: static const UInt32 DEFAULT_NUMBER_OF_SAMPLES = 10; // For both color 1->2 and color 2->1 transitions. nuclear@3: static const UInt32 INITIAL_SAMPLES_TO_IGNORE = 4; nuclear@3: static const UInt32 TIMEOUT_WAITING_FOR_TEST_STARTED = 1000; nuclear@3: static const UInt32 TIMEOUT_WAITING_FOR_COLOR_DETECTED = 4000; nuclear@3: static const Color CALIBRATE_BLACK(0, 0, 0); nuclear@3: static const Color CALIBRATE_WHITE(255, 255, 255); nuclear@3: static const Color COLOR1(0, 0, 0); nuclear@3: static const Color COLOR2(255, 255, 255); nuclear@3: static const Color SENSOR_DETECT_THRESHOLD(128, 255, 255); nuclear@3: static const float BIG_FLOAT = 1000000.0f; nuclear@3: static const float SMALL_FLOAT = -1000000.0f; nuclear@3: nuclear@3: //------------------------------------------------------------------------------------- nuclear@3: // ***** LatencyTest nuclear@3: nuclear@3: LatencyTest::LatencyTest(LatencyTestDevice* device) nuclear@3: : Handler(getThis()) nuclear@3: { nuclear@3: if (device != NULL) nuclear@3: { nuclear@3: SetDevice(device); nuclear@3: } nuclear@3: nuclear@3: reset(); nuclear@3: nuclear@3: srand(Timer::GetTicksMs()); nuclear@3: } nuclear@3: nuclear@3: LatencyTest::~LatencyTest() nuclear@3: { nuclear@3: clearMeasurementResults(); nuclear@3: } nuclear@3: nuclear@3: bool LatencyTest::SetDevice(LatencyTestDevice* device) nuclear@3: { nuclear@3: nuclear@3: if (device != Device) nuclear@3: { nuclear@3: if (device != NULL) nuclear@3: { nuclear@3: if (device->GetMessageHandler() != NULL) nuclear@3: { nuclear@3: OVR_DEBUG_LOG( nuclear@3: ("LatencyTest::AttachToDevice failed - device %p already has handler", device)); nuclear@3: return false; nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: if (Device != NULL) nuclear@3: { nuclear@3: Device->SetMessageHandler(0); nuclear@3: } nuclear@3: Device = device; nuclear@3: nuclear@3: if (Device != NULL) nuclear@3: { nuclear@3: Device->SetMessageHandler(&Handler); nuclear@3: nuclear@3: // Set trigger threshold. nuclear@3: LatencyTestConfiguration configuration(SENSOR_DETECT_THRESHOLD, false); // No samples streaming. nuclear@3: Device->SetConfiguration(configuration, true); nuclear@3: nuclear@3: // Set display to intial (3 dashes). nuclear@3: LatencyTestDisplay ltd(2, 0x40400040); nuclear@3: Device->SetDisplay(ltd); nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: return true; nuclear@3: } nuclear@3: nuclear@3: UInt32 LatencyTest::getRandomComponent(UInt32 range) nuclear@3: { nuclear@3: UInt32 val = rand() % range; nuclear@3: return val; nuclear@3: } nuclear@3: nuclear@3: void LatencyTest::BeginTest() nuclear@3: { nuclear@3: if (State == State_WaitingForButton) nuclear@3: { nuclear@3: // Set color to black and wait a while. nuclear@3: RenderColor = CALIBRATE_BLACK; nuclear@3: nuclear@3: State = State_WaitingForSettlePreCalibrationColorBlack; nuclear@3: OVR_DEBUG_LOG(("State_WaitingForButton -> State_WaitingForSettlePreCalibrationColorBlack.")); nuclear@3: nuclear@3: setTimer(TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION); nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: void LatencyTest::handleMessage(const Message& msg, LatencyTestMessageType latencyTestMessage) nuclear@3: { nuclear@3: // For debugging. nuclear@3: /* if (msg.Type == Message_LatencyTestSamples) nuclear@3: { nuclear@3: MessageLatencyTestSamples* pSamples = (MessageLatencyTestSamples*) &msg; nuclear@3: nuclear@3: if (pSamples->Samples.GetSize() > 0) nuclear@3: { nuclear@3: // Just show the first one for now. nuclear@3: Color c = pSamples->Samples[0]; nuclear@3: OVR_DEBUG_LOG(("%d %d %d", c.R, c.G, c.B)); nuclear@3: } nuclear@3: return; nuclear@3: } nuclear@3: */ nuclear@3: nuclear@3: if (latencyTestMessage == LatencyTest_Timer) nuclear@3: { nuclear@3: if (!Device) nuclear@3: { nuclear@3: reset(); nuclear@3: return; nuclear@3: } nuclear@3: nuclear@3: if (State == State_WaitingForSettlePreCalibrationColorBlack) nuclear@3: { nuclear@3: // Send calibrate message to device and wait a while. nuclear@3: Device->SetCalibrate(CALIBRATE_BLACK); nuclear@3: nuclear@3: State = State_WaitingForSettlePostCalibrationColorBlack; nuclear@3: OVR_DEBUG_LOG(("State_WaitingForSettlePreCalibrationColorBlack -> State_WaitingForSettlePostCalibrationColorBlack.")); nuclear@3: nuclear@3: setTimer(TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION); nuclear@3: } nuclear@3: else if (State == State_WaitingForSettlePostCalibrationColorBlack) nuclear@3: { nuclear@3: // Change color to white and wait a while. nuclear@3: RenderColor = CALIBRATE_WHITE; nuclear@3: nuclear@3: State = State_WaitingForSettlePreCalibrationColorWhite; nuclear@3: OVR_DEBUG_LOG(("State_WaitingForSettlePostCalibrationColorBlack -> State_WaitingForSettlePreCalibrationColorWhite.")); nuclear@3: nuclear@3: setTimer(TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION); nuclear@3: } nuclear@3: else if (State == State_WaitingForSettlePreCalibrationColorWhite) nuclear@3: { nuclear@3: // Send calibrate message to device and wait a while. nuclear@3: Device->SetCalibrate(CALIBRATE_WHITE); nuclear@3: nuclear@3: State = State_WaitingForSettlePostCalibrationColorWhite; nuclear@3: OVR_DEBUG_LOG(("State_WaitingForSettlePreCalibrationColorWhite -> State_WaitingForSettlePostCalibrationColorWhite.")); nuclear@3: nuclear@3: setTimer(TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION); nuclear@3: } nuclear@3: else if (State == State_WaitingForSettlePostCalibrationColorWhite) nuclear@3: { nuclear@3: // Calibration is done. Switch to color 1 and wait for it to settle. nuclear@3: RenderColor = COLOR1; nuclear@3: nuclear@3: State = State_WaitingForSettlePostMeasurement; nuclear@3: OVR_DEBUG_LOG(("State_WaitingForSettlePostCalibrationColorWhite -> State_WaitingForSettlePostMeasurement.")); nuclear@3: nuclear@3: UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS); nuclear@3: setTimer(waitTime); nuclear@3: } nuclear@3: else if (State == State_WaitingForSettlePostMeasurement) nuclear@3: { nuclear@3: // Prepare for next measurement. nuclear@3: nuclear@3: // Create a new result object. nuclear@3: MeasurementResult* pResult = new MeasurementResult(); nuclear@3: Results.PushBack(pResult); nuclear@3: nuclear@3: State = State_WaitingToTakeMeasurement; nuclear@3: OVR_DEBUG_LOG(("State_WaitingForSettlePostMeasurement -> State_WaitingToTakeMeasurement.")); nuclear@3: } nuclear@3: else if (State == State_WaitingForTestStarted) nuclear@3: { nuclear@3: // We timed out waiting for 'TestStarted'. Abandon this measurement and setup for the next. nuclear@3: getActiveResult()->TimedOutWaitingForTestStarted = true; nuclear@3: nuclear@3: State = State_WaitingForSettlePostMeasurement; nuclear@3: OVR_DEBUG_LOG(("** Timed out waiting for 'TestStarted'.")); nuclear@3: OVR_DEBUG_LOG(("State_WaitingForTestStarted -> State_WaitingForSettlePostMeasurement.")); nuclear@3: nuclear@3: UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS); nuclear@3: setTimer(waitTime); nuclear@3: } nuclear@3: else if (State == State_WaitingForColorDetected) nuclear@3: { nuclear@3: // We timed out waiting for 'ColorDetected'. Abandon this measurement and setup for the next. nuclear@3: getActiveResult()->TimedOutWaitingForColorDetected = true; nuclear@3: nuclear@3: State = State_WaitingForSettlePostMeasurement; nuclear@3: OVR_DEBUG_LOG(("** Timed out waiting for 'ColorDetected'.")); nuclear@3: OVR_DEBUG_LOG(("State_WaitingForColorDetected -> State_WaitingForSettlePostMeasurement.")); nuclear@3: nuclear@3: UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS); nuclear@3: setTimer(waitTime); nuclear@3: } nuclear@3: } nuclear@3: else if (latencyTestMessage == LatencyTest_ProcessInputs) nuclear@3: { nuclear@3: if (State == State_WaitingToTakeMeasurement) nuclear@3: { nuclear@3: if (!Device) nuclear@3: { nuclear@3: reset(); nuclear@3: return; nuclear@3: } nuclear@3: nuclear@3: // Send 'StartTest' feature report with opposite target color. nuclear@3: if (RenderColor == COLOR1) nuclear@3: { nuclear@3: RenderColor = COLOR2; nuclear@3: } nuclear@3: else nuclear@3: { nuclear@3: RenderColor = COLOR1; nuclear@3: } nuclear@3: nuclear@3: getActiveResult()->TargetColor = RenderColor; nuclear@3: nuclear@3: // Record time so we can determine usb roundtrip time. nuclear@3: getActiveResult()->StartTestTicksMicroS = Timer::GetTicks(); nuclear@3: nuclear@3: Device->SetStartTest(RenderColor); nuclear@3: nuclear@3: State = State_WaitingForTestStarted; nuclear@3: OVR_DEBUG_LOG(("State_WaitingToTakeMeasurement -> State_WaitingForTestStarted.")); nuclear@3: nuclear@3: setTimer(TIMEOUT_WAITING_FOR_TEST_STARTED); nuclear@3: nuclear@3: LatencyTestDisplay ltd(2, 0x40090040); nuclear@3: Device->SetDisplay(ltd); nuclear@3: } nuclear@3: } nuclear@3: else if (msg.Type == Message_LatencyTestButton) nuclear@3: { nuclear@3: BeginTest(); nuclear@3: } nuclear@3: else if (msg.Type == Message_LatencyTestStarted) nuclear@3: { nuclear@3: if (State == State_WaitingForTestStarted) nuclear@3: { nuclear@3: clearTimer(); nuclear@3: nuclear@3: // Record time so we can determine usb roundtrip time. nuclear@3: getActiveResult()->TestStartedTicksMicroS = Timer::GetTicks(); nuclear@3: nuclear@3: State = State_WaitingForColorDetected; nuclear@3: OVR_DEBUG_LOG(("State_WaitingForTestStarted -> State_WaitingForColorDetected.")); nuclear@3: nuclear@3: setTimer(TIMEOUT_WAITING_FOR_COLOR_DETECTED); nuclear@3: } nuclear@3: } nuclear@3: else if (msg.Type == Message_LatencyTestColorDetected) nuclear@3: { nuclear@3: if (State == State_WaitingForColorDetected) nuclear@3: { nuclear@3: // Record time to detect color. nuclear@3: MessageLatencyTestColorDetected* pDetected = (MessageLatencyTestColorDetected*) &msg; nuclear@3: UInt16 elapsedTime = pDetected->Elapsed; nuclear@3: OVR_DEBUG_LOG(("Time to 'ColorDetected' = %d", elapsedTime)); nuclear@3: nuclear@3: getActiveResult()->DeviceMeasuredElapsedMilliS = elapsedTime; nuclear@3: nuclear@3: if (areResultsComplete()) nuclear@3: { nuclear@3: // We're done. nuclear@3: processResults(); nuclear@3: reset(); nuclear@3: } nuclear@3: else nuclear@3: { nuclear@3: // Run another measurement. nuclear@3: State = State_WaitingForSettlePostMeasurement; nuclear@3: OVR_DEBUG_LOG(("State_WaitingForColorDetected -> State_WaitingForSettlePostMeasurement.")); nuclear@3: nuclear@3: UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS); nuclear@3: setTimer(waitTime); nuclear@3: nuclear@3: LatencyTestDisplay ltd(2, 0x40400040); nuclear@3: Device->SetDisplay(ltd); nuclear@3: } nuclear@3: } nuclear@3: } nuclear@3: else if (msg.Type == Message_DeviceRemoved) nuclear@3: { nuclear@3: reset(); nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: LatencyTest::MeasurementResult* LatencyTest::getActiveResult() nuclear@3: { nuclear@3: OVR_ASSERT(!Results.IsEmpty()); nuclear@3: return Results.GetLast(); nuclear@3: } nuclear@3: nuclear@3: void LatencyTest::setTimer(UInt32 timeMilliS) nuclear@3: { nuclear@3: ActiveTimerMilliS = timeMilliS; nuclear@3: } nuclear@3: nuclear@3: void LatencyTest::clearTimer() nuclear@3: { nuclear@3: ActiveTimerMilliS = 0; nuclear@3: } nuclear@3: nuclear@3: void LatencyTest::reset() nuclear@3: { nuclear@3: clearMeasurementResults(); nuclear@3: State = State_WaitingForButton; nuclear@3: nuclear@3: HaveOldTime = false; nuclear@3: ActiveTimerMilliS = 0; nuclear@3: } nuclear@3: nuclear@3: void LatencyTest::clearMeasurementResults() nuclear@3: { nuclear@3: while(!Results.IsEmpty()) nuclear@3: { nuclear@3: MeasurementResult* pElem = Results.GetFirst(); nuclear@3: pElem->RemoveNode(); nuclear@3: delete pElem; nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: LatencyTest::LatencyTestHandler::~LatencyTestHandler() nuclear@3: { nuclear@3: RemoveHandlerFromDevices(); nuclear@3: } nuclear@3: nuclear@3: void LatencyTest::LatencyTestHandler::OnMessage(const Message& msg) nuclear@3: { nuclear@3: pLatencyTestUtil->handleMessage(msg); nuclear@3: } nuclear@3: nuclear@3: void LatencyTest::ProcessInputs() nuclear@3: { nuclear@3: updateForTimeouts(); nuclear@3: handleMessage(Message(), LatencyTest_ProcessInputs); nuclear@3: } nuclear@3: nuclear@3: bool LatencyTest::DisplayScreenColor(Color& colorToDisplay) nuclear@3: { nuclear@3: updateForTimeouts(); nuclear@3: nuclear@3: if (State == State_WaitingForButton) nuclear@3: { nuclear@3: return false; nuclear@3: } nuclear@3: nuclear@3: colorToDisplay = RenderColor; nuclear@3: return true; nuclear@3: } nuclear@3: nuclear@3: const char* LatencyTest::GetResultsString() nuclear@3: { nuclear@3: if (!ResultsString.IsEmpty() && ReturnedResultString != ResultsString.ToCStr()) nuclear@3: { nuclear@3: ReturnedResultString = ResultsString; nuclear@3: return ReturnedResultString.ToCStr(); nuclear@3: } nuclear@3: nuclear@3: return NULL; nuclear@3: } nuclear@3: nuclear@3: bool LatencyTest::areResultsComplete() nuclear@3: { nuclear@3: UInt32 initialMeasurements = 0; nuclear@3: nuclear@3: UInt32 measurements1to2 = 0; nuclear@3: UInt32 measurements2to1 = 0; nuclear@3: nuclear@3: MeasurementResult* pCurr = Results.GetFirst(); nuclear@3: while(true) nuclear@3: { nuclear@3: // Process. nuclear@3: if (!pCurr->TimedOutWaitingForTestStarted && nuclear@3: !pCurr->TimedOutWaitingForColorDetected) nuclear@3: { nuclear@3: initialMeasurements++; nuclear@3: nuclear@3: if (initialMeasurements > INITIAL_SAMPLES_TO_IGNORE) nuclear@3: { nuclear@3: if (pCurr->TargetColor == COLOR2) nuclear@3: { nuclear@3: measurements1to2++; nuclear@3: } nuclear@3: else nuclear@3: { nuclear@3: measurements2to1++; nuclear@3: } nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: if (Results.IsLast(pCurr)) nuclear@3: { nuclear@3: break; nuclear@3: } nuclear@3: pCurr = Results.GetNext(pCurr); nuclear@3: } nuclear@3: nuclear@3: if (measurements1to2 >= DEFAULT_NUMBER_OF_SAMPLES && nuclear@3: measurements2to1 >= DEFAULT_NUMBER_OF_SAMPLES) nuclear@3: { nuclear@3: return true; nuclear@3: } nuclear@3: nuclear@3: return false; nuclear@3: } nuclear@3: nuclear@3: void LatencyTest::processResults() nuclear@3: { nuclear@3: nuclear@3: UInt32 minTime1To2 = UINT_MAX; nuclear@3: UInt32 maxTime1To2 = 0; nuclear@3: float averageTime1To2 = 0.0f; nuclear@3: UInt32 minTime2To1 = UINT_MAX; nuclear@3: UInt32 maxTime2To1 = 0; nuclear@3: float averageTime2To1 = 0.0f; nuclear@3: nuclear@3: float minUSBTripMilliS = BIG_FLOAT; nuclear@3: float maxUSBTripMilliS = SMALL_FLOAT; nuclear@3: float averageUSBTripMilliS = 0.0f; nuclear@3: UInt32 countUSBTripTime = 0; nuclear@3: nuclear@3: UInt32 measurementsCount = 0; nuclear@3: UInt32 measurements1to2 = 0; nuclear@3: UInt32 measurements2to1 = 0; nuclear@3: nuclear@3: MeasurementResult* pCurr = Results.GetFirst(); nuclear@3: UInt32 count = 0; nuclear@3: while(true) nuclear@3: { nuclear@3: count++; nuclear@3: nuclear@3: if (!pCurr->TimedOutWaitingForTestStarted && nuclear@3: !pCurr->TimedOutWaitingForColorDetected) nuclear@3: { nuclear@3: measurementsCount++; nuclear@3: nuclear@3: if (measurementsCount > INITIAL_SAMPLES_TO_IGNORE) nuclear@3: { nuclear@3: if (pCurr->TargetColor == COLOR2) nuclear@3: { nuclear@3: measurements1to2++; nuclear@3: nuclear@3: if (measurements1to2 <= DEFAULT_NUMBER_OF_SAMPLES) nuclear@3: { nuclear@3: UInt32 elapsed = pCurr->DeviceMeasuredElapsedMilliS; nuclear@3: nuclear@3: minTime1To2 = Alg::Min(elapsed, minTime1To2); nuclear@3: maxTime1To2 = Alg::Max(elapsed, maxTime1To2); nuclear@3: nuclear@3: averageTime1To2 += (float) elapsed; nuclear@3: } nuclear@3: } nuclear@3: else nuclear@3: { nuclear@3: measurements2to1++; nuclear@3: nuclear@3: if (measurements2to1 <= DEFAULT_NUMBER_OF_SAMPLES) nuclear@3: { nuclear@3: UInt32 elapsed = pCurr->DeviceMeasuredElapsedMilliS; nuclear@3: nuclear@3: minTime2To1 = Alg::Min(elapsed, minTime2To1); nuclear@3: maxTime2To1 = Alg::Max(elapsed, maxTime2To1); nuclear@3: nuclear@3: averageTime2To1 += (float) elapsed; nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: float usbRountripElapsedMilliS = 0.001f * (float) (pCurr->TestStartedTicksMicroS - pCurr->StartTestTicksMicroS); nuclear@3: minUSBTripMilliS = Alg::Min(usbRountripElapsedMilliS, minUSBTripMilliS); nuclear@3: maxUSBTripMilliS = Alg::Max(usbRountripElapsedMilliS, maxUSBTripMilliS); nuclear@3: averageUSBTripMilliS += usbRountripElapsedMilliS; nuclear@3: countUSBTripTime++; nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: if (measurements1to2 >= DEFAULT_NUMBER_OF_SAMPLES && nuclear@3: measurements2to1 >= DEFAULT_NUMBER_OF_SAMPLES) nuclear@3: { nuclear@3: break; nuclear@3: } nuclear@3: nuclear@3: if (Results.IsLast(pCurr)) nuclear@3: { nuclear@3: break; nuclear@3: } nuclear@3: pCurr = Results.GetNext(pCurr); nuclear@3: } nuclear@3: nuclear@3: averageTime1To2 /= (float) DEFAULT_NUMBER_OF_SAMPLES; nuclear@3: averageTime2To1 /= (float) DEFAULT_NUMBER_OF_SAMPLES; nuclear@3: nuclear@3: averageUSBTripMilliS /= countUSBTripTime; nuclear@3: nuclear@3: float finalResult = 0.5f * (averageTime1To2 + averageTime2To1); nuclear@3: finalResult += averageUSBTripMilliS; nuclear@3: nuclear@3: ResultsString.Clear(); nuclear@3: ResultsString.AppendFormat("RESULT=%.1f (add half Tracker period) [b->w %d|%.1f|%d] [w->b %d|%.1f|%d] [usb rndtrp %.1f|%.1f|%.1f] [cnt %d] [tmouts %d]", nuclear@3: finalResult, nuclear@3: minTime1To2, averageTime1To2, maxTime1To2, nuclear@3: minTime2To1, averageTime2To1, maxTime2To1, nuclear@3: minUSBTripMilliS, averageUSBTripMilliS, maxUSBTripMilliS, nuclear@3: DEFAULT_NUMBER_OF_SAMPLES*2, count - measurementsCount); nuclear@3: nuclear@3: // Display result on latency tester display. nuclear@3: LatencyTestDisplay ltd(1, (int)finalResult); nuclear@3: Device->SetDisplay(ltd); nuclear@3: } nuclear@3: nuclear@3: void LatencyTest::updateForTimeouts() nuclear@3: { nuclear@3: if (!HaveOldTime) nuclear@3: { nuclear@3: HaveOldTime = true; nuclear@3: OldTime = Timer::GetTicksMs(); nuclear@3: return; nuclear@3: } nuclear@3: nuclear@3: UInt32 newTime = Timer::GetTicksMs(); nuclear@3: UInt32 elapsedMilliS = newTime - OldTime; nuclear@3: if (newTime < OldTime) nuclear@3: { nuclear@3: elapsedMilliS = OldTime - newTime; nuclear@3: elapsedMilliS = UINT_MAX - elapsedMilliS; nuclear@3: } nuclear@3: OldTime = newTime; nuclear@3: nuclear@3: elapsedMilliS = Alg::Min(elapsedMilliS, (UInt32) 100); // Clamp at 100mS in case we're not being called very often. nuclear@3: nuclear@3: nuclear@3: if (ActiveTimerMilliS == 0) nuclear@3: { nuclear@3: return; nuclear@3: } nuclear@3: nuclear@3: if (elapsedMilliS >= ActiveTimerMilliS) nuclear@3: { nuclear@3: ActiveTimerMilliS = 0; nuclear@3: handleMessage(Message(), LatencyTest_Timer); nuclear@3: return; nuclear@3: } nuclear@3: nuclear@3: ActiveTimerMilliS -= elapsedMilliS; nuclear@3: } nuclear@3: nuclear@3: }} // namespace OVR::Util