using System; using System.Linq; using System.Threading.Tasks; using Plotting; using UnityEngine; using UnityEngine.Serialization; [System.Serializable] public struct PolarSensorConfig { public int port; public String ipAddress; public bool plotAcc; public bool plotEcg; public int accSampleRate; //TODO: let user choose between 25, 50, 100, 200 public PolarSensorConfig(int port = 9099, string ipAddress = "0.0.0.0", bool plotAcc = false, bool plotEcg = false, int accSampleRate = 25) { this.port = port; this.ipAddress = ipAddress; this.plotAcc = plotAcc; this.plotEcg = plotEcg; this.accSampleRate = accSampleRate; } } public struct PolarSensorData { public Vector3 Acc; public float EcgValue; } public class PolarReceiver { private UdpConnection connection; private PolarSensorData sensorData; public PolarSensorConfig SensorConfig { get; private set; } public PolarSensorData SensorData => sensorData; private PlotFileWriter ecgPlotFile; private PlotFileWriter accPlotFile; private static DateTime startTime; private static long previousTime; [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] private static void InitTime() { startTime = DateTime.Now; } public PolarReceiver(PolarSensorConfig config) { SensorConfig = config; } public async Task StartListening() { if (SensorConfig.plotAcc) { accPlotFile = DebugPlot.Instance.StartPlotting("Assets/Plotting/plots/acc.tsv"); await accPlotFile.WriteDataLine("timestamp", new[] {"x", "y", "z"}); } if (SensorConfig.plotEcg) { ecgPlotFile = DebugPlot.Instance.StartPlotting("Assets/Plotting/plots/ecg.tsv"); await accPlotFile.WriteDataLine("timestamp", new[] {"voltage"}); } if (SensorConfig.plotAcc || SensorConfig.plotEcg) { DebugPlot.Instance.ShowPlots(); } connection = new UdpConnection(SensorConfig.ipAddress, SensorConfig.port, OnAccData, OnEcgData); connection.Listen(); } public void Dispose() { connection.StopListening(); DebugPlot.DestroyInstance(); } private async void OnAccData(AccData data) { var now = DateTime.Now; Debug.Log($"#ACC DATA items: {data.Values.Count}"); Debug.Log($"ACC DATA s since last: {data.Timestamp - previousTime} /1000000000f"); previousTime = data.Timestamp; await Task.WhenAll(UpdateSensorDataForAcc(data), PlotAcc(data)); } private async Task PlotAcc(AccData data) { if (SensorConfig.plotAcc) { var timestamp = (int) (DateTime.Now - startTime) .TotalMilliseconds; //not perfect because of delay. But that's the time the game get's the data //var timestamp = data.Timestamp; foreach (var item in data.Values) { await accPlotFile.WriteDataLine(timestamp, new[] {item.x, item.y, item.z}); timestamp += 1000 / SensorConfig.accSampleRate; } } } private async Task UpdateSensorDataForAcc(AccData data) { foreach (var item in data.Values) { sensorData.Acc = data.Values[0]; await Task.Delay(1000 / SensorConfig.accSampleRate); } } private async void OnEcgData(EcgData data) { if (SensorConfig.plotEcg) { //var timestamp = data.Timestamp; // if we wanted to use the timestamp of the polar sensor directly var timestamp = (int) (DateTime.Now - startTime) .TotalMilliseconds; //not perfect because of delay. But that's the time the game get's the data foreach (var item in data.Values) { await ecgPlotFile.WriteDataLine(timestamp, new[] {item}); timestamp += 1000 / 130; } } sensorData.EcgValue = data.Values[0]; //TODO } }