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