oculus1

diff libovr/Src/Util/Util_LatencyTest.cpp @ 3:b069a5c27388

added a couple more stuff, fixed all the LibOVR line endings
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 15 Sep 2013 04:10:05 +0300
parents e2f9e4603129
children
line diff
     1.1 --- a/libovr/Src/Util/Util_LatencyTest.cpp	Sat Sep 14 17:51:03 2013 +0300
     1.2 +++ b/libovr/Src/Util/Util_LatencyTest.cpp	Sun Sep 15 04:10:05 2013 +0300
     1.3 @@ -1,1 +1,571 @@
     1.4 -/************************************************************************************
     1.5 
     1.6 Filename    :   Util_LatencyTest.cpp
     1.7 Content     :   Wraps the lower level LatencyTester interface and adds functionality.
     1.8 Created     :   February 14, 2013
     1.9 Authors     :   Lee Cooper
    1.10 
    1.11 Copyright   :   Copyright 2013 Oculus VR, Inc. All Rights reserved.
    1.12 
    1.13 Use of this software is subject to the terms of the Oculus license
    1.14 agreement provided at the time of installation or download, or which
    1.15 otherwise accompanies this software in either electronic or hard copy form.
    1.16 
    1.17 *************************************************************************************/
    1.18 
    1.19 #include "Util_LatencyTest.h"
    1.20 
    1.21 #include "../Kernel/OVR_Log.h"
    1.22 #include "../Kernel/OVR_Timer.h"
    1.23 
    1.24 namespace OVR { namespace Util {
    1.25 
    1.26 static const UInt32     TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION = 16*10;
    1.27 static const UInt32     TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION = 16*10;
    1.28 static const UInt32     TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT = 16*5;
    1.29 static const UInt32     TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS = 16*5;
    1.30 static const UInt32     DEFAULT_NUMBER_OF_SAMPLES = 10;                 // For both color 1->2 and color 2->1 transitions.
    1.31 static const UInt32     INITIAL_SAMPLES_TO_IGNORE = 4;
    1.32 static const UInt32     TIMEOUT_WAITING_FOR_TEST_STARTED = 1000;
    1.33 static const UInt32     TIMEOUT_WAITING_FOR_COLOR_DETECTED = 4000;
    1.34 static const Color      CALIBRATE_BLACK(0, 0, 0);
    1.35 static const Color      CALIBRATE_WHITE(255, 255, 255);
    1.36 static const Color      COLOR1(0, 0, 0);
    1.37 static const Color      COLOR2(255, 255, 255);
    1.38 static const Color      SENSOR_DETECT_THRESHOLD(128, 255, 255);
    1.39 static const float      BIG_FLOAT = 1000000.0f;
    1.40 static const float      SMALL_FLOAT = -1000000.0f;
    1.41 
    1.42 //-------------------------------------------------------------------------------------
    1.43 // ***** LatencyTest
    1.44 
    1.45 LatencyTest::LatencyTest(LatencyTestDevice* device)
    1.46  :  Handler(getThis())
    1.47 {
    1.48     if (device != NULL)
    1.49     {
    1.50         SetDevice(device);
    1.51     }
    1.52 
    1.53     reset();
    1.54 
    1.55     srand(Timer::GetTicksMs());
    1.56 }
    1.57 
    1.58 LatencyTest::~LatencyTest()
    1.59 {
    1.60      clearMeasurementResults();
    1.61 }
    1.62 
    1.63 bool LatencyTest::SetDevice(LatencyTestDevice* device)
    1.64 {
    1.65 
    1.66     if (device != Device)
    1.67     {
    1.68         if (device != NULL)
    1.69         {
    1.70             if (device->GetMessageHandler() != NULL)
    1.71             {
    1.72                 OVR_DEBUG_LOG(
    1.73                     ("LatencyTest::AttachToDevice failed - device %p already has handler", device));
    1.74                 return false;
    1.75             }
    1.76         }
    1.77 
    1.78         if (Device != NULL)
    1.79         {
    1.80             Device->SetMessageHandler(0);
    1.81         }
    1.82         Device = device;
    1.83 
    1.84         if (Device != NULL)
    1.85         {
    1.86             Device->SetMessageHandler(&Handler);
    1.87 
    1.88             // Set trigger threshold.
    1.89             LatencyTestConfiguration configuration(SENSOR_DETECT_THRESHOLD, false);     // No samples streaming.
    1.90             Device->SetConfiguration(configuration, true);
    1.91 
    1.92             // Set display to intial (3 dashes).
    1.93             LatencyTestDisplay ltd(2, 0x40400040);
    1.94             Device->SetDisplay(ltd);
    1.95         }
    1.96     }
    1.97 
    1.98     return true;
    1.99 }
   1.100 
   1.101 UInt32 LatencyTest::getRandomComponent(UInt32 range)
   1.102 {
   1.103     UInt32 val = rand() % range;
   1.104     return val;
   1.105 }
   1.106 
   1.107 void LatencyTest::BeginTest()
   1.108 {
   1.109      if (State == State_WaitingForButton)
   1.110     {
   1.111         // Set color to black and wait a while.
   1.112         RenderColor = CALIBRATE_BLACK;
   1.113 
   1.114         State = State_WaitingForSettlePreCalibrationColorBlack;
   1.115         OVR_DEBUG_LOG(("State_WaitingForButton -> State_WaitingForSettlePreCalibrationColorBlack."));
   1.116 
   1.117         setTimer(TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION);
   1.118     }
   1.119 }
   1.120 
   1.121 void LatencyTest::handleMessage(const Message& msg, LatencyTestMessageType latencyTestMessage)
   1.122 {
   1.123     // For debugging.
   1.124 /*  if (msg.Type == Message_LatencyTestSamples)
   1.125     {
   1.126         MessageLatencyTestSamples* pSamples = (MessageLatencyTestSamples*) &msg;
   1.127 
   1.128         if (pSamples->Samples.GetSize() > 0)
   1.129         {
   1.130             // Just show the first one for now.
   1.131             Color c = pSamples->Samples[0];
   1.132             OVR_DEBUG_LOG(("%d %d %d", c.R, c.G, c.B));
   1.133         }
   1.134         return;
   1.135     }
   1.136 */
   1.137 
   1.138     if (latencyTestMessage == LatencyTest_Timer)
   1.139     {
   1.140         if (!Device)
   1.141         {
   1.142             reset();
   1.143             return;
   1.144         }
   1.145         
   1.146         if (State == State_WaitingForSettlePreCalibrationColorBlack)
   1.147         {
   1.148             // Send calibrate message to device and wait a while.
   1.149             Device->SetCalibrate(CALIBRATE_BLACK);
   1.150 
   1.151             State = State_WaitingForSettlePostCalibrationColorBlack;
   1.152             OVR_DEBUG_LOG(("State_WaitingForSettlePreCalibrationColorBlack -> State_WaitingForSettlePostCalibrationColorBlack."));
   1.153 
   1.154             setTimer(TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION);
   1.155         }
   1.156         else if (State == State_WaitingForSettlePostCalibrationColorBlack)
   1.157         {
   1.158             // Change color to white and wait a while.
   1.159             RenderColor = CALIBRATE_WHITE;
   1.160 
   1.161             State = State_WaitingForSettlePreCalibrationColorWhite;
   1.162             OVR_DEBUG_LOG(("State_WaitingForSettlePostCalibrationColorBlack -> State_WaitingForSettlePreCalibrationColorWhite."));
   1.163 
   1.164             setTimer(TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION);
   1.165         }
   1.166         else if (State == State_WaitingForSettlePreCalibrationColorWhite)
   1.167         {
   1.168             // Send calibrate message to device and wait a while.
   1.169             Device->SetCalibrate(CALIBRATE_WHITE);
   1.170 
   1.171             State = State_WaitingForSettlePostCalibrationColorWhite;
   1.172             OVR_DEBUG_LOG(("State_WaitingForSettlePreCalibrationColorWhite -> State_WaitingForSettlePostCalibrationColorWhite."));
   1.173 
   1.174             setTimer(TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION);
   1.175         }
   1.176         else if (State == State_WaitingForSettlePostCalibrationColorWhite)
   1.177         {
   1.178             // Calibration is done. Switch to color 1 and wait for it to settle.
   1.179             RenderColor = COLOR1;
   1.180 
   1.181             State = State_WaitingForSettlePostMeasurement;
   1.182             OVR_DEBUG_LOG(("State_WaitingForSettlePostCalibrationColorWhite -> State_WaitingForSettlePostMeasurement."));
   1.183 
   1.184             UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS);
   1.185             setTimer(waitTime);
   1.186         }
   1.187         else if (State == State_WaitingForSettlePostMeasurement)
   1.188         {
   1.189             // Prepare for next measurement.
   1.190 
   1.191             // Create a new result object.
   1.192             MeasurementResult* pResult = new MeasurementResult();
   1.193             Results.PushBack(pResult);
   1.194 
   1.195             State = State_WaitingToTakeMeasurement;
   1.196             OVR_DEBUG_LOG(("State_WaitingForSettlePostMeasurement -> State_WaitingToTakeMeasurement."));
   1.197         }
   1.198         else if (State == State_WaitingForTestStarted)
   1.199         {
   1.200             // We timed out waiting for 'TestStarted'. Abandon this measurement and setup for the next.
   1.201             getActiveResult()->TimedOutWaitingForTestStarted = true;
   1.202 
   1.203             State = State_WaitingForSettlePostMeasurement;
   1.204             OVR_DEBUG_LOG(("** Timed out waiting for 'TestStarted'."));
   1.205             OVR_DEBUG_LOG(("State_WaitingForTestStarted -> State_WaitingForSettlePostMeasurement."));
   1.206 
   1.207             UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS);
   1.208             setTimer(waitTime);
   1.209         }
   1.210         else if (State == State_WaitingForColorDetected)
   1.211         {
   1.212             // We timed out waiting for 'ColorDetected'. Abandon this measurement and setup for the next.
   1.213             getActiveResult()->TimedOutWaitingForColorDetected = true;
   1.214 
   1.215             State = State_WaitingForSettlePostMeasurement;
   1.216             OVR_DEBUG_LOG(("** Timed out waiting for 'ColorDetected'."));
   1.217             OVR_DEBUG_LOG(("State_WaitingForColorDetected -> State_WaitingForSettlePostMeasurement."));
   1.218 
   1.219             UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS);
   1.220             setTimer(waitTime);
   1.221         }
   1.222     }
   1.223     else if (latencyTestMessage == LatencyTest_ProcessInputs)
   1.224     {
   1.225         if (State == State_WaitingToTakeMeasurement)
   1.226         {
   1.227             if (!Device)
   1.228             {
   1.229                 reset();
   1.230                 return;
   1.231             }
   1.232             
   1.233             // Send 'StartTest' feature report with opposite target color.
   1.234             if (RenderColor == COLOR1)
   1.235             {
   1.236                 RenderColor = COLOR2;
   1.237             }
   1.238             else
   1.239             {
   1.240                 RenderColor = COLOR1;
   1.241             }
   1.242 
   1.243             getActiveResult()->TargetColor = RenderColor;
   1.244             
   1.245             // Record time so we can determine usb roundtrip time.
   1.246             getActiveResult()->StartTestTicksMicroS = Timer::GetTicks();
   1.247 
   1.248             Device->SetStartTest(RenderColor);
   1.249 
   1.250             State = State_WaitingForTestStarted;
   1.251             OVR_DEBUG_LOG(("State_WaitingToTakeMeasurement -> State_WaitingForTestStarted."));
   1.252 
   1.253             setTimer(TIMEOUT_WAITING_FOR_TEST_STARTED);
   1.254 
   1.255             LatencyTestDisplay ltd(2, 0x40090040);
   1.256             Device->SetDisplay(ltd);
   1.257         }
   1.258     }
   1.259     else if (msg.Type == Message_LatencyTestButton)
   1.260     {
   1.261         BeginTest();
   1.262     }
   1.263     else if (msg.Type == Message_LatencyTestStarted)
   1.264     {
   1.265         if (State == State_WaitingForTestStarted)
   1.266         {
   1.267             clearTimer();
   1.268 
   1.269             // Record time so we can determine usb roundtrip time.
   1.270             getActiveResult()->TestStartedTicksMicroS = Timer::GetTicks();
   1.271             
   1.272             State = State_WaitingForColorDetected;
   1.273             OVR_DEBUG_LOG(("State_WaitingForTestStarted -> State_WaitingForColorDetected."));
   1.274 
   1.275             setTimer(TIMEOUT_WAITING_FOR_COLOR_DETECTED);
   1.276         }
   1.277     }
   1.278     else if (msg.Type == Message_LatencyTestColorDetected)
   1.279     {
   1.280         if (State == State_WaitingForColorDetected)
   1.281         {
   1.282             // Record time to detect color.
   1.283             MessageLatencyTestColorDetected* pDetected = (MessageLatencyTestColorDetected*) &msg;
   1.284             UInt16 elapsedTime = pDetected->Elapsed;
   1.285             OVR_DEBUG_LOG(("Time to 'ColorDetected' = %d", elapsedTime));
   1.286             
   1.287             getActiveResult()->DeviceMeasuredElapsedMilliS = elapsedTime;
   1.288 
   1.289             if (areResultsComplete())
   1.290             {
   1.291                 // We're done.
   1.292                 processResults();
   1.293                 reset();
   1.294             }
   1.295             else
   1.296             {
   1.297                 // Run another measurement.
   1.298                 State = State_WaitingForSettlePostMeasurement;
   1.299                 OVR_DEBUG_LOG(("State_WaitingForColorDetected -> State_WaitingForSettlePostMeasurement."));
   1.300 
   1.301                 UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS);
   1.302                 setTimer(waitTime);
   1.303 
   1.304                 LatencyTestDisplay ltd(2, 0x40400040);
   1.305                 Device->SetDisplay(ltd);
   1.306             }
   1.307         }
   1.308     }
   1.309     else if (msg.Type == Message_DeviceRemoved)
   1.310     {
   1.311         reset();
   1.312     }
   1.313 }
   1.314 
   1.315 LatencyTest::MeasurementResult* LatencyTest::getActiveResult()
   1.316 {
   1.317     OVR_ASSERT(!Results.IsEmpty());    
   1.318     return Results.GetLast();
   1.319 }
   1.320 
   1.321 void LatencyTest::setTimer(UInt32 timeMilliS)
   1.322 {
   1.323     ActiveTimerMilliS = timeMilliS;
   1.324 }
   1.325 
   1.326 void LatencyTest::clearTimer()
   1.327 {
   1.328     ActiveTimerMilliS = 0;
   1.329 }
   1.330 
   1.331 void LatencyTest::reset()
   1.332 {
   1.333     clearMeasurementResults();
   1.334     State = State_WaitingForButton;
   1.335 
   1.336     HaveOldTime = false;
   1.337     ActiveTimerMilliS = 0;
   1.338 }
   1.339 
   1.340 void LatencyTest::clearMeasurementResults()
   1.341 {
   1.342     while(!Results.IsEmpty())
   1.343     {
   1.344         MeasurementResult* pElem = Results.GetFirst();
   1.345         pElem->RemoveNode();
   1.346         delete pElem;
   1.347     }
   1.348 }
   1.349 
   1.350 LatencyTest::LatencyTestHandler::~LatencyTestHandler()
   1.351 {
   1.352     RemoveHandlerFromDevices();
   1.353 }
   1.354 
   1.355 void LatencyTest::LatencyTestHandler::OnMessage(const Message& msg)
   1.356 {
   1.357     pLatencyTestUtil->handleMessage(msg);
   1.358 }
   1.359 
   1.360 void LatencyTest::ProcessInputs()
   1.361 {
   1.362     updateForTimeouts();
   1.363     handleMessage(Message(), LatencyTest_ProcessInputs);
   1.364 }
   1.365 
   1.366 bool LatencyTest::DisplayScreenColor(Color& colorToDisplay)
   1.367 {
   1.368     updateForTimeouts();
   1.369 
   1.370     if (State == State_WaitingForButton)
   1.371     {
   1.372         return false;
   1.373     }
   1.374 
   1.375     colorToDisplay = RenderColor;
   1.376     return true;
   1.377 }
   1.378 
   1.379 const char*	LatencyTest::GetResultsString()
   1.380 {
   1.381 	if (!ResultsString.IsEmpty() && ReturnedResultString != ResultsString.ToCStr())
   1.382 	{
   1.383 		ReturnedResultString = ResultsString;
   1.384 		return ReturnedResultString.ToCStr();
   1.385 	}
   1.386     
   1.387 	return NULL;
   1.388 }
   1.389 
   1.390 bool LatencyTest::areResultsComplete()
   1.391 {
   1.392     UInt32 initialMeasurements = 0;
   1.393 
   1.394     UInt32 measurements1to2 = 0;
   1.395     UInt32 measurements2to1 = 0;
   1.396 
   1.397     MeasurementResult* pCurr = Results.GetFirst();
   1.398     while(true)
   1.399     {
   1.400         // Process.
   1.401         if (!pCurr->TimedOutWaitingForTestStarted &&
   1.402             !pCurr->TimedOutWaitingForColorDetected)
   1.403         {
   1.404             initialMeasurements++;
   1.405 
   1.406             if (initialMeasurements > INITIAL_SAMPLES_TO_IGNORE)
   1.407             {
   1.408                 if (pCurr->TargetColor == COLOR2)
   1.409                 {
   1.410                     measurements1to2++;
   1.411                 }
   1.412                 else
   1.413                 {
   1.414                     measurements2to1++;
   1.415                 }
   1.416             }
   1.417         }
   1.418 
   1.419         if (Results.IsLast(pCurr))
   1.420         {
   1.421             break;
   1.422         }
   1.423         pCurr = Results.GetNext(pCurr);
   1.424     }
   1.425 
   1.426     if (measurements1to2 >= DEFAULT_NUMBER_OF_SAMPLES &&
   1.427         measurements2to1 >= DEFAULT_NUMBER_OF_SAMPLES)
   1.428     {
   1.429         return true;
   1.430     }
   1.431 
   1.432     return false;
   1.433 }
   1.434 
   1.435 void LatencyTest::processResults()
   1.436 {
   1.437 
   1.438     UInt32 minTime1To2 = UINT_MAX;
   1.439     UInt32 maxTime1To2 = 0;
   1.440     float averageTime1To2 = 0.0f;
   1.441     UInt32 minTime2To1 = UINT_MAX;
   1.442     UInt32 maxTime2To1 = 0;
   1.443     float averageTime2To1 = 0.0f;
   1.444 
   1.445     float minUSBTripMilliS = BIG_FLOAT;
   1.446     float maxUSBTripMilliS = SMALL_FLOAT;
   1.447     float averageUSBTripMilliS = 0.0f;
   1.448     UInt32 countUSBTripTime = 0;
   1.449 
   1.450     UInt32 measurementsCount = 0;
   1.451     UInt32 measurements1to2 = 0;
   1.452     UInt32 measurements2to1 = 0;
   1.453 
   1.454     MeasurementResult* pCurr = Results.GetFirst();
   1.455     UInt32 count = 0;
   1.456     while(true)
   1.457     {
   1.458         count++;
   1.459 
   1.460         if (!pCurr->TimedOutWaitingForTestStarted &&
   1.461             !pCurr->TimedOutWaitingForColorDetected)
   1.462         {
   1.463             measurementsCount++;
   1.464 
   1.465             if (measurementsCount > INITIAL_SAMPLES_TO_IGNORE)
   1.466             {
   1.467                 if (pCurr->TargetColor == COLOR2)
   1.468                 {
   1.469                     measurements1to2++;
   1.470 
   1.471                     if (measurements1to2 <= DEFAULT_NUMBER_OF_SAMPLES)
   1.472                     {
   1.473                         UInt32 elapsed = pCurr->DeviceMeasuredElapsedMilliS;
   1.474 
   1.475                         minTime1To2 = Alg::Min(elapsed, minTime1To2);
   1.476                         maxTime1To2 = Alg::Max(elapsed, maxTime1To2);
   1.477 
   1.478                         averageTime1To2 += (float) elapsed;
   1.479                     }
   1.480                 }
   1.481                 else
   1.482                 {
   1.483                     measurements2to1++;
   1.484 
   1.485                     if (measurements2to1 <= DEFAULT_NUMBER_OF_SAMPLES)
   1.486                     {
   1.487                         UInt32 elapsed = pCurr->DeviceMeasuredElapsedMilliS;
   1.488 
   1.489                         minTime2To1 = Alg::Min(elapsed, minTime2To1);
   1.490                         maxTime2To1 = Alg::Max(elapsed, maxTime2To1);
   1.491 
   1.492                         averageTime2To1 += (float) elapsed;
   1.493                     }
   1.494                 }
   1.495 
   1.496                 float usbRountripElapsedMilliS = 0.001f * (float) (pCurr->TestStartedTicksMicroS - pCurr->StartTestTicksMicroS);
   1.497                 minUSBTripMilliS = Alg::Min(usbRountripElapsedMilliS, minUSBTripMilliS);
   1.498                 maxUSBTripMilliS = Alg::Max(usbRountripElapsedMilliS, maxUSBTripMilliS);
   1.499                 averageUSBTripMilliS += usbRountripElapsedMilliS;
   1.500                 countUSBTripTime++;
   1.501             }
   1.502         }
   1.503 
   1.504         if (measurements1to2 >= DEFAULT_NUMBER_OF_SAMPLES &&
   1.505             measurements2to1 >= DEFAULT_NUMBER_OF_SAMPLES)
   1.506         {
   1.507             break;
   1.508         }
   1.509 
   1.510         if (Results.IsLast(pCurr))
   1.511         {
   1.512             break;
   1.513         }
   1.514         pCurr = Results.GetNext(pCurr);
   1.515     }
   1.516 
   1.517     averageTime1To2 /= (float) DEFAULT_NUMBER_OF_SAMPLES;      
   1.518     averageTime2To1 /= (float) DEFAULT_NUMBER_OF_SAMPLES;
   1.519 
   1.520     averageUSBTripMilliS /= countUSBTripTime;
   1.521     
   1.522     float finalResult = 0.5f * (averageTime1To2 + averageTime2To1);
   1.523     finalResult += averageUSBTripMilliS;
   1.524 
   1.525     ResultsString.Clear();
   1.526     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]",  
   1.527                 finalResult, 
   1.528                 minTime1To2, averageTime1To2, maxTime1To2, 
   1.529                 minTime2To1, averageTime2To1, maxTime2To1,
   1.530                 minUSBTripMilliS, averageUSBTripMilliS, maxUSBTripMilliS,
   1.531                 DEFAULT_NUMBER_OF_SAMPLES*2, count - measurementsCount);
   1.532     
   1.533     // Display result on latency tester display.
   1.534     LatencyTestDisplay ltd(1, (int)finalResult);
   1.535     Device->SetDisplay(ltd);
   1.536 }
   1.537 
   1.538 void LatencyTest::updateForTimeouts()
   1.539 {
   1.540     if (!HaveOldTime)
   1.541     {
   1.542         HaveOldTime = true;
   1.543         OldTime = Timer::GetTicksMs();
   1.544         return;
   1.545     }
   1.546 
   1.547     UInt32 newTime = Timer::GetTicksMs();
   1.548     UInt32 elapsedMilliS = newTime - OldTime;
   1.549     if (newTime < OldTime)
   1.550     {
   1.551         elapsedMilliS = OldTime - newTime;
   1.552         elapsedMilliS = UINT_MAX - elapsedMilliS;
   1.553     }
   1.554     OldTime = newTime;
   1.555 
   1.556     elapsedMilliS = Alg::Min(elapsedMilliS, (UInt32) 100);   // Clamp at 100mS in case we're not being called very often.
   1.557 
   1.558 
   1.559     if (ActiveTimerMilliS == 0)
   1.560     {
   1.561         return;
   1.562     }
   1.563 
   1.564     if (elapsedMilliS >= ActiveTimerMilliS)
   1.565     {
   1.566         ActiveTimerMilliS = 0;
   1.567         handleMessage(Message(), LatencyTest_Timer);
   1.568         return;
   1.569     }
   1.570 
   1.571     ActiveTimerMilliS -= elapsedMilliS;
   1.572 }
   1.573 
   1.574 }} // namespace OVR::Util
   1.575 \ No newline at end of file
   1.576 +/************************************************************************************
   1.577 +
   1.578 +Filename    :   Util_LatencyTest.cpp
   1.579 +Content     :   Wraps the lower level LatencyTester interface and adds functionality.
   1.580 +Created     :   February 14, 2013
   1.581 +Authors     :   Lee Cooper
   1.582 +
   1.583 +Copyright   :   Copyright 2013 Oculus VR, Inc. All Rights reserved.
   1.584 +
   1.585 +Use of this software is subject to the terms of the Oculus license
   1.586 +agreement provided at the time of installation or download, or which
   1.587 +otherwise accompanies this software in either electronic or hard copy form.
   1.588 +
   1.589 +*************************************************************************************/
   1.590 +
   1.591 +#include "Util_LatencyTest.h"
   1.592 +
   1.593 +#include "../Kernel/OVR_Log.h"
   1.594 +#include "../Kernel/OVR_Timer.h"
   1.595 +
   1.596 +namespace OVR { namespace Util {
   1.597 +
   1.598 +static const UInt32     TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION = 16*10;
   1.599 +static const UInt32     TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION = 16*10;
   1.600 +static const UInt32     TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT = 16*5;
   1.601 +static const UInt32     TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS = 16*5;
   1.602 +static const UInt32     DEFAULT_NUMBER_OF_SAMPLES = 10;                 // For both color 1->2 and color 2->1 transitions.
   1.603 +static const UInt32     INITIAL_SAMPLES_TO_IGNORE = 4;
   1.604 +static const UInt32     TIMEOUT_WAITING_FOR_TEST_STARTED = 1000;
   1.605 +static const UInt32     TIMEOUT_WAITING_FOR_COLOR_DETECTED = 4000;
   1.606 +static const Color      CALIBRATE_BLACK(0, 0, 0);
   1.607 +static const Color      CALIBRATE_WHITE(255, 255, 255);
   1.608 +static const Color      COLOR1(0, 0, 0);
   1.609 +static const Color      COLOR2(255, 255, 255);
   1.610 +static const Color      SENSOR_DETECT_THRESHOLD(128, 255, 255);
   1.611 +static const float      BIG_FLOAT = 1000000.0f;
   1.612 +static const float      SMALL_FLOAT = -1000000.0f;
   1.613 +
   1.614 +//-------------------------------------------------------------------------------------
   1.615 +// ***** LatencyTest
   1.616 +
   1.617 +LatencyTest::LatencyTest(LatencyTestDevice* device)
   1.618 + :  Handler(getThis())
   1.619 +{
   1.620 +    if (device != NULL)
   1.621 +    {
   1.622 +        SetDevice(device);
   1.623 +    }
   1.624 +
   1.625 +    reset();
   1.626 +
   1.627 +    srand(Timer::GetTicksMs());
   1.628 +}
   1.629 +
   1.630 +LatencyTest::~LatencyTest()
   1.631 +{
   1.632 +     clearMeasurementResults();
   1.633 +}
   1.634 +
   1.635 +bool LatencyTest::SetDevice(LatencyTestDevice* device)
   1.636 +{
   1.637 +
   1.638 +    if (device != Device)
   1.639 +    {
   1.640 +        if (device != NULL)
   1.641 +        {
   1.642 +            if (device->GetMessageHandler() != NULL)
   1.643 +            {
   1.644 +                OVR_DEBUG_LOG(
   1.645 +                    ("LatencyTest::AttachToDevice failed - device %p already has handler", device));
   1.646 +                return false;
   1.647 +            }
   1.648 +        }
   1.649 +
   1.650 +        if (Device != NULL)
   1.651 +        {
   1.652 +            Device->SetMessageHandler(0);
   1.653 +        }
   1.654 +        Device = device;
   1.655 +
   1.656 +        if (Device != NULL)
   1.657 +        {
   1.658 +            Device->SetMessageHandler(&Handler);
   1.659 +
   1.660 +            // Set trigger threshold.
   1.661 +            LatencyTestConfiguration configuration(SENSOR_DETECT_THRESHOLD, false);     // No samples streaming.
   1.662 +            Device->SetConfiguration(configuration, true);
   1.663 +
   1.664 +            // Set display to intial (3 dashes).
   1.665 +            LatencyTestDisplay ltd(2, 0x40400040);
   1.666 +            Device->SetDisplay(ltd);
   1.667 +        }
   1.668 +    }
   1.669 +
   1.670 +    return true;
   1.671 +}
   1.672 +
   1.673 +UInt32 LatencyTest::getRandomComponent(UInt32 range)
   1.674 +{
   1.675 +    UInt32 val = rand() % range;
   1.676 +    return val;
   1.677 +}
   1.678 +
   1.679 +void LatencyTest::BeginTest()
   1.680 +{
   1.681 +     if (State == State_WaitingForButton)
   1.682 +    {
   1.683 +        // Set color to black and wait a while.
   1.684 +        RenderColor = CALIBRATE_BLACK;
   1.685 +
   1.686 +        State = State_WaitingForSettlePreCalibrationColorBlack;
   1.687 +        OVR_DEBUG_LOG(("State_WaitingForButton -> State_WaitingForSettlePreCalibrationColorBlack."));
   1.688 +
   1.689 +        setTimer(TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION);
   1.690 +    }
   1.691 +}
   1.692 +
   1.693 +void LatencyTest::handleMessage(const Message& msg, LatencyTestMessageType latencyTestMessage)
   1.694 +{
   1.695 +    // For debugging.
   1.696 +/*  if (msg.Type == Message_LatencyTestSamples)
   1.697 +    {
   1.698 +        MessageLatencyTestSamples* pSamples = (MessageLatencyTestSamples*) &msg;
   1.699 +
   1.700 +        if (pSamples->Samples.GetSize() > 0)
   1.701 +        {
   1.702 +            // Just show the first one for now.
   1.703 +            Color c = pSamples->Samples[0];
   1.704 +            OVR_DEBUG_LOG(("%d %d %d", c.R, c.G, c.B));
   1.705 +        }
   1.706 +        return;
   1.707 +    }
   1.708 +*/
   1.709 +
   1.710 +    if (latencyTestMessage == LatencyTest_Timer)
   1.711 +    {
   1.712 +        if (!Device)
   1.713 +        {
   1.714 +            reset();
   1.715 +            return;
   1.716 +        }
   1.717 +        
   1.718 +        if (State == State_WaitingForSettlePreCalibrationColorBlack)
   1.719 +        {
   1.720 +            // Send calibrate message to device and wait a while.
   1.721 +            Device->SetCalibrate(CALIBRATE_BLACK);
   1.722 +
   1.723 +            State = State_WaitingForSettlePostCalibrationColorBlack;
   1.724 +            OVR_DEBUG_LOG(("State_WaitingForSettlePreCalibrationColorBlack -> State_WaitingForSettlePostCalibrationColorBlack."));
   1.725 +
   1.726 +            setTimer(TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION);
   1.727 +        }
   1.728 +        else if (State == State_WaitingForSettlePostCalibrationColorBlack)
   1.729 +        {
   1.730 +            // Change color to white and wait a while.
   1.731 +            RenderColor = CALIBRATE_WHITE;
   1.732 +
   1.733 +            State = State_WaitingForSettlePreCalibrationColorWhite;
   1.734 +            OVR_DEBUG_LOG(("State_WaitingForSettlePostCalibrationColorBlack -> State_WaitingForSettlePreCalibrationColorWhite."));
   1.735 +
   1.736 +            setTimer(TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION);
   1.737 +        }
   1.738 +        else if (State == State_WaitingForSettlePreCalibrationColorWhite)
   1.739 +        {
   1.740 +            // Send calibrate message to device and wait a while.
   1.741 +            Device->SetCalibrate(CALIBRATE_WHITE);
   1.742 +
   1.743 +            State = State_WaitingForSettlePostCalibrationColorWhite;
   1.744 +            OVR_DEBUG_LOG(("State_WaitingForSettlePreCalibrationColorWhite -> State_WaitingForSettlePostCalibrationColorWhite."));
   1.745 +
   1.746 +            setTimer(TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION);
   1.747 +        }
   1.748 +        else if (State == State_WaitingForSettlePostCalibrationColorWhite)
   1.749 +        {
   1.750 +            // Calibration is done. Switch to color 1 and wait for it to settle.
   1.751 +            RenderColor = COLOR1;
   1.752 +
   1.753 +            State = State_WaitingForSettlePostMeasurement;
   1.754 +            OVR_DEBUG_LOG(("State_WaitingForSettlePostCalibrationColorWhite -> State_WaitingForSettlePostMeasurement."));
   1.755 +
   1.756 +            UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS);
   1.757 +            setTimer(waitTime);
   1.758 +        }
   1.759 +        else if (State == State_WaitingForSettlePostMeasurement)
   1.760 +        {
   1.761 +            // Prepare for next measurement.
   1.762 +
   1.763 +            // Create a new result object.
   1.764 +            MeasurementResult* pResult = new MeasurementResult();
   1.765 +            Results.PushBack(pResult);
   1.766 +
   1.767 +            State = State_WaitingToTakeMeasurement;
   1.768 +            OVR_DEBUG_LOG(("State_WaitingForSettlePostMeasurement -> State_WaitingToTakeMeasurement."));
   1.769 +        }
   1.770 +        else if (State == State_WaitingForTestStarted)
   1.771 +        {
   1.772 +            // We timed out waiting for 'TestStarted'. Abandon this measurement and setup for the next.
   1.773 +            getActiveResult()->TimedOutWaitingForTestStarted = true;
   1.774 +
   1.775 +            State = State_WaitingForSettlePostMeasurement;
   1.776 +            OVR_DEBUG_LOG(("** Timed out waiting for 'TestStarted'."));
   1.777 +            OVR_DEBUG_LOG(("State_WaitingForTestStarted -> State_WaitingForSettlePostMeasurement."));
   1.778 +
   1.779 +            UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS);
   1.780 +            setTimer(waitTime);
   1.781 +        }
   1.782 +        else if (State == State_WaitingForColorDetected)
   1.783 +        {
   1.784 +            // We timed out waiting for 'ColorDetected'. Abandon this measurement and setup for the next.
   1.785 +            getActiveResult()->TimedOutWaitingForColorDetected = true;
   1.786 +
   1.787 +            State = State_WaitingForSettlePostMeasurement;
   1.788 +            OVR_DEBUG_LOG(("** Timed out waiting for 'ColorDetected'."));
   1.789 +            OVR_DEBUG_LOG(("State_WaitingForColorDetected -> State_WaitingForSettlePostMeasurement."));
   1.790 +
   1.791 +            UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS);
   1.792 +            setTimer(waitTime);
   1.793 +        }
   1.794 +    }
   1.795 +    else if (latencyTestMessage == LatencyTest_ProcessInputs)
   1.796 +    {
   1.797 +        if (State == State_WaitingToTakeMeasurement)
   1.798 +        {
   1.799 +            if (!Device)
   1.800 +            {
   1.801 +                reset();
   1.802 +                return;
   1.803 +            }
   1.804 +            
   1.805 +            // Send 'StartTest' feature report with opposite target color.
   1.806 +            if (RenderColor == COLOR1)
   1.807 +            {
   1.808 +                RenderColor = COLOR2;
   1.809 +            }
   1.810 +            else
   1.811 +            {
   1.812 +                RenderColor = COLOR1;
   1.813 +            }
   1.814 +
   1.815 +            getActiveResult()->TargetColor = RenderColor;
   1.816 +            
   1.817 +            // Record time so we can determine usb roundtrip time.
   1.818 +            getActiveResult()->StartTestTicksMicroS = Timer::GetTicks();
   1.819 +
   1.820 +            Device->SetStartTest(RenderColor);
   1.821 +
   1.822 +            State = State_WaitingForTestStarted;
   1.823 +            OVR_DEBUG_LOG(("State_WaitingToTakeMeasurement -> State_WaitingForTestStarted."));
   1.824 +
   1.825 +            setTimer(TIMEOUT_WAITING_FOR_TEST_STARTED);
   1.826 +
   1.827 +            LatencyTestDisplay ltd(2, 0x40090040);
   1.828 +            Device->SetDisplay(ltd);
   1.829 +        }
   1.830 +    }
   1.831 +    else if (msg.Type == Message_LatencyTestButton)
   1.832 +    {
   1.833 +        BeginTest();
   1.834 +    }
   1.835 +    else if (msg.Type == Message_LatencyTestStarted)
   1.836 +    {
   1.837 +        if (State == State_WaitingForTestStarted)
   1.838 +        {
   1.839 +            clearTimer();
   1.840 +
   1.841 +            // Record time so we can determine usb roundtrip time.
   1.842 +            getActiveResult()->TestStartedTicksMicroS = Timer::GetTicks();
   1.843 +            
   1.844 +            State = State_WaitingForColorDetected;
   1.845 +            OVR_DEBUG_LOG(("State_WaitingForTestStarted -> State_WaitingForColorDetected."));
   1.846 +
   1.847 +            setTimer(TIMEOUT_WAITING_FOR_COLOR_DETECTED);
   1.848 +        }
   1.849 +    }
   1.850 +    else if (msg.Type == Message_LatencyTestColorDetected)
   1.851 +    {
   1.852 +        if (State == State_WaitingForColorDetected)
   1.853 +        {
   1.854 +            // Record time to detect color.
   1.855 +            MessageLatencyTestColorDetected* pDetected = (MessageLatencyTestColorDetected*) &msg;
   1.856 +            UInt16 elapsedTime = pDetected->Elapsed;
   1.857 +            OVR_DEBUG_LOG(("Time to 'ColorDetected' = %d", elapsedTime));
   1.858 +            
   1.859 +            getActiveResult()->DeviceMeasuredElapsedMilliS = elapsedTime;
   1.860 +
   1.861 +            if (areResultsComplete())
   1.862 +            {
   1.863 +                // We're done.
   1.864 +                processResults();
   1.865 +                reset();
   1.866 +            }
   1.867 +            else
   1.868 +            {
   1.869 +                // Run another measurement.
   1.870 +                State = State_WaitingForSettlePostMeasurement;
   1.871 +                OVR_DEBUG_LOG(("State_WaitingForColorDetected -> State_WaitingForSettlePostMeasurement."));
   1.872 +
   1.873 +                UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS);
   1.874 +                setTimer(waitTime);
   1.875 +
   1.876 +                LatencyTestDisplay ltd(2, 0x40400040);
   1.877 +                Device->SetDisplay(ltd);
   1.878 +            }
   1.879 +        }
   1.880 +    }
   1.881 +    else if (msg.Type == Message_DeviceRemoved)
   1.882 +    {
   1.883 +        reset();
   1.884 +    }
   1.885 +}
   1.886 +
   1.887 +LatencyTest::MeasurementResult* LatencyTest::getActiveResult()
   1.888 +{
   1.889 +    OVR_ASSERT(!Results.IsEmpty());    
   1.890 +    return Results.GetLast();
   1.891 +}
   1.892 +
   1.893 +void LatencyTest::setTimer(UInt32 timeMilliS)
   1.894 +{
   1.895 +    ActiveTimerMilliS = timeMilliS;
   1.896 +}
   1.897 +
   1.898 +void LatencyTest::clearTimer()
   1.899 +{
   1.900 +    ActiveTimerMilliS = 0;
   1.901 +}
   1.902 +
   1.903 +void LatencyTest::reset()
   1.904 +{
   1.905 +    clearMeasurementResults();
   1.906 +    State = State_WaitingForButton;
   1.907 +
   1.908 +    HaveOldTime = false;
   1.909 +    ActiveTimerMilliS = 0;
   1.910 +}
   1.911 +
   1.912 +void LatencyTest::clearMeasurementResults()
   1.913 +{
   1.914 +    while(!Results.IsEmpty())
   1.915 +    {
   1.916 +        MeasurementResult* pElem = Results.GetFirst();
   1.917 +        pElem->RemoveNode();
   1.918 +        delete pElem;
   1.919 +    }
   1.920 +}
   1.921 +
   1.922 +LatencyTest::LatencyTestHandler::~LatencyTestHandler()
   1.923 +{
   1.924 +    RemoveHandlerFromDevices();
   1.925 +}
   1.926 +
   1.927 +void LatencyTest::LatencyTestHandler::OnMessage(const Message& msg)
   1.928 +{
   1.929 +    pLatencyTestUtil->handleMessage(msg);
   1.930 +}
   1.931 +
   1.932 +void LatencyTest::ProcessInputs()
   1.933 +{
   1.934 +    updateForTimeouts();
   1.935 +    handleMessage(Message(), LatencyTest_ProcessInputs);
   1.936 +}
   1.937 +
   1.938 +bool LatencyTest::DisplayScreenColor(Color& colorToDisplay)
   1.939 +{
   1.940 +    updateForTimeouts();
   1.941 +
   1.942 +    if (State == State_WaitingForButton)
   1.943 +    {
   1.944 +        return false;
   1.945 +    }
   1.946 +
   1.947 +    colorToDisplay = RenderColor;
   1.948 +    return true;
   1.949 +}
   1.950 +
   1.951 +const char*	LatencyTest::GetResultsString()
   1.952 +{
   1.953 +	if (!ResultsString.IsEmpty() && ReturnedResultString != ResultsString.ToCStr())
   1.954 +	{
   1.955 +		ReturnedResultString = ResultsString;
   1.956 +		return ReturnedResultString.ToCStr();
   1.957 +	}
   1.958 +    
   1.959 +	return NULL;
   1.960 +}
   1.961 +
   1.962 +bool LatencyTest::areResultsComplete()
   1.963 +{
   1.964 +    UInt32 initialMeasurements = 0;
   1.965 +
   1.966 +    UInt32 measurements1to2 = 0;
   1.967 +    UInt32 measurements2to1 = 0;
   1.968 +
   1.969 +    MeasurementResult* pCurr = Results.GetFirst();
   1.970 +    while(true)
   1.971 +    {
   1.972 +        // Process.
   1.973 +        if (!pCurr->TimedOutWaitingForTestStarted &&
   1.974 +            !pCurr->TimedOutWaitingForColorDetected)
   1.975 +        {
   1.976 +            initialMeasurements++;
   1.977 +
   1.978 +            if (initialMeasurements > INITIAL_SAMPLES_TO_IGNORE)
   1.979 +            {
   1.980 +                if (pCurr->TargetColor == COLOR2)
   1.981 +                {
   1.982 +                    measurements1to2++;
   1.983 +                }
   1.984 +                else
   1.985 +                {
   1.986 +                    measurements2to1++;
   1.987 +                }
   1.988 +            }
   1.989 +        }
   1.990 +
   1.991 +        if (Results.IsLast(pCurr))
   1.992 +        {
   1.993 +            break;
   1.994 +        }
   1.995 +        pCurr = Results.GetNext(pCurr);
   1.996 +    }
   1.997 +
   1.998 +    if (measurements1to2 >= DEFAULT_NUMBER_OF_SAMPLES &&
   1.999 +        measurements2to1 >= DEFAULT_NUMBER_OF_SAMPLES)
  1.1000 +    {
  1.1001 +        return true;
  1.1002 +    }
  1.1003 +
  1.1004 +    return false;
  1.1005 +}
  1.1006 +
  1.1007 +void LatencyTest::processResults()
  1.1008 +{
  1.1009 +
  1.1010 +    UInt32 minTime1To2 = UINT_MAX;
  1.1011 +    UInt32 maxTime1To2 = 0;
  1.1012 +    float averageTime1To2 = 0.0f;
  1.1013 +    UInt32 minTime2To1 = UINT_MAX;
  1.1014 +    UInt32 maxTime2To1 = 0;
  1.1015 +    float averageTime2To1 = 0.0f;
  1.1016 +
  1.1017 +    float minUSBTripMilliS = BIG_FLOAT;
  1.1018 +    float maxUSBTripMilliS = SMALL_FLOAT;
  1.1019 +    float averageUSBTripMilliS = 0.0f;
  1.1020 +    UInt32 countUSBTripTime = 0;
  1.1021 +
  1.1022 +    UInt32 measurementsCount = 0;
  1.1023 +    UInt32 measurements1to2 = 0;
  1.1024 +    UInt32 measurements2to1 = 0;
  1.1025 +
  1.1026 +    MeasurementResult* pCurr = Results.GetFirst();
  1.1027 +    UInt32 count = 0;
  1.1028 +    while(true)
  1.1029 +    {
  1.1030 +        count++;
  1.1031 +
  1.1032 +        if (!pCurr->TimedOutWaitingForTestStarted &&
  1.1033 +            !pCurr->TimedOutWaitingForColorDetected)
  1.1034 +        {
  1.1035 +            measurementsCount++;
  1.1036 +
  1.1037 +            if (measurementsCount > INITIAL_SAMPLES_TO_IGNORE)
  1.1038 +            {
  1.1039 +                if (pCurr->TargetColor == COLOR2)
  1.1040 +                {
  1.1041 +                    measurements1to2++;
  1.1042 +
  1.1043 +                    if (measurements1to2 <= DEFAULT_NUMBER_OF_SAMPLES)
  1.1044 +                    {
  1.1045 +                        UInt32 elapsed = pCurr->DeviceMeasuredElapsedMilliS;
  1.1046 +
  1.1047 +                        minTime1To2 = Alg::Min(elapsed, minTime1To2);
  1.1048 +                        maxTime1To2 = Alg::Max(elapsed, maxTime1To2);
  1.1049 +
  1.1050 +                        averageTime1To2 += (float) elapsed;
  1.1051 +                    }
  1.1052 +                }
  1.1053 +                else
  1.1054 +                {
  1.1055 +                    measurements2to1++;
  1.1056 +
  1.1057 +                    if (measurements2to1 <= DEFAULT_NUMBER_OF_SAMPLES)
  1.1058 +                    {
  1.1059 +                        UInt32 elapsed = pCurr->DeviceMeasuredElapsedMilliS;
  1.1060 +
  1.1061 +                        minTime2To1 = Alg::Min(elapsed, minTime2To1);
  1.1062 +                        maxTime2To1 = Alg::Max(elapsed, maxTime2To1);
  1.1063 +
  1.1064 +                        averageTime2To1 += (float) elapsed;
  1.1065 +                    }
  1.1066 +                }
  1.1067 +
  1.1068 +                float usbRountripElapsedMilliS = 0.001f * (float) (pCurr->TestStartedTicksMicroS - pCurr->StartTestTicksMicroS);
  1.1069 +                minUSBTripMilliS = Alg::Min(usbRountripElapsedMilliS, minUSBTripMilliS);
  1.1070 +                maxUSBTripMilliS = Alg::Max(usbRountripElapsedMilliS, maxUSBTripMilliS);
  1.1071 +                averageUSBTripMilliS += usbRountripElapsedMilliS;
  1.1072 +                countUSBTripTime++;
  1.1073 +            }
  1.1074 +        }
  1.1075 +
  1.1076 +        if (measurements1to2 >= DEFAULT_NUMBER_OF_SAMPLES &&
  1.1077 +            measurements2to1 >= DEFAULT_NUMBER_OF_SAMPLES)
  1.1078 +        {
  1.1079 +            break;
  1.1080 +        }
  1.1081 +
  1.1082 +        if (Results.IsLast(pCurr))
  1.1083 +        {
  1.1084 +            break;
  1.1085 +        }
  1.1086 +        pCurr = Results.GetNext(pCurr);
  1.1087 +    }
  1.1088 +
  1.1089 +    averageTime1To2 /= (float) DEFAULT_NUMBER_OF_SAMPLES;      
  1.1090 +    averageTime2To1 /= (float) DEFAULT_NUMBER_OF_SAMPLES;
  1.1091 +
  1.1092 +    averageUSBTripMilliS /= countUSBTripTime;
  1.1093 +    
  1.1094 +    float finalResult = 0.5f * (averageTime1To2 + averageTime2To1);
  1.1095 +    finalResult += averageUSBTripMilliS;
  1.1096 +
  1.1097 +    ResultsString.Clear();
  1.1098 +    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]",  
  1.1099 +                finalResult, 
  1.1100 +                minTime1To2, averageTime1To2, maxTime1To2, 
  1.1101 +                minTime2To1, averageTime2To1, maxTime2To1,
  1.1102 +                minUSBTripMilliS, averageUSBTripMilliS, maxUSBTripMilliS,
  1.1103 +                DEFAULT_NUMBER_OF_SAMPLES*2, count - measurementsCount);
  1.1104 +    
  1.1105 +    // Display result on latency tester display.
  1.1106 +    LatencyTestDisplay ltd(1, (int)finalResult);
  1.1107 +    Device->SetDisplay(ltd);
  1.1108 +}
  1.1109 +
  1.1110 +void LatencyTest::updateForTimeouts()
  1.1111 +{
  1.1112 +    if (!HaveOldTime)
  1.1113 +    {
  1.1114 +        HaveOldTime = true;
  1.1115 +        OldTime = Timer::GetTicksMs();
  1.1116 +        return;
  1.1117 +    }
  1.1118 +
  1.1119 +    UInt32 newTime = Timer::GetTicksMs();
  1.1120 +    UInt32 elapsedMilliS = newTime - OldTime;
  1.1121 +    if (newTime < OldTime)
  1.1122 +    {
  1.1123 +        elapsedMilliS = OldTime - newTime;
  1.1124 +        elapsedMilliS = UINT_MAX - elapsedMilliS;
  1.1125 +    }
  1.1126 +    OldTime = newTime;
  1.1127 +
  1.1128 +    elapsedMilliS = Alg::Min(elapsedMilliS, (UInt32) 100);   // Clamp at 100mS in case we're not being called very often.
  1.1129 +
  1.1130 +
  1.1131 +    if (ActiveTimerMilliS == 0)
  1.1132 +    {
  1.1133 +        return;
  1.1134 +    }
  1.1135 +
  1.1136 +    if (elapsedMilliS >= ActiveTimerMilliS)
  1.1137 +    {
  1.1138 +        ActiveTimerMilliS = 0;
  1.1139 +        handleMessage(Message(), LatencyTest_Timer);
  1.1140 +        return;
  1.1141 +    }
  1.1142 +
  1.1143 +    ActiveTimerMilliS -= elapsedMilliS;
  1.1144 +}
  1.1145 +
  1.1146 +}} // namespace OVR::Util