Skip to content

Commit

Permalink
Structural changes to handle edge cases better when starting and stop…
Browse files Browse the repository at this point in the history
…ping tracking

StartTracker now returns bool indicating success. Only does anything meaningful in SmartEye right now.

Similarly, CalibrationResult now has an IsValid method.

Main window should now respond gracefully to a tracker failing to start (when implemented)
  • Loading branch information
fisherdog1 committed May 16, 2022
1 parent 6927691 commit 6a63e78
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 37 deletions.
20 changes: 20 additions & 0 deletions itrace_core/CalibrationResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@ namespace iTrace_Core
abstract class CalibrationResult
{
public abstract void WriteToXMLWriter(XmlTextWriter xmlTextWriter);
public abstract bool IsValid();
}

class EmptyCalibrationResult : CalibrationResult
{
public override void WriteToXMLWriter(XmlTextWriter xmlTextWriter) { }
public override bool IsValid() //TODO
{
throw new System.NotImplementedException();
}
}

class TobiiCalibrationResult : CalibrationResult
Expand All @@ -41,6 +46,11 @@ public TobiiCalibrationResult(Tobii.Research.CalibrationResult calibrationResult
SessionManager.GetInstance().GenerateCalibrationTimeStamp();
}

public override bool IsValid() //TODO
{
throw new System.NotImplementedException();
}

public List<Point> GetLeftEyePoints()
{
List<Point> leftEyePoints = new List<Point>();
Expand Down Expand Up @@ -133,6 +143,11 @@ public GazePointCalibrationResult(string xmlCalibrationData, int numberOfPoints)
SessionManager.GetInstance().GenerateCalibrationTimeStamp();
}

public override bool IsValid() //TODO
{
throw new System.NotImplementedException();
}

public override void WriteToXMLWriter(XmlTextWriter xmlTextWriter)
{
XmlNode recNode = XmlDoc.FirstChild;
Expand Down Expand Up @@ -185,6 +200,11 @@ public SmartEyeCalibrationResult(SEWorldModel worldModel, List<SETarget> calibra
SessionManager.GetInstance().GenerateCalibrationTimeStamp();
}

public override bool IsValid() //TODO
{
return screenMapping.IsValid() && calibrationTargets.Count > 0;
}

public override void WriteToXMLWriter(XmlTextWriter xmlTextWriter)
{
worldModel.WriteToXMLWriter(xmlTextWriter);
Expand Down
4 changes: 3 additions & 1 deletion itrace_core/GazePointTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public String GetTrackerSerialNumber()
return TrackerSerialNumber;
}

public void StartTracker()
public bool StartTracker()
{
new System.Threading.Thread(() =>
{
Expand All @@ -92,6 +92,8 @@ public void StartTracker()
Console.WriteLine("START GP TRACKING");
Writer.Write("<SET ID=\"ENABLE_SEND_DATA\" STATE=\"1\" />\r\n");
Writer.Flush();

return true;
}

public void StopTracker()
Expand Down
2 changes: 1 addition & 1 deletion itrace_core/ITracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ interface ITracker
{
void EnterCalibration();
void LeaveCalibration();
void StartTracker();
bool StartTracker();
void StopTracker();
String GetTrackerName();
String GetTrackerSerialNumber();
Expand Down
11 changes: 10 additions & 1 deletion itrace_core/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,16 @@ private void StartTracker(object sender, RoutedEventArgs e)
}
else
{
bool trackerStarted = TrackerManager.StartTracker();

if (!trackerStarted)
{
//Fail to start
Console.WriteLine("Failed to start tracker: " + TrackerManager.GetActiveTracker().GetTrackerName());
return;
}

//Maybe figure out something less janky for this AL
string trackerID = TrackerManager.GetActiveTracker().GetTrackerName() + TrackerManager.GetActiveTracker().GetTrackerSerialNumber();
if (trackerID != SessionManager.GetInstance().CalibratedTrackerID)
SessionManager.GetInstance().ClearCalibration();
Expand All @@ -313,7 +323,6 @@ private void StartTracker(object sender, RoutedEventArgs e)

ActivateTrackerButton.Content = Properties.Resources.StopTracking;

TrackerManager.StartTracker();
ActivateCalibrationButton.IsEnabled = false;
ShowEyeStatusButton.IsEnabled = false;
TrackerList.IsEnabled = false;
Expand Down
3 changes: 2 additions & 1 deletion itrace_core/MouseTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ public String GetTrackerSerialNumber()
return "";
}

public void StartTracker()
public bool StartTracker()
{
MouseLocationTick.Start();
return true;
}

public void StopTracker()
Expand Down
8 changes: 5 additions & 3 deletions itrace_core/ScreenMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,13 @@ public ScreenMapping(SEWorldScreen[] seScreens, Screen[] osScreens)
mapping = rule.GetMapping();
break;
}

if (mapping.Count == 0)
throw new ArgumentException("No reasonable mapping between world model screens and device screens!");
}

//Check that world model maps any screens
public bool IsValid()
{
return mapping.Count > 0;
}

/// <summary>
/// Get the screen whose name matches the name of the provided seScreenName, presumably obtained from an intersection
Expand Down
87 changes: 60 additions & 27 deletions itrace_core/SmartEyeTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
using iTrace_Core.Properties;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Numerics;
using System.Windows.Forms;

namespace iTrace_Core
Expand Down Expand Up @@ -88,8 +87,6 @@ public SmartEyeTracker()
double accLeft = accuracy.Value<JToken>(0).Value<double>();
double accRight = accuracy.Value<JToken>(1).Value<double>();

//Get world and calibration points
GetWorldCalibration();
}
catch (Exception e)
{
Expand Down Expand Up @@ -180,39 +177,56 @@ public void CleanupConnections()
//Retrieve the World Model and calibration error vectors. Returns true on success
private Boolean GetWorldCalibration()
{
//Retrieve WorldModel
List<SETarget> targets = new List<SETarget>();
String WorldModelString;

SendRpc(new SERPC("getWorldModel").GetNetstring());
JToken result = ReceiveRpcResponse().GetValue("result");
try
{
//Retrieve WorldModel
SendRpc(new SERPC("getWorldModel").GetNetstring());
JToken result = ReceiveRpcResponse().GetValue("result");

//Escaped String representing the world model
String WorldModelString = result.Value<String>("worldModel");
//Escaped String representing the world model
WorldModelString = result.Value<String>("worldModel");

List<SETarget> targets = new List<SETarget>();
//Retrieve calibration targets
int targetNumber = 0;
while (true)
{
//Retrieve a target
SendRpc(new SERPCGetTargetStats(targetNumber++).GetNetstring());
SETarget target = ReceiveRpcResponse().GetValue("result").ToObject<SETarget>();

//Retrieve calibration targets
int targetNumber = 0;
while (true)
{
SendRpc(new SERPCGetTargetStats(targetNumber++).GetNetstring());
SETarget target = ReceiveRpcResponse().GetValue("result").ToObject<SETarget>();
//Ran out of targets
if (!target.TargetValid())
break;

if (!target.TargetValid())
break;
targets.Add(target);
}

targets.Add(target);
}
if (targets.Count == 0)
{
//No targets, most likely user has not done a gaze calibration in SmartEye
System.Windows.Forms.MessageBox.Show("SmartEye returned no calibration points. Perform a calibration from the SmartEye program before proceeding. \n\nMake sure that the correct World Model is selected before calibrating, or you will have to do it again!");
return false;
}

if (targets.Count == 0)
} catch (Exception e)
{
//No targets, most likely user has not done a gaze calibration in SmartEye
System.Windows.Forms.MessageBox.Show("SmartEye is connected, but reported no calibration point data. Perform a gaze calibration from the SmartEye software.");
return false;
throw new Exception("Failed to retrieve SmartEye WorldModel and calibration points");
}

//Store world model string and calibration data
//TODO exception handling for invalid worldModelString
SEWorldModel worldModel = new SEWorldModel(WorldModelString);

seCalibrationResult = new SmartEyeCalibrationResult(worldModel, targets);

if (!seCalibrationResult.IsValid())
{
System.Windows.Forms.MessageBox.Show("The SmartEye World Model does not match the displays present on this computer. Make sure the correct world model is selected and perform another SmartEye calibration.");
}

SessionManager.GetInstance().SetCalibration(seCalibrationResult, this);

return true;
Expand All @@ -227,6 +241,7 @@ public JObject ReceiveRpcResponse()
return JsonConvert.DeserializeObject<dynamic>(response);
}

//An Rpc connection and UDP (Realtime) socket are required to track
public bool TrackerFound()
{
return (RealtimeClient != null) && (RpcClient != null);
Expand All @@ -250,28 +265,48 @@ public void SendRpc(String netstring)
RpcClient.GetStream().Write(buf, 0, buf.Length);
}

public void StartTracker()
public bool StartTracker()
{
//Before tracking starts the worldmodel must be valid and contain a set of calibration points
//Get world and calibration points
if (!GetWorldCalibration())
return false;

//Tell SmartEye to start tracking (same as clicking track eye button)
SendRpc(new SERPC("startTracking").GetNetstring());
ReceiveRpcResponse(); // Dummy receive to eat any error

//Used to stop listening thread loops
Listen = true;

//Realtime (UDP) thread
new System.Threading.Thread(() =>
{
System.Threading.Thread.CurrentThread.IsBackground = true;
ListenForData();
}).Start();

//Latent (TCP) thread
new System.Threading.Thread(() =>
{
System.Threading.Thread.CurrentThread.IsBackground = true;
ListenForLatent();
}).Start();

//Ok
Console.WriteLine("START SE TRACKING");
return true;
}

//Important to make sure the tracker is actually running before sending this, otherwise an error will be returned
public void StopTracker()
{
SendRpc(new SERPC("stopTracking").GetNetstring());
//Send stop command to SmartEye
if (Listen)
{
SendRpc(new SERPC("stopTracking").GetNetstring());
ReceiveRpcResponse(); // Dummy receive to eat any error
}

Listen = false;
}
Expand Down Expand Up @@ -301,8 +336,6 @@ private void TrackerInit()

private void ListenForData()
{
Listen = true;

while (Listen)
{
//Receive UDP packet
Expand Down
1 change: 1 addition & 0 deletions itrace_core/SocketServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ private void ListenForConnections()
{
TcpClient client;

//For some reason this now doesn't stop when you close the main window, I think it did before. AL
while (true)
{
client = server.AcceptTcpClient();
Expand Down
3 changes: 2 additions & 1 deletion itrace_core/TobiiTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@ public String GetTrackerSerialNumber()
return TrackingDevice.SerialNumber;
}

public void StartTracker()
public bool StartTracker()
{
TrackingDevice.GazeDataReceived += ReceiveRawGaze;
return true;
}

public void StopTracker()
Expand Down
6 changes: 4 additions & 2 deletions itrace_core/TrackerManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,11 @@ public Boolean Running()

public Boolean StartTracker()
{
Tracking = true;

GazeHandler.Instance.StartHandler();
ActiveTracker.StartTracker();
if (ActiveTracker.StartTracker())
Tracking = true;

return Tracking;
}

Expand Down

0 comments on commit 6a63e78

Please sign in to comment.