diff --git a/Assets/Scripts/EphysLink/CommunicationManager.cs b/Assets/Scripts/EphysLink/CommunicationManager.cs index 261514f6..c242f174 100644 --- a/Assets/Scripts/EphysLink/CommunicationManager.cs +++ b/Assets/Scripts/EphysLink/CommunicationManager.cs @@ -20,9 +20,10 @@ public class CommunicationManager : MonoBehaviour #region Properties - private static readonly int[] EPHYS_LINK_MIN_VERSION = { 1, 2, 8 }; + private static readonly int[] EPHYS_LINK_MIN_VERSION = { 1, 3, 0 }; - public static readonly string EPHYS_LINK_MIN_VERSION_STRING = $"≥ v{string.Join(".", EPHYS_LINK_MIN_VERSION)}"; + public static readonly string EPHYS_LINK_MIN_VERSION_STRING = + $"≥ v{string.Join(".", EPHYS_LINK_MIN_VERSION)}"; private const string UNKOWN_EVENT = "UNKNOWN_EVENT"; @@ -58,13 +59,23 @@ private void Awake() public void ServerSettingsLoaded() { // Automatically connect if the server credentials are possible - if (!IsConnected && !string.IsNullOrEmpty(Settings.EphysLinkServerIp) && - Settings.EphysLinkServerPort >= 1025) - ConnectToServer(Settings.EphysLinkServerIp, Settings.EphysLinkServerPort, () => - { - // Verify Ephys Link version - VerifyVersion(() => IsEphysLinkCompatible = true, () => Instance.DisconnectFromServer()); - }); + if ( + !IsConnected + && !string.IsNullOrEmpty(Settings.EphysLinkServerIp) + && Settings.EphysLinkServerPort >= 1025 + ) + ConnectToServer( + Settings.EphysLinkServerIp, + Settings.EphysLinkServerPort, + () => + { + // Verify Ephys Link version + VerifyVersion( + () => IsEphysLinkCompatible = true, + () => Instance.DisconnectFromServer() + ); + } + ); } /// @@ -74,18 +85,19 @@ public void ServerSettingsLoaded() /// Port of the server /// Callback function to handle a successful connection /// - public void ConnectToServer(string ip, int port, Action onConnected = null, - Action onError = null) + public void ConnectToServer( + string ip, + int port, + Action onConnected = null, + Action onError = null + ) { // Disconnect the old connection if needed - if (_connectionManager != null && _connectionManager.Socket.IsOpen) _connectionManager.Close(); + if (_connectionManager != null && _connectionManager.Socket.IsOpen) + _connectionManager.Close(); // Create new connection - var options = new SocketOptions - { - Timeout = new TimeSpan(0, 0, 2) - }; - + var options = new SocketOptions { Timeout = new TimeSpan(0, 0, 2) }; // Try to open a connection try @@ -95,42 +107,52 @@ public void ConnectToServer(string ip, int port, Action onConnected = null, _socket = _connectionManager.Socket; // On successful connection - _socket.Once("connect", () => - { - Debug.Log($"Connected to WebSocket server at {ip}:{port}"); - IsConnected = true; + _socket.Once( + "connect", + () => + { + Debug.Log($"Connected to WebSocket server at {ip}:{port}"); + IsConnected = true; - // Save settings - Settings.EphysLinkServerIp = ip; - Settings.EphysLinkServerPort = port; + // Save settings + Settings.EphysLinkServerIp = ip; + Settings.EphysLinkServerPort = port; - onConnected?.Invoke(); - }); + onConnected?.Invoke(); + } + ); // On error - _socket.Once("error", () => - { - var connectionErrorMessage = - $"Error connecting to server at {ip}:{port}. Check server for details."; - Debug.LogWarning(connectionErrorMessage); - IsConnected = false; - _connectionManager.Close(); - _connectionManager = null; - _socket = null; - onError?.Invoke(connectionErrorMessage); - }); + _socket.Once( + "error", + () => + { + var connectionErrorMessage = + $"Error connecting to server at {ip}:{port}. Check server for details."; + Debug.LogWarning(connectionErrorMessage); + IsConnected = false; + _connectionManager.Close(); + _connectionManager = null; + _socket = null; + onError?.Invoke(connectionErrorMessage); + } + ); // On timeout - _socket.Once("connect_timeout", () => - { - var connectionTimeoutMessage = "Connection to server at {ip}:{port} timed out"; - Debug.LogWarning(connectionTimeoutMessage); - IsConnected = false; - _connectionManager.Close(); - _connectionManager = null; - _socket = null; - onError?.Invoke(connectionTimeoutMessage); - }); + _socket.Once( + "connect_timeout", + () => + { + var connectionTimeoutMessage = + "Connection to server at {ip}:{port} timed out"; + Debug.LogWarning(connectionTimeoutMessage); + IsConnected = false; + _connectionManager.Close(); + _connectionManager = null; + _socket = null; + onError?.Invoke(connectionTimeoutMessage); + } + ); } catch (Exception e) { @@ -159,37 +181,45 @@ public void DisconnectFromServer(Action onDisconnected = null) public void VerifyVersion(Action onSuccess, Action onFailure) { - GetVersion(versionString => - { - var versionNumbers = versionString.Split(".").Select(values => - values.TakeWhile(char.IsDigit).ToArray()).TakeWhile(numbers => numbers.Length > 0) - .Select(nonEmpty => int.Parse(new string(nonEmpty))).ToArray(); - - // Fail if major version mismatch (breaking changes). - if (versionNumbers[0] != EPHYS_LINK_MIN_VERSION[0]) - { - onFailure.Invoke(); - return; - } - - // Fail if minor version is too small (missing features). - if (versionNumbers[1] < EPHYS_LINK_MIN_VERSION[0]) - { - onFailure.Invoke(); - return; - } - - // Fail if patch version is too small and minor version is not greater (bug fixes). - if (versionNumbers[1] == EPHYS_LINK_MIN_VERSION[1] && - versionNumbers[2] < EPHYS_LINK_MIN_VERSION[2]) + GetVersion( + versionString => { - onFailure.Invoke(); - return; - } - - // Passed checks. - onSuccess.Invoke(); - }, onFailure.Invoke); + var versionNumbers = versionString + .Split(".") + .Select(values => values.TakeWhile(char.IsDigit).ToArray()) + .TakeWhile(numbers => numbers.Length > 0) + .Select(nonEmpty => int.Parse(new string(nonEmpty))) + .ToArray(); + + // Fail if major version mismatch (breaking changes). + if (versionNumbers[0] != EPHYS_LINK_MIN_VERSION[0]) + { + onFailure.Invoke(); + return; + } + + // Fail if minor version is too small (missing features). + if (versionNumbers[1] < EPHYS_LINK_MIN_VERSION[0]) + { + onFailure.Invoke(); + return; + } + + // Fail if patch version is too small and minor version is not greater (bug fixes). + if ( + versionNumbers[1] == EPHYS_LINK_MIN_VERSION[1] + && versionNumbers[2] < EPHYS_LINK_MIN_VERSION[2] + ) + { + onFailure.Invoke(); + return; + } + + // Passed checks. + onSuccess.Invoke(); + }, + onFailure.Invoke + ); } #endregion @@ -203,13 +233,15 @@ public void VerifyVersion(Action onSuccess, Action onFailure) /// If the version number is empty or failed to return private void GetVersion(Action onSuccessCallback, Action onErrorCallback = null) { - _connectionManager.Socket.ExpectAcknowledgement(data => - { - if (DataKnownAndNotEmpty(data)) - onSuccessCallback?.Invoke(data); - else - onErrorCallback?.Invoke(); - }).Emit("get_version"); + _connectionManager + .Socket.ExpectAcknowledgement(data => + { + if (DataKnownAndNotEmpty(data)) + onSuccessCallback?.Invoke(data); + else + onErrorCallback?.Invoke(); + }) + .Emit("get_version"); } /// @@ -217,25 +249,29 @@ private void GetVersion(Action onSuccessCallback, Action onErrorCallback /// /// Callback function to handle incoming manipulator ID's /// Callback function to handle errors - public void GetManipulators(Action onSuccessCallback, - Action onErrorCallback = null) + public void GetManipulators( + Action onSuccessCallback, + Action onErrorCallback = null + ) { - _connectionManager.Socket.ExpectAcknowledgement(data => - { - if (DataKnownAndNotEmpty(data)) + _connectionManager + .Socket.ExpectAcknowledgement(data => { - var parsedData = ParseJson(data); - - if (string.IsNullOrEmpty(parsedData.Error)) - onSuccessCallback?.Invoke(parsedData); + if (DataKnownAndNotEmpty(data)) + { + var parsedData = ParseJson(data); + + if (string.IsNullOrEmpty(parsedData.Error)) + onSuccessCallback?.Invoke(parsedData); + else + onErrorCallback?.Invoke(parsedData.Error); + } else - onErrorCallback?.Invoke(parsedData.Error); - } - else - { - onErrorCallback?.Invoke($"get_manipulators invalid response: {data}"); - } - }).Emit("get_manipulators"); + { + onErrorCallback?.Invoke($"get_manipulators invalid response: {data}"); + } + }) + .Emit("get_manipulators"); } /// @@ -244,16 +280,21 @@ public void GetManipulators(Action onSuccessCallback, /// The ID of the manipulator to register /// Callback function to handle a successful registration /// Callback function to handle errors - public void RegisterManipulator(string manipulatorId, Action onSuccessCallback = null, - Action onErrorCallback = null) + public void RegisterManipulator( + string manipulatorId, + Action onSuccessCallback = null, + Action onErrorCallback = null + ) { - _connectionManager.Socket.ExpectAcknowledgement(error => - { - if (string.IsNullOrEmpty(error)) - onSuccessCallback?.Invoke(); - else - onErrorCallback?.Invoke($"register_manipulators invalid response: {error}"); - }).Emit("register_manipulator", manipulatorId); + _connectionManager + .Socket.ExpectAcknowledgement(error => + { + if (string.IsNullOrEmpty(error)) + onSuccessCallback?.Invoke(); + else + onErrorCallback?.Invoke($"register_manipulators invalid response: {error}"); + }) + .Emit("register_manipulator", manipulatorId); } /// @@ -262,16 +303,23 @@ public void RegisterManipulator(string manipulatorId, Action onSuccessCallback = /// The ID of the manipulator to unregister /// Callback function to handle a successful un-registration /// Callback function to handle errors - public void UnregisterManipulator(string manipulatorId, Action onSuccessCallback = null, - Action onErrorCallback = null) + public void UnregisterManipulator( + string manipulatorId, + Action onSuccessCallback = null, + Action onErrorCallback = null + ) { - _connectionManager.Socket.ExpectAcknowledgement(error => - { - if (string.IsNullOrEmpty(error)) - onSuccessCallback?.Invoke(); - else - onErrorCallback?.Invoke($"unregister_manipulator invalid response: {error}"); - }).Emit("unregister_manipulator", manipulatorId); + _connectionManager + .Socket.ExpectAcknowledgement(error => + { + if (string.IsNullOrEmpty(error)) + onSuccessCallback?.Invoke(); + else + onErrorCallback?.Invoke( + $"unregister_manipulator invalid response: {error}" + ); + }) + .Emit("unregister_manipulator", manipulatorId); } /// @@ -280,25 +328,30 @@ public void UnregisterManipulator(string manipulatorId, Action onSuccessCallback /// ID of the manipulator to get the position of /// Callback function to pass manipulator position to /// Callback function to handle errors - public void GetPos(string manipulatorId, Action onSuccessCallback, - Action onErrorCallback = null) + public void GetPos( + string manipulatorId, + Action onSuccessCallback, + Action onErrorCallback = null + ) { - _connectionManager.Socket.ExpectAcknowledgement(data => - { - if (DataKnownAndNotEmpty(data)) + _connectionManager + .Socket.ExpectAcknowledgement(data => { - var parsedData = ParseJson(data); - - if (string.IsNullOrEmpty(parsedData.Error)) - onSuccessCallback?.Invoke(parsedData.Position); + if (DataKnownAndNotEmpty(data)) + { + var parsedData = ParseJson(data); + + if (string.IsNullOrEmpty(parsedData.Error)) + onSuccessCallback?.Invoke(parsedData.Position); + else + onErrorCallback?.Invoke(parsedData.Error); + } else - onErrorCallback?.Invoke(parsedData.Error); - } - else - { - onErrorCallback?.Invoke($"get_pos invalid response: {data}"); - } - }).Emit("get_pos", manipulatorId); + { + onErrorCallback?.Invoke($"get_pos invalid response: {data}"); + } + }) + .Emit("get_pos", manipulatorId); } /// @@ -307,44 +360,54 @@ public void GetPos(string manipulatorId, Action onSuccessCallback, /// ID of the manipulator to get the position of /// Callback function to pass manipulator angles to /// Callback function to handle errors - public void GetAngles(string manipulatorId, Action onSuccessCallback, - Action onErrorCallback = null) + public void GetAngles( + string manipulatorId, + Action onSuccessCallback, + Action onErrorCallback = null + ) { - _connectionManager.Socket.ExpectAcknowledgement(data => - { - if (DataKnownAndNotEmpty(data)) + _connectionManager + .Socket.ExpectAcknowledgement(data => { - var parsedData = ParseJson(data); - if (string.IsNullOrEmpty(parsedData.Error)) - onSuccessCallback?.Invoke(parsedData.Angles); + if (DataKnownAndNotEmpty(data)) + { + var parsedData = ParseJson(data); + if (string.IsNullOrEmpty(parsedData.Error)) + onSuccessCallback?.Invoke(parsedData.Angles); + else + onErrorCallback?.Invoke(parsedData.Error); + } else - onErrorCallback?.Invoke(parsedData.Error); - } - else - { - onErrorCallback?.Invoke($"get_angles invalid response: {data}"); - } - }).Emit("get_angles", manipulatorId); + { + onErrorCallback?.Invoke($"get_angles invalid response: {data}"); + } + }) + .Emit("get_angles", manipulatorId); } - public void GetShankCount(string manipulatorId, Action onSuccessCallback, - Action onErrorCallback = null) + public void GetShankCount( + string manipulatorId, + Action onSuccessCallback, + Action onErrorCallback = null + ) { - _connectionManager.Socket.ExpectAcknowledgement(data => - { - if (DataKnownAndNotEmpty(data)) + _connectionManager + .Socket.ExpectAcknowledgement(data => { - var parsedData = ParseJson(data); - if (string.IsNullOrEmpty(parsedData.Error)) - onSuccessCallback?.Invoke(parsedData.ShankCount); + if (DataKnownAndNotEmpty(data)) + { + var parsedData = ParseJson(data); + if (string.IsNullOrEmpty(parsedData.Error)) + onSuccessCallback?.Invoke(parsedData.ShankCount); + else + onErrorCallback?.Invoke(parsedData.Error); + } else - onErrorCallback?.Invoke(parsedData.Error); - } - else - { - onErrorCallback?.Invoke($"get_shank_count invalid response: {data}"); - } - }).Emit("get_shank_count", manipulatorId); + { + onErrorCallback?.Invoke($"get_shank_count invalid response: {data}"); + } + }) + .Emit("get_shank_count", manipulatorId); } /// @@ -354,24 +417,29 @@ public void GetShankCount(string manipulatorId, Action onSuccessCallback, /// Goto position request object /// Callback function to handle successful manipulator movement /// Callback function to handle errors - public void GotoPos(GotoPositionRequest request, Action onSuccessCallback, - Action onErrorCallback = null) + public void GotoPos( + GotoPositionRequest request, + Action onSuccessCallback, + Action onErrorCallback = null + ) { - _connectionManager.Socket.ExpectAcknowledgement(data => - { - if (DataKnownAndNotEmpty(data)) + _connectionManager + .Socket.ExpectAcknowledgement(data => { - var parsedData = ParseJson(data); - if (string.IsNullOrEmpty(parsedData.Error)) - onSuccessCallback?.Invoke(parsedData.Position); + if (DataKnownAndNotEmpty(data)) + { + var parsedData = ParseJson(data); + if (string.IsNullOrEmpty(parsedData.Error)) + onSuccessCallback?.Invoke(parsedData.Position); + else + onErrorCallback?.Invoke(parsedData.Error); + } else - onErrorCallback?.Invoke(parsedData.Error); - } - else - { - onErrorCallback?.Invoke($"goto_pos invalid response: {data}"); - } - }).Emit("goto_pos", ToJson(request)); + { + onErrorCallback?.Invoke($"goto_pos invalid response: {data}"); + } + }) + .Emit("goto_pos", ToJson(request)); } /// @@ -380,24 +448,29 @@ public void GotoPos(GotoPositionRequest request, Action onSuccessCallba /// Drive to depth request /// Callback function to handle successful manipulator movement /// Callback function to handle errors - public void DriveToDepth(DriveToDepthRequest request, Action onSuccessCallback, - Action onErrorCallback) + public void DriveToDepth( + DriveToDepthRequest request, + Action onSuccessCallback, + Action onErrorCallback + ) { - _connectionManager.Socket.ExpectAcknowledgement(data => - { - if (DataKnownAndNotEmpty(data)) + _connectionManager + .Socket.ExpectAcknowledgement(data => { - var parsedData = ParseJson(data); - if (string.IsNullOrEmpty(parsedData.Error)) - onSuccessCallback?.Invoke(parsedData.Depth); + if (DataKnownAndNotEmpty(data)) + { + var parsedData = ParseJson(data); + if (string.IsNullOrEmpty(parsedData.Error)) + onSuccessCallback?.Invoke(parsedData.Depth); + else + onErrorCallback?.Invoke(parsedData.Error); + } else - onErrorCallback?.Invoke(parsedData.Error); - } - else - { - onErrorCallback?.Invoke($"drive_to_depth invalid response: {data}"); - } - }).Emit("drive_to_depth", ToJson(request)); + { + onErrorCallback?.Invoke($"drive_to_depth invalid response: {data}"); + } + }) + .Emit("drive_to_depth", ToJson(request)); } /// @@ -406,24 +479,29 @@ public void DriveToDepth(DriveToDepthRequest request, Action onSuccessCal /// /// Callback function to handle setting inside_brain state successfully /// Callback function to handle errors - public void SetInsideBrain(InsideBrainRequest request, Action onSuccessCallback, - Action onErrorCallback = null) + public void SetInsideBrain( + InsideBrainRequest request, + Action onSuccessCallback, + Action onErrorCallback = null + ) { - _connectionManager.Socket.ExpectAcknowledgement(data => - { - if (DataKnownAndNotEmpty(data)) + _connectionManager + .Socket.ExpectAcknowledgement(data => { - var parsedData = ParseJson(data); - if (string.IsNullOrEmpty(parsedData.Error)) - onSuccessCallback?.Invoke(parsedData.State); + if (DataKnownAndNotEmpty(data)) + { + var parsedData = ParseJson(data); + if (string.IsNullOrEmpty(parsedData.Error)) + onSuccessCallback?.Invoke(parsedData.State); + else + onErrorCallback?.Invoke(parsedData.Error); + } else - onErrorCallback?.Invoke(parsedData.Error); - } - else - { - onErrorCallback?.Invoke($"set_inside_brain invalid response: {data}"); - } - }).Emit("set_inside_brain", ToJson(request)); + { + onErrorCallback?.Invoke($"set_inside_brain invalid response: {data}"); + } + }) + .Emit("set_inside_brain", ToJson(request)); } /// @@ -432,15 +510,21 @@ public void SetInsideBrain(InsideBrainRequest request, Action onSuccessCal /// ID of the manipulator to be calibrated /// Callback function to handle a successful calibration /// Callback function to handle an unsuccessful calibration - public void Calibrate(string manipulatorId, Action onSuccessCallback, Action onErrorCallback = null) + public void Calibrate( + string manipulatorId, + Action onSuccessCallback, + Action onErrorCallback = null + ) { - _connectionManager.Socket.ExpectAcknowledgement(error => - { - if (error == "") - onSuccessCallback?.Invoke(); - else - onErrorCallback?.Invoke(error); - }).Emit("calibrate", manipulatorId); + _connectionManager + .Socket.ExpectAcknowledgement(error => + { + if (error == "") + onSuccessCallback?.Invoke(); + else + onErrorCallback?.Invoke(error); + }) + .Emit("calibrate", manipulatorId); } /// @@ -450,16 +534,21 @@ public void Calibrate(string manipulatorId, Action onSuccessCallback, ActionID of the manipulator to bypass calibration /// Callback function to handle a successful calibration bypass /// Callback function to handle errors - public void BypassCalibration(string manipulatorId, Action onSuccessCallback, - Action onErrorCallback = null) + public void BypassCalibration( + string manipulatorId, + Action onSuccessCallback, + Action onErrorCallback = null + ) { - _connectionManager.Socket.ExpectAcknowledgement(error => - { - if (error == "") - onSuccessCallback?.Invoke(); - else - onErrorCallback?.Invoke(error); - }).Emit("bypass_calibration", manipulatorId); + _connectionManager + .Socket.ExpectAcknowledgement(error => + { + if (error == "") + onSuccessCallback?.Invoke(); + else + onErrorCallback?.Invoke(error); + }) + .Emit("bypass_calibration", manipulatorId); } /// @@ -468,24 +557,29 @@ public void BypassCalibration(string manipulatorId, Action onSuccessCallback, /// /// Callback function to handle successfully setting can_write state /// Callback function to handle errors - public void SetCanWrite(CanWriteRequest request, Action onSuccessCallback, - Action onErrorCallback = null) + public void SetCanWrite( + CanWriteRequest request, + Action onSuccessCallback, + Action onErrorCallback = null + ) { - _connectionManager.Socket.ExpectAcknowledgement(data => - { - if (DataKnownAndNotEmpty(data)) + _connectionManager + .Socket.ExpectAcknowledgement(data => { - var parsedData = ParseJson(data); - if (string.IsNullOrEmpty(parsedData.Error)) - onSuccessCallback?.Invoke(parsedData.State); + if (DataKnownAndNotEmpty(data)) + { + var parsedData = ParseJson(data); + if (string.IsNullOrEmpty(parsedData.Error)) + onSuccessCallback?.Invoke(parsedData.State); + else + onErrorCallback?.Invoke(parsedData.Error); + } else - onErrorCallback?.Invoke(parsedData.Error); - } - else - { - onErrorCallback?.Invoke($"set_can_write invalid response: {data}"); - } - }).Emit("set_can_write", ToJson(request)); + { + onErrorCallback?.Invoke($"set_can_write invalid response: {data}"); + } + }) + .Emit("set_can_write", ToJson(request)); } /// @@ -518,4 +612,4 @@ private string ToJson(T data) #endregion } -} \ No newline at end of file +} diff --git a/Assets/Scripts/Pinpoint/UI/EphysLinkSettings/EphysLinkSettings.cs b/Assets/Scripts/Pinpoint/UI/EphysLinkSettings/EphysLinkSettings.cs index 1957fecf..b287000e 100644 --- a/Assets/Scripts/Pinpoint/UI/EphysLinkSettings/EphysLinkSettings.cs +++ b/Assets/Scripts/Pinpoint/UI/EphysLinkSettings/EphysLinkSettings.cs @@ -20,28 +20,51 @@ public class EphysLinkSettings : MonoBehaviour { #region Constants - private const string EPHYS_LINK_EXE_NAME = "EphysLink-v1.3.0b1.exe"; - private static string EphysLinkExePath => Path.Combine(Application.streamingAssetsPath, EPHYS_LINK_EXE_NAME); + private const string EPHYS_LINK_EXE_NAME = "EphysLink-v1.3.0b2.exe"; + private static string EphysLinkExePath => + Path.Combine(Application.streamingAssetsPath, EPHYS_LINK_EXE_NAME); #endregion #region Components // Server connection - [SerializeField] private TMP_Dropdown _manipulatorTypeDropdown; - [SerializeField] private TMP_InputField _pathfinderPortInputField; - [SerializeField] private Button _launchEphysLinkButton; - [SerializeField] private GameObject _existingServerGroup; - [SerializeField] private TMP_InputField _ipAddressInputField; - [SerializeField] private InputField _portInputField; - [SerializeField] private GameObject _connectButton; - [SerializeField] private Text _connectButtonText; - [SerializeField] private TMP_Text _connectionErrorText; + [SerializeField] + private TMP_Dropdown _manipulatorTypeDropdown; + + [SerializeField] + private TMP_InputField _pathfinderPortInputField; + + [SerializeField] + private Button _launchEphysLinkButton; + + [SerializeField] + private GameObject _existingServerGroup; + + [SerializeField] + private TMP_InputField _ipAddressInputField; + + [SerializeField] + private InputField _portInputField; + + [SerializeField] + private GameObject _connectButton; + + [SerializeField] + private Text _connectButtonText; + + [SerializeField] + private TMP_Text _connectionErrorText; // Manipulators - [SerializeField] private GameObject _manipulatorList; - [SerializeField] private GameObject _manipulatorConnectionPanelPrefab; - [SerializeField] private Toggle _copilotToggle; + [SerializeField] + private GameObject _manipulatorList; + + [SerializeField] + private GameObject _manipulatorConnectionPanelPrefab; + + [SerializeField] + private Toggle _copilotToggle; private UIManager _uiManager; @@ -49,9 +72,10 @@ public class EphysLinkSettings : MonoBehaviour #region Properties - private readonly Dictionary - _manipulatorIdToManipulatorConnectionSettingsPanel = new(); + private readonly Dictionary< + string, + (ManipulatorConnectionPanel manipulatorConnectionSettingsPanel, GameObject gameObject) + > _manipulatorIdToManipulatorConnectionSettingsPanel = new(); public HashSet LinkedProbes { get; } = new(); public UnityEvent ShouldUpdateProbesListEvent { get; } = new(); @@ -88,7 +112,9 @@ public void OnTypeChanged(int type) // Show/hide extra groups based on connection type _existingServerGroup.SetActive(type == _manipulatorTypeDropdown.options.Count - 1); _connectButton.SetActive(type == _manipulatorTypeDropdown.options.Count - 1); - _launchEphysLinkButton.gameObject.SetActive(type != _manipulatorTypeDropdown.options.Count - 1); + _launchEphysLinkButton.gameObject.SetActive( + type != _manipulatorTypeDropdown.options.Count - 1 + ); _pathfinderPortInputField.gameObject.SetActive(type == 2); // Save settings @@ -106,56 +132,83 @@ private void UpdateManipulatorPanels() if (CommunicationManager.Instance.IsConnected) { - CommunicationManager.Instance.GetManipulators((response) => - { - // Keep track of handled manipulator panels - var handledManipulatorIds = new HashSet(); - - // Add any new manipulators in scene to list - foreach (var manipulatorID in response.Manipulators) + CommunicationManager.Instance.GetManipulators( + (response) => { - // Create new manipulator connection settings panel if the manipulator is new - if (!_manipulatorIdToManipulatorConnectionSettingsPanel.ContainsKey(manipulatorID)) + // Keep track of handled manipulator panels + var handledManipulatorIds = new HashSet(); + + // Add any new manipulators in scene to list + foreach (var manipulatorID in response.Manipulators) { - // Instantiate panel - var manipulatorConnectionSettingsPanelGameObject = - Instantiate(_manipulatorConnectionPanelPrefab, _manipulatorList.transform); - var manipulatorConnectionSettingsPanel = - manipulatorConnectionSettingsPanelGameObject - .GetComponent(); - - // Set manipulator id - manipulatorConnectionSettingsPanel.Initialize(this, manipulatorID, response.NumAxes); - - // Add to dictionary - _manipulatorIdToManipulatorConnectionSettingsPanel.Add(manipulatorID, - new ValueTuple( - manipulatorConnectionSettingsPanel, manipulatorConnectionSettingsPanelGameObject)); + // Create new manipulator connection settings panel if the manipulator is new + if ( + !_manipulatorIdToManipulatorConnectionSettingsPanel.ContainsKey( + manipulatorID + ) + ) + { + // Instantiate panel + var manipulatorConnectionSettingsPanelGameObject = Instantiate( + _manipulatorConnectionPanelPrefab, + _manipulatorList.transform + ); + var manipulatorConnectionSettingsPanel = + manipulatorConnectionSettingsPanelGameObject.GetComponent(); + + // Set manipulator id + manipulatorConnectionSettingsPanel.Initialize( + this, + manipulatorID, + response.NumAxes + ); + + // Add to dictionary + _manipulatorIdToManipulatorConnectionSettingsPanel.Add( + manipulatorID, + new ValueTuple( + manipulatorConnectionSettingsPanel, + manipulatorConnectionSettingsPanelGameObject + ) + ); + } + + // Mark ID as handled + handledManipulatorIds.Add(manipulatorID); } - // Mark ID as handled - handledManipulatorIds.Add(manipulatorID); - } + // Remove any manipulators that are not connected anymore + foreach ( + var disconnectedManipulator in _manipulatorIdToManipulatorConnectionSettingsPanel + .Keys.Except(handledManipulatorIds) + .ToList() + ) + { + _manipulatorIdToManipulatorConnectionSettingsPanel.Remove( + disconnectedManipulator + ); + Destroy( + _manipulatorIdToManipulatorConnectionSettingsPanel[ + disconnectedManipulator + ].gameObject + ); + } - // Remove any manipulators that are not connected anymore - foreach (var disconnectedManipulator in _manipulatorIdToManipulatorConnectionSettingsPanel.Keys - .Except(handledManipulatorIds).ToList()) - { - _manipulatorIdToManipulatorConnectionSettingsPanel.Remove(disconnectedManipulator); - Destroy(_manipulatorIdToManipulatorConnectionSettingsPanel[disconnectedManipulator].gameObject); + // Reorder panels to match order of availableIds + foreach (var manipulatorId in response.Manipulators) + _manipulatorIdToManipulatorConnectionSettingsPanel[manipulatorId] + .gameObject.transform.SetAsLastSibling(); } - - // Reorder panels to match order of availableIds - foreach (var manipulatorId in response.Manipulators) - _manipulatorIdToManipulatorConnectionSettingsPanel[manipulatorId].gameObject.transform - .SetAsLastSibling(); - }); + ); } else { // Clear manipulator panels if not connected - foreach (var manipulatorPanel in - _manipulatorIdToManipulatorConnectionSettingsPanel.Values.Select(value => value.gameObject)) + foreach ( + var manipulatorPanel in _manipulatorIdToManipulatorConnectionSettingsPanel.Values.Select( + value => value.gameObject + ) + ) Destroy(manipulatorPanel); _manipulatorIdToManipulatorConnectionSettingsPanel.Clear(); } @@ -208,7 +261,10 @@ public void OnLaunchEphysLinkPressed() void ConnectToServer() { - CommunicationManager.Instance.ConnectToServer("localhost", 8081, HandleSuccessfulConnection, + CommunicationManager.Instance.ConnectToServer( + "localhost", + 8081, + HandleSuccessfulConnection, err => { attempts++; @@ -217,14 +273,19 @@ void ConnectToServer() _connectionErrorText.text = err; _connectButtonText.text = "Connect"; - _manipulatorTypeDropdown.interactable = !CommunicationManager.Instance.IsConnected; - _launchEphysLinkButton.interactable = !CommunicationManager.Instance.IsConnected; + _manipulatorTypeDropdown.interactable = !CommunicationManager + .Instance + .IsConnected; + _launchEphysLinkButton.interactable = !CommunicationManager + .Instance + .IsConnected; } else { ConnectToServer(); } - }); + } + ); } } @@ -246,9 +307,11 @@ public void OnConnectDisconnectPressed() if (string.IsNullOrEmpty(_portInputField.text)) _portInputField.text = "8081"; - CommunicationManager.Instance.ConnectToServer(_ipAddressInputField.text, + CommunicationManager.Instance.ConnectToServer( + _ipAddressInputField.text, int.Parse(_portInputField.text), - HandleSuccessfulConnection, err => + HandleSuccessfulConnection, + err => { _connectionErrorText.text = err; _connectButtonText.text = "Connect"; @@ -266,7 +329,8 @@ public void OnConnectDisconnectPressed() QuestionDialogue.Instance.YesCallback = HandleDisconnectingFromServer; QuestionDialogue.Instance.NewQuestion( - "Are you sure you want to disconnect?\nAll incomplete movements will be canceled."); + "Are you sure you want to disconnect?\nAll incomplete movements will be canceled." + ); } } @@ -294,30 +358,38 @@ public void InvokeShouldUpdateProbesListEvent() private void HandleSuccessfulConnection() { // Check Ephys Link version - CommunicationManager.Instance.VerifyVersion(() => - { - // Ephys Link is current enough - CommunicationManager.Instance.IsEphysLinkCompatible = true; - UpdateConnectionPanel(); - }, () => - { - CommunicationManager.Instance.DisconnectFromServer(() => + CommunicationManager.Instance.VerifyVersion( + () => { - _connectionErrorText.text = - "Ephys Link is outdated. Please update to " + - CommunicationManager.EPHYS_LINK_MIN_VERSION_STRING; - _connectButtonText.text = "Connect"; - }); - }); + // Ephys Link is current enough + CommunicationManager.Instance.IsEphysLinkCompatible = true; + UpdateConnectionPanel(); + }, + () => + { + CommunicationManager.Instance.DisconnectFromServer(() => + { + _connectionErrorText.text = + "Ephys Link is outdated. Please update to " + + CommunicationManager.EPHYS_LINK_MIN_VERSION_STRING; + _connectButtonText.text = "Connect"; + }); + } + ); } private void HandleDisconnectingFromServer() { - foreach (var probeManager in ProbeManager.Instances - .Where(probeManager => probeManager.IsEphysLinkControlled)) + foreach ( + var probeManager in ProbeManager.Instances.Where(probeManager => + probeManager.IsEphysLinkControlled + ) + ) { - probeManager.SetIsEphysLinkControlled(false, - probeManager.ManipulatorBehaviorController.ManipulatorID); + probeManager.SetIsEphysLinkControlled( + false, + probeManager.ManipulatorBehaviorController.ManipulatorID + ); // FIXME: This is done because of race condition with closing out server. Should be fixed with non-registration setup. probeManager.ManipulatorBehaviorController.Deinitialize(); @@ -335,10 +407,14 @@ private void HandleDisconnectingFromServer() /// private void UpdateConnectionPanel() { - if (CommunicationManager.Instance.IsConnected && !CommunicationManager.Instance.IsEphysLinkCompatible) + if ( + CommunicationManager.Instance.IsConnected + && !CommunicationManager.Instance.IsEphysLinkCompatible + ) { _connectionErrorText.text = - "Ephys Link is outdated. Please update to " + CommunicationManager.EPHYS_LINK_MIN_VERSION_STRING; + "Ephys Link is outdated. Please update to " + + CommunicationManager.EPHYS_LINK_MIN_VERSION_STRING; _connectButtonText.text = "Connect"; CommunicationManager.Instance.DisconnectFromServer(); return; @@ -346,7 +422,9 @@ private void UpdateConnectionPanel() // Connection UI _connectionErrorText.text = ""; - _connectButtonText.text = CommunicationManager.Instance.IsConnected ? "Disconnect" : "Connect"; + _connectButtonText.text = CommunicationManager.Instance.IsConnected + ? "Disconnect" + : "Connect"; _connectButton.SetActive(CommunicationManager.Instance.IsConnected); _manipulatorTypeDropdown.interactable = !CommunicationManager.Instance.IsConnected; @@ -358,7 +436,8 @@ private void UpdateConnectionPanel() private void KillEphysLinkProcess() { - if (_ephysLinkProcess == null) return; + if (_ephysLinkProcess == null) + return; _ephysLinkProcess.Kill(true); _ephysLinkProcess.Dispose(); _ephysLinkProcess = null; @@ -366,4 +445,4 @@ private void KillEphysLinkProcess() #endregion } -} \ No newline at end of file +} diff --git a/Assets/StreamingAssets/EphysLink-v1.3.0b1.exe b/Assets/StreamingAssets/EphysLink-v1.3.0b2.exe similarity index 98% rename from Assets/StreamingAssets/EphysLink-v1.3.0b1.exe rename to Assets/StreamingAssets/EphysLink-v1.3.0b2.exe index 682ee9b8..fea950c5 100644 Binary files a/Assets/StreamingAssets/EphysLink-v1.3.0b1.exe and b/Assets/StreamingAssets/EphysLink-v1.3.0b2.exe differ diff --git a/Assets/StreamingAssets/EphysLink-v1.3.0b1.exe.meta b/Assets/StreamingAssets/EphysLink-v1.3.0b2.exe.meta similarity index 74% rename from Assets/StreamingAssets/EphysLink-v1.3.0b1.exe.meta rename to Assets/StreamingAssets/EphysLink-v1.3.0b2.exe.meta index c3115ad5..6dda3e94 100644 --- a/Assets/StreamingAssets/EphysLink-v1.3.0b1.exe.meta +++ b/Assets/StreamingAssets/EphysLink-v1.3.0b2.exe.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 539f2f9af7e829a4e987b7e68e462e75 +guid: b7782d59c912fe547b89e361d2ea2d3a DefaultImporter: externalObjects: {} userData: