Skip to content

Commit

Permalink
feat: add middleware and devices status update feature
Browse files Browse the repository at this point in the history
  • Loading branch information
Marco Bacis committed Jun 29, 2023
1 parent 1033e9c commit 0bd4baa
Show file tree
Hide file tree
Showing 2 changed files with 201 additions and 3 deletions.
116 changes: 113 additions & 3 deletions WeArtClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,16 @@ public enum ErrorType
/// </summary>
public event Action<HandSide> OnCalibrationResultFail;

/// <summary>
/// Called when a status update is received from the middleware
/// </summary>
public event Action<MiddlewareStatusMessage> OnMiddlewareStatusMessage;

/// <summary>
/// Called when a status update about the connected devices is received
/// </summary>
public event Action<DevicesStatusMessage> OnDevicesStatusMessage;

/// <summary>
/// True if a connection to the middleware has been established
/// </summary>
Expand Down Expand Up @@ -125,7 +135,7 @@ public int Port
public Task Start(TrackingType trackingType = TrackingType.WEART_HAND)
{
_cancellation = new CancellationTokenSource();
return Task.Run(() =>
return Task.Run(async () =>
{
// Connection loop
while (!_cancellation.IsCancellationRequested)
Expand All @@ -143,6 +153,10 @@ public Task Start(TrackingType trackingType = TrackingType.WEART_HAND)

// Send the request to start
SendMessage(new StartFromClientMessage { TrackingType = trackingType });

// Wait for the middleware to start the session (or throw TimeoutException otherwise)
SendMessage(new GetMiddlewareStatusMessage());
await WaitForMessage((MiddlewareStatusMessage message) => message.Status == MiddlewareStatus.RUNNING, 5000);
}
catch (Exception e)
{
Expand Down Expand Up @@ -170,10 +184,25 @@ public Task Start(TrackingType trackingType = TrackingType.WEART_HAND)
/// <summary>
/// Stops the middleware and the established connection
/// </summary>
public void Stop()
/// <returns>True if the middleware was stopped correctly and the connection closed, false otherwise</returns>
public async Task<bool> Stop()
{
SendMessage(new StopFromClientMessage());

try
{
await WaitForMessage((MiddlewareStatusMessage msg) =>
msg.Status != MiddlewareStatus.RUNNING && msg.Status != MiddlewareStatus.STOPPING,
5000
);
}
catch (TimeoutException)
{
return false;
}

StopConnection();
return true;
}

/// <summary>
Expand All @@ -192,16 +221,97 @@ public void StopCalibration()
SendMessage(new StopCalibrationMessage());
}

/// <summary>
/// Asks the middleware to start sending raw data events to the sdk
/// </summary>
public void StartRawData()
{
SendMessage(new RawDataOnMessage());
}

/// <summary>
/// Tells the middleware to stop sending raw data events
/// </summary>
public void StopRawData()
{
SendMessage(new RawDataOffMessage());
}

/// <summary>
/// Asks the middleware to send an updated status message
/// </summary>
public void AskStatusUpdate()
{
SendMessage(new GetMiddlewareStatusMessage());
}

/// <summary>
/// Asks the middleware to send an updated message on the status of connected devices
/// </summary>
public void AskDevicesStatusUpdate()
{
SendMessage(new GetDevicesStatusMessage());
}

/// <summary>
/// Waits for any message with the given type for the given timeout
/// </summary>
/// <typeparam name="T">Type of the message to wait</typeparam>
/// <param name="timeoutMs">Timeout to wait for the correct message</param>
/// <returns>The received message</returns>
/// <exception cref="TimeoutException">Thrown when the correct message is not received withih the given timeout</exception>
public async Task<T> WaitForMessage<T>(int timeoutMs)
{
return await WaitForMessage<T>((T msg) => true, timeoutMs);
}

/// <summary>
/// Waits for any message with the given type and condition for the given timeout
/// </summary>
/// <typeparam name="T">Type of the message to wait</typeparam>
/// <param name="predicate">Condition that the message must fullfill to be considered ok</param>
/// <param name="timeoutMs">Timeout to wait for the correct message</param>
/// <returns>The received message</returns>
/// <exception cref="TimeoutException">Thrown when the correct message is not received withih the given timeout</exception>
public async Task<T> WaitForMessage<T>(Func<T, bool> predicate, int timeoutMs)
{
// Write Pack and wait for responses (of a certain type) with a given timeout
CancellationTokenSource source = new CancellationTokenSource();

T receivedMessage = default(T);
Action<MessageType, IWeArtMessage> onMessageReceived = (MessageType type, IWeArtMessage message) =>
{
if (type != MessageType.MessageReceived) return;
if (message is T castedMessage)
{
if (predicate(castedMessage))
{
receivedMessage = castedMessage;
source.Cancel();
}
}
};

OnMessage += onMessageReceived;

// Wait to receive message
try
{
await Task.Delay(timeoutMs, source.Token);
throw new TimeoutException();
}
catch (OperationCanceledException)
{
// Canceled operation means we received the correct message
}
finally
{
OnMessage -= onMessageReceived;
}

return receivedMessage;
}

/// <summary>
/// Sends a message to the middleware
/// </summary>
Expand Down Expand Up @@ -257,7 +367,7 @@ private bool ReceiveMessages(out IWeArtMessage[] messages)
messages = new IWeArtMessage[split.Length];
for (int i = 0; i < messages.Length; i++)
{
if(_messageSerializer.Deserialize(split[i], out messages[i]))
if (_messageSerializer.Deserialize(split[i], out messages[i]))
ForwardMessage(split[i], messages[i]);
}
return true;
Expand Down
88 changes: 88 additions & 0 deletions WeArtMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Collections.Generic;
using WeArt.Core;
Expand Down Expand Up @@ -370,4 +371,91 @@ public class RawDataMessage : WeArtJsonMessage
public SensorData Middle { get; set; }
public SensorData Palm { get; set; }
}

[WeArtMiddlewareMessageID("MW_GET_STATUS")]
public class GetMiddlewareStatusMessage : WeArtJsonMessage { }


/// <summary>
/// Defines the STATUS.
/// </summary>
public enum MiddlewareStatus
{
DISCONNECTED,
IDLE,
STARTING,
RUNNING,
STOPPING,
UPLOADING_TEXTURES,
CONNECTING_DEVICE,
CALIBRATION,
};

[WeArtMiddlewareMessageID("MW_STATUS")]
public class MiddlewareStatusMessage : WeArtJsonMessage
{
[JsonConverter(typeof(StringEnumConverter))]
public MiddlewareStatus Status { get; set; }

public string Version { get; set; }

public int StatusCode { get; set; }

public string ErrorDesc { get; set; }

public bool ActuationsEnabled { get; set; }

public List<MiddlewareConnectedDevice> ConnectedDevices { get; set; }

public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
}

public struct MiddlewareConnectedDevice
{
public string MacAddress { get; set; }

[JsonConverter(typeof(StringEnumConverter))]
public HandSide HandSide { get; set; }
}

[WeArtMiddlewareMessageID("DEVICES_GET_STATUS")]
public class GetDevicesStatusMessage : WeArtJsonMessage { }

[WeArtMiddlewareMessageID("DEVICES_STATUS")]
public class DevicesStatusMessage : WeArtJsonMessage
{
public List<DeviceStatus> Devices { get; set; }

public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
}

public struct DeviceStatus
{
public string MacAddress { get; set; }

[JsonConverter(typeof(StringEnumConverter))]
public HandSide HandSide { get; set; }

public int BatteryLevel { get; set; }

public List<ThimbleStatus> Thimbles { get; set; }
}

public struct ThimbleStatus
{
[JsonConverter(typeof(StringEnumConverter))]
public ActuationPoint Id { get; set; }

public bool Connected { get; set; }

public int StatusCode { get; set; }

public string ErrorDesc { get; set; }
}
}

0 comments on commit 0bd4baa

Please sign in to comment.