diff --git a/CodeMaid.config b/CodeMaid.config
new file mode 100644
index 0000000..20aa96c
--- /dev/null
+++ b/CodeMaid.config
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+ Constructors||6||Constructors
+
+
+ Properties||5||Properties
+
+
+ Enums||1||Enums
+
+
+ Destructors||7||Destructors
+
+
+ Delegates||2||Delegates
+
+
+ Fields||4||Fields
+
+
+ Interfaces||8||Interfaces
+
+
+ Events||3||Events
+
+
+
+
\ No newline at end of file
diff --git a/GazeWebSocketServer/App.config b/GazeWebSocketServer/App.config
index 6bcc981..26b239c 100644
--- a/GazeWebSocketServer/App.config
+++ b/GazeWebSocketServer/App.config
@@ -3,6 +3,7 @@
+
diff --git a/GazeWebSocketServer/ConfigurationData.cs b/GazeWebSocketServer/ConfigurationData.cs
index 1fa58ba..335ce9d 100644
--- a/GazeWebSocketServer/ConfigurationData.cs
+++ b/GazeWebSocketServer/ConfigurationData.cs
@@ -11,6 +11,7 @@ namespace GazeWebSocketServer
{
public string TrackerSerialNumber { get; private set; }
public float TrackerFrequency { get; private set; }
+ public float OutputFrequency { get; private set; }
public int WebSocketPort { get; private set; }
public string WebSocketEndpoint { get; private set; }
public bool DebugFlag { get; private set; }
@@ -21,6 +22,7 @@ namespace GazeWebSocketServer
{
TrackerSerialNumber = ConfigurationManager.AppSettings["TrackerSerialNumber"],
TrackerFrequency = float.Parse(ConfigurationManager.AppSettings["TrackerFrequency_Hz"]),
+ OutputFrequency = float.Parse(ConfigurationManager.AppSettings["OutputFrequency_Hz"]),
WebSocketPort = int.Parse(ConfigurationManager.AppSettings["WebSocketPort"]),
WebSocketEndpoint = ConfigurationManager.AppSettings["WebSocketEndpoint"],
DebugFlag = bool.Parse(ConfigurationManager.AppSettings["DebugFlag"])
@@ -32,6 +34,7 @@ namespace GazeWebSocketServer
{
InitializeSetting("TrackerSerialNumber", "TPSP1-");
InitializeSetting("TrackerFrequency_Hz", "600");
+ InitializeSetting("OutputFrequency_Hz", "60");
InitializeSetting("WebSocketPort", "8001");
InitializeSetting("WebSocketEndpoint", "/gaze");
InitializeSetting("DebugFlag", "false");
diff --git a/GazeWebSocketServer/Program.cs b/GazeWebSocketServer/Program.cs
index 3c74670..be567ae 100644
--- a/GazeWebSocketServer/Program.cs
+++ b/GazeWebSocketServer/Program.cs
@@ -4,12 +4,15 @@ using TrackerBridge;
using System.Windows.Forms;
using System.Drawing;
using System.Timers;
+using TrackerBridge.DSP;
namespace GazeWebSocketServer
{
public class Program
{
private static GazeServer gazeServer;
+ private static GazeDecimator decimator = new GazeDecimator(1, 600);
+
public static void Main(string[] args)
{
ConfigurationData.InitializeUnexistingWithDefaults();
@@ -17,7 +20,7 @@ namespace GazeWebSocketServer
if (args.Length > 0 && args[0] == "-d")
{
- Task.Run(() => SimulateGazeDataHz(120));
+ Task.Run(() => SimulateGazeDataHz(10));
}
else
{
@@ -35,14 +38,16 @@ namespace GazeWebSocketServer
private static void SimulateGazeDataHz(Int32 frequency)
{
- System.Timers.Timer timer = new System.Timers.Timer(1.0/frequency);
+ System.Timers.Timer timer = new System.Timers.Timer(1000.0/frequency);
timer.Elapsed += (Object sender, ElapsedEventArgs e) =>
{
Point mousePosition = Control.MousePosition;
GazeData data = new GazeData(mousePosition.X, mousePosition.Y, mousePosition.X, mousePosition.Y, 0, 0);
if (gazeServer != null && gazeServer.isRunning)
{
- gazeServer.Publish(data);
+ decimator.Input(data);
+ if(decimator.Output.HasValue)
+ gazeServer.Publish(data);
}
};
timer.AutoReset = true;
diff --git a/TrackerBridge/DSP/GazeDecimator.cs b/TrackerBridge/DSP/GazeDecimator.cs
new file mode 100644
index 0000000..39eca61
--- /dev/null
+++ b/TrackerBridge/DSP/GazeDecimator.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TrackerBridge.DSP
+{
+ public class GazeDecimator : IGazeFilter
+ {
+ private GazeData[] buffer;
+ private Int32 currentValueIndex;
+ private Single inputFrequency;
+ private GazeData? output;
+ private Single outputFrequency;
+
+ private Object outputLock = new Object();
+ private Object inputLock = new Object();
+
+ public Single InputFrequency {
+ get { return inputFrequency; }
+ set {
+ inputFrequency = value;
+ Reset();
+ }
+ }
+ public GazeData? Output {
+ get {
+ lock (outputLock)
+ {
+ GazeData? temp = null;
+ if (output.HasValue)
+ {
+ temp = output.Value;
+ output = null;
+
+ }
+ return temp;
+ }
+ }
+ }
+ public Single OutputFrequency {
+ get { return outputFrequency; }
+ set {
+ outputFrequency = value;
+ Reset();
+ }
+ }
+
+ public GazeDecimator(Single outputFrequency, Single inputFrequency)
+ {
+ this.outputFrequency = outputFrequency;
+ this.inputFrequency = inputFrequency;
+ Reset();
+ }
+
+ public void Input(GazeData input)
+ {
+ lock (inputLock)
+ {
+ buffer[currentValueIndex] = input;
+ currentValueIndex = (currentValueIndex + 1) % buffer.Length;
+
+ if (currentValueIndex == 0)
+ {
+ GazeData sum = buffer[0];
+ for (Int32 index = 1; index < buffer.Length; index++)
+ {
+ sum += buffer[index];
+ }
+ lock (outputLock)
+ {
+ output = sum / buffer.Length;
+ }
+ }
+ }
+ }
+
+ public void Reset()
+ {
+ Int32 bufferLength = Convert.ToInt32(InputFrequency / OutputFrequency);
+ buffer = new GazeData[bufferLength];
+ currentValueIndex = 0;
+ output = null;
+ }
+ }
+}
diff --git a/TrackerBridge/DSP/IGazeFilter.cs b/TrackerBridge/DSP/IGazeFilter.cs
new file mode 100644
index 0000000..c383b77
--- /dev/null
+++ b/TrackerBridge/DSP/IGazeFilter.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TrackerBridge.DSP
+{
+ interface IGazeFilter
+ {
+ GazeData? Output { get; }
+ void Input(GazeData input);
+ void Reset();
+ }
+}
diff --git a/TrackerBridge/GazeData.cs b/TrackerBridge/GazeData.cs
index 152a70b..bf52a61 100644
--- a/TrackerBridge/GazeData.cs
+++ b/TrackerBridge/GazeData.cs
@@ -31,5 +31,29 @@ namespace TrackerBridge
FormattableString message = $"{leftX};{leftY};{rightX};{rightY};{trackerTimeStamp};{systemTimeStamp}";
return FormattableString.Invariant(message);
}
+
+ public static GazeData operator +(GazeData a, GazeData b)
+ {
+ GazeData result = new GazeData(a.leftX + b.leftX,
+ a.leftY + b.leftY,
+ a.rightX + b.rightX,
+ a.rightY + b.rightY,
+ Math.Abs(a.trackerTimeStamp - b.trackerTimeStamp),
+ Math.Abs(a.systemTimeStamp - b.systemTimeStamp));
+
+ return result;
+ }
+
+ public static GazeData operator /(GazeData a, Single b)
+ {
+ GazeData result = new GazeData(a.leftX / b,
+ a.leftY / b,
+ a.rightX / b,
+ a.rightY / b,
+ a.trackerTimeStamp / Convert.ToInt64(b),
+ a.systemTimeStamp / Convert.ToInt64(b));
+
+ return result;
+ }
}
}
diff --git a/TrackerBridge/GazeDataProcessor.cs b/TrackerBridge/GazeDataProcessor.cs
index 2817f09..b67088f 100644
--- a/TrackerBridge/GazeDataProcessor.cs
+++ b/TrackerBridge/GazeDataProcessor.cs
@@ -5,21 +5,44 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tobii.Research;
+using TrackerBridge.DSP;
namespace TrackerBridge
{
public class GazeDataProcessor
{
- readonly float screenHeight;
- readonly float screenWidth;
+ public event EventHandler ProcessedGazeDataAvailable;
- public GazeDataProcessor()
+ private readonly IGazeFilter[] gazeFilters;
+ private readonly Single screenHeight;
+ private readonly Single screenWidth;
+ private Single outputFrequency;
+
+ public Single OutputFrequency {
+ get { return outputFrequency; }
+ set {
+ outputFrequency = value;
+ Initialize();
+ }
+ }
+
+ public GazeDataProcessor(IBridgeTracker tracker)
{
+ tracker.TrackingFrequencyChanged += OnTrackingFrequencyChanged;
screenHeight = Convert.ToSingle(SystemParameters.PrimaryScreenHeight);
screenWidth = Convert.ToSingle(SystemParameters.PrimaryScreenWidth);
+ gazeFilters = new IGazeFilter[1];
+ gazeFilters[0] = new GazeDecimator(outputFrequency, tracker.GetTrackingFrequency());
+ }
+ public void Initialize()
+ {
+ foreach (IGazeFilter filter in gazeFilters)
+ {
+ filter.Reset();
+ }
}
- public GazeData Extract(GazeDataEventArgs e)
+ public GazeData? Process(GazeDataEventArgs e)
{
GazeData data = new GazeData(e.LeftEye.GazePoint.PositionOnDisplayArea.X * screenWidth,
e.LeftEye.GazePoint.PositionOnDisplayArea.Y * screenHeight,
@@ -27,7 +50,28 @@ namespace TrackerBridge
e.RightEye.GazePoint.PositionOnDisplayArea.Y * screenHeight,
e.DeviceTimeStamp,
e.SystemTimeStamp);
- return data;
+
+ gazeFilters[0].Input(data);
+ for (Int32 index = 1; index < gazeFilters.Length; index++)
+ {
+ if (gazeFilters[index - 1].Output.HasValue)
+ {
+ gazeFilters[index].Input(gazeFilters[index - 1].Output.Value);
+ }
+ }
+ //TODO: If output, invoke event
+ return gazeFilters[gazeFilters.Length - 1].Output;
+ }
+ private void OnTrackingFrequencyChanged(Object sender, Single frequency)
+ {
+ foreach(IGazeFilter filter in gazeFilters)
+ {
+ if(filter.GetType() == typeof(GazeDecimator))
+ {
+ GazeDecimator decimator = (GazeDecimator)filter;
+ decimator.InputFrequency = frequency;
+ }
+ }
}
}
}
diff --git a/TrackerBridge/IBridgeTracker.cs b/TrackerBridge/IBridgeTracker.cs
new file mode 100644
index 0000000..ee5f5b6
--- /dev/null
+++ b/TrackerBridge/IBridgeTracker.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TrackerBridge
+{
+ public interface IBridgeTracker
+ {
+ event EventHandler TrackingFrequencyChanged;
+ void SetTrackingFrequency(Single value);
+ Single GetTrackingFrequency();
+ }
+}
diff --git a/TrackerBridge/TobiiEyeTracker.cs b/TrackerBridge/TobiiEyeTracker.cs
index c7cf92b..9f5d8a6 100644
--- a/TrackerBridge/TobiiEyeTracker.cs
+++ b/TrackerBridge/TobiiEyeTracker.cs
@@ -7,32 +7,38 @@ using Tobii.Research;
namespace TrackerBridge
{
- public class TobiiEyeTracker
+ public class TobiiEyeTracker : IBridgeTracker
{
public delegate void ConnectionEventHandler(TobiiEyeTracker sender);
public delegate void GazeDataHandler(TobiiEyeTracker sender, GazeData data);
+
public event ConnectionEventHandler ConnectionEvent;
public event ConnectionEventHandler ConnectionTimeout;
public event GazeDataHandler GazeDataAvailable;
-
- public Boolean IsConnected { get; private set; }
- public String SerialNumber { get => serialNumber; }
+ public event EventHandler TrackingFrequencyChanged;
private IEyeTracker eyeTracker = null;
- private String serialNumber = null;
- private GazeDataProcessor gazeDataProcessor;
+
+ public GazeDataProcessor GazeDataProcessor { get; set; }
+ public Boolean IsConnected { get; private set; } = false;
+ public String SerialNumber { get; private set; } = null;
public TobiiEyeTracker()
{
- gazeDataProcessor = new GazeDataProcessor();
+ GazeDataProcessor = new GazeDataProcessor(this);
}
public TobiiEyeTracker(String serialNumber) : this()
{
- this.serialNumber = serialNumber;
+ SerialNumber = serialNumber;
+ }
+ public void Connect()
+ {
+ Task task = new Task(() => InitiateConnection());
+ task.Start();
}
- public float GetTrackingFrequency()
+ public Single GetTrackingFrequency()
{
if (eyeTracker != null)
{
@@ -43,18 +49,22 @@ namespace TrackerBridge
throw new NullReferenceException();
}
}
+
+ Single IBridgeTracker.GetTrackingFrequency()
+ {
+ throw new NotImplementedException();
+ }
+
public void SetTrackingFrequency(float value)
{
- if (eyeTracker != null)
+ if (eyeTracker != null && eyeTracker.GetAllGazeOutputFrequencies().Contains(value))
{
eyeTracker.SetGazeOutputFrequency(value);
}
}
-
- public void Connect()
+ void IBridgeTracker.SetTrackingFrequency(Single value)
{
- Task task = new Task(() => InitiateConnection());
- task.Start();
+ throw new NotImplementedException();
}
private void InitiateConnection()
@@ -65,7 +75,7 @@ namespace TrackerBridge
EyeTrackerCollection eyeTrackers = EyeTrackingOperations.FindAllEyeTrackers();
if (eyeTrackers.Count > 0)
{
- if (serialNumber == null)
+ if (SerialNumber == null)
{
eyeTracker = eyeTrackers[0];
break;
@@ -74,7 +84,7 @@ namespace TrackerBridge
{
foreach (IEyeTracker t in eyeTrackers)
{
- if (serialNumber == t.SerialNumber)
+ if (SerialNumber == t.SerialNumber)
{
eyeTracker = t;
break;
@@ -94,15 +104,24 @@ namespace TrackerBridge
}
}
eyeTracker.GazeDataReceived += OnGazeDataReceived;
- serialNumber = eyeTracker.SerialNumber;
+ eyeTracker.GazeOutputFrequencyChanged += OnGazeOutputFrequencyChanged;
+ SerialNumber = eyeTracker.SerialNumber;
SetTrackingFrequency(600f);
ConnectionEvent?.Invoke(this);
}
private void OnGazeDataReceived(object sender, GazeDataEventArgs e)
{
- GazeData gazeData = gazeDataProcessor.Extract(e);
- GazeDataAvailable?.Invoke(this, gazeData);
+ GazeData? gazeData = GazeDataProcessor.Process(e);
+ if (gazeData.HasValue)
+ {
+ GazeDataAvailable?.Invoke(this, gazeData.Value);
+ }
+ }
+
+ private void OnGazeOutputFrequencyChanged(Object sender, GazeOutputFrequencyEventArgs e)
+ {
+ TrackingFrequencyChanged?.Invoke(this, e.GazeOutputFrequency);
}
}
}
\ No newline at end of file
diff --git a/TrackerBridge/TrackerBridge.csproj b/TrackerBridge/TrackerBridge.csproj
index 2b99db3..53502a0 100644
--- a/TrackerBridge/TrackerBridge.csproj
+++ b/TrackerBridge/TrackerBridge.csproj
@@ -48,8 +48,11 @@
+
+
+