diff --git a/Editor/Scripts/SceneMenuItems.cs b/Editor/Scripts/SceneMenuItems.cs index 72e3ead..fae1395 100644 --- a/Editor/Scripts/SceneMenuItems.cs +++ b/Editor/Scripts/SceneMenuItems.cs @@ -33,13 +33,13 @@ private static bool ValidateLoadSnapshot() [MenuItem("Open Commissioning/Scene/Create Configuration", priority = 20)] private static void CreateConfiguration() { - SceneConfiguration.Create(); + SceneConfigurationManager.Save(); } [MenuItem("Open Commissioning/Scene/Load Configuration", priority = 21)] private static void LoadConfiguration() { - SceneConfiguration.Load(); + SceneConfigurationManager.Load(); } [MenuItem("Open Commissioning/Settings/Apply Default Layers", priority = 100)] diff --git a/Runtime/Scripts/Communication/Client/Client.cs b/Runtime/Scripts/Communication/Client/Client.cs index a9eecd7..2d9fdfe 100644 --- a/Runtime/Scripts/Communication/Client/Client.cs +++ b/Runtime/Scripts/Communication/Client/Client.cs @@ -15,11 +15,6 @@ public abstract class Client : MonoBehaviour, IClient, IConfigAsset, IAfterFixed public IPropertyReadOnly IsConnected => _isConnected; public abstract IClientBuffer Buffer { get; } public string RootName => _rootName; - public bool Verbose - { - get => _verbose; - set => _verbose = value; - } public float TimeScale { @@ -33,8 +28,6 @@ public float TimeScale [Header("Settings")] [SerializeField] protected string _rootName = "MAIN"; - [SerializeField] - protected bool _verbose; [HideInInspector] [SerializeField] diff --git a/Runtime/Scripts/Communication/Client/TwinCAT/TcAdsClient.cs b/Runtime/Scripts/Communication/Client/TwinCAT/TcAdsClient.cs index 336faa0..b5a5ce4 100644 --- a/Runtime/Scripts/Communication/Client/TwinCAT/TcAdsClient.cs +++ b/Runtime/Scripts/Communication/Client/TwinCAT/TcAdsClient.cs @@ -10,18 +10,16 @@ namespace OC.Communication.TwinCAT public class TcAdsClient : Client { public override IClientBuffer Buffer => _adsClientBuffer; - public bool AutoConnect => _autoConnect; - public string NetId => _netId; - public int Port => _port; + + public TcAdsClientConfig Config + { + get => _config; + set => _config = value; + } [Header("ADS")] [SerializeField] - private bool _autoConnect; - [SerializeField] - private string _netId = "Local"; - [SerializeField] - [Tooltip("Port range [301...399], [851...899]")] - private int _port = 851; + private TcAdsClientConfig _config = TcAdsClientConfig.Default; private TcClientStateHandler _clientStateHandler; private IClientBuffer _adsClientBuffer; @@ -37,7 +35,7 @@ public class TcAdsClient : Client base.Start(); _clientStateHandler = new TcClientStateHandler(); _clientStateHandler.OnStateChanged += OnClientStateChanged; - _clientStateHandler.Connect(_netId); + _clientStateHandler.Connect(_config.NetId); } public override void BeforeFixedUpdate() @@ -54,7 +52,7 @@ public override void AfterFixedUpdate() private void OnClientStateChanged(TcAdsExtension.TcClientState state) { - if (!_autoConnect) return; + if (!_config.Reconnect) return; switch (state) { @@ -77,26 +75,26 @@ public override void Connect() try { - _ = ValidatePort(_port); + _ = ValidatePort(_config.Port); if (!_clientStateHandler.IsRunning) { throw new Exception("Target system isn't in run mode"); } - var tcAdsBufferType = GetTcAdsBufferType(_port); + var tcAdsBufferType = GetTcAdsBufferType(_config.Port); switch (tcAdsBufferType) { case TcAdsBufferType.None: - throw new Exception($"Port:{_port} is out of range [301...399], [851...899]"); + throw new Exception($"Port:{_config.Port} is out of range [301...399], [851...899]"); case TcAdsBufferType.Array: _adsClientBuffer = new TcAdsTaskBuffer(this); - _adsClientBuffer.Connect(_netId, _port); + _adsClientBuffer.Connect(_config.NetId, _config.Port); break; case TcAdsBufferType.SumCommand: _adsClientBuffer = new TcAdsSumCommandBuffer(this); - _adsClientBuffer.Connect(_netId, _port); + _adsClientBuffer.Connect(_config.NetId, _config.Port); break; default: throw new ArgumentOutOfRangeException(); @@ -107,7 +105,7 @@ public override void Connect() catch (Exception exception) { _isConnected.Value = false; - Logging.Logger.Log(LogType.Error, $"TcAdsClient failed to connect: {_netId}:{_port}. {exception.Message}. \n{exception.Source}{exception.StackTrace}"); + Logging.Logger.Log(LogType.Error, $"TcAdsClient failed to connect: {_config.NetId}:{_config.Port}. {exception.Message}. \n{exception.Source}{exception.StackTrace}"); } } @@ -177,7 +175,7 @@ private bool ValidatePort(int port) { > 300 and < 400 => true, > 850 and < 900 => true, - _ => throw new Exception($"Port:{_port} is out of range [301...399], [851...899]") + _ => throw new Exception($"Port:{_config.Port} is out of range [301...399], [851...899]") }; } @@ -193,8 +191,7 @@ private TcAdsBufferType GetTcAdsBufferType(int port) public override XElement GetAsset() { - var config = new TcAdsClientConfig(this); - var element = config.ToXElement(); + var element = _config.ToXElement(); element.SetAttributeValue("Name", name); return element; } @@ -203,11 +200,7 @@ public override void SetAsset(XElement xElement) { try { - var config = xElement.FromXElement(); - _autoConnect = config.Reconnect; - _netId = config.NetId; - _port = config.Port; - _verbose = config.Verbose; + _config = xElement.FromXElement(); } catch (Exception exception) { diff --git a/Runtime/Scripts/Communication/Client/TwinCAT/TcAdsClientConfig.cs b/Runtime/Scripts/Communication/Client/TwinCAT/TcAdsClientConfig.cs index 589d4b2..6eb9267 100644 --- a/Runtime/Scripts/Communication/Client/TwinCAT/TcAdsClientConfig.cs +++ b/Runtime/Scripts/Communication/Client/TwinCAT/TcAdsClientConfig.cs @@ -1,34 +1,70 @@ using System; +using UnityEngine; namespace OC.Communication.TwinCAT { [Serializable] - public struct TcAdsClientConfig + public class TcAdsClientConfig { - public string Name; - public bool Reconnect; - public string NetId; - public int Port; - public bool Verbose; + public string Name + { + get => _name; + set => _name = value; + } - public TcAdsClientConfig(string name, bool reconnect, string netId, int port, bool verbose = false) + public bool Reconnect { - Name = name; - Reconnect = reconnect; - NetId = netId; - Port = port; - Verbose = verbose; + get => _reconnect; + set => _reconnect = value; } - public TcAdsClientConfig(TcAdsClient tcAdsClient) + public string NetId { - Name = tcAdsClient.name; - Reconnect = tcAdsClient.AutoConnect; - NetId = tcAdsClient.NetId; - Port = tcAdsClient.Port; - Verbose = tcAdsClient.Verbose; + get => _netId; + set => _netId = value; } - public static TcAdsClientConfig Default => new ("Client", true, "Local", 351); + public int Port + { + get => _port; + set => _port = value; + } + + public bool ClearBuffer + { + get => _clearBuffer; + set => _clearBuffer = value; + } + + public bool Verbose + { + get => _verbose; + set => _verbose = value; + } + + [SerializeField] + private string _name; + [SerializeField] + private bool _reconnect; + [SerializeField] + private string _netId; + [Tooltip("Port range [301...399], [851...899]")] + [SerializeField] + private int _port; + [Tooltip("If Disconnected, process data will be overwrite with null")] + [SerializeField] + private bool _clearBuffer; + [SerializeField] + private bool _verbose; + + public static TcAdsClientConfig Default => new () + { + Name = "Client", + Reconnect = true, + NetId = "Local", + Port = 351, + ClearBuffer = true, + Verbose = false + }; } } \ No newline at end of file diff --git a/Runtime/Scripts/Communication/Client/TwinCAT/TcAdsSumCommandBuffer.cs b/Runtime/Scripts/Communication/Client/TwinCAT/TcAdsSumCommandBuffer.cs index f550310..bef6a80 100644 --- a/Runtime/Scripts/Communication/Client/TwinCAT/TcAdsSumCommandBuffer.cs +++ b/Runtime/Scripts/Communication/Client/TwinCAT/TcAdsSumCommandBuffer.cs @@ -20,7 +20,7 @@ public class TcAdsSumCommandBuffer : IClientBuffer private readonly List _outputVariables = new(); private readonly List _inputSymbols = new(); private readonly List _outputSymbols = new(); - private readonly Client _client; + private readonly TcAdsClient _client; private AdsClient _adsClient; private string _netId; private int _port; @@ -33,7 +33,7 @@ public class TcAdsSumCommandBuffer : IClientBuffer private bool _isConnected; - public TcAdsSumCommandBuffer(Client client) + public TcAdsSumCommandBuffer(TcAdsClient client) { _client = client; } @@ -54,7 +54,7 @@ public void Connect(string netId, int port) public void Disconnect() { - WriteNullData(); + if (_client.Config.ClearBuffer) WriteNullData(); Clear(); _adsClient?.Disconnect(); _isConnected = false; @@ -121,14 +121,14 @@ private void Initialize() { _inputSymbols.Add(adsSymbol); _inputSize += symbol.ByteSize; - if (_client.Verbose) Logging.Logger.Log(LogType.Log, Logging.Logger.VERBOSE_TAG + " Find ADS Variable:" + $"{symbol.InstancePath} : {symbol.TypeName} : TcOutput"); + if (_client.Config.Verbose) Logging.Logger.Log(LogType.Log, Logging.Logger.VERBOSE_TAG + " Find ADS Variable:" + $"{symbol.InstancePath} : {symbol.TypeName} : TcOutput"); break; } case 0xF020: { _outputSymbols.Add(adsSymbol); _outputSize += symbol.ByteSize; - if (_client.Verbose) Logging.Logger.Log(LogType.Log, Logging.Logger.VERBOSE_TAG + " Find ADS Variable:" + $"{symbol.InstancePath} : {symbol.TypeName} : TcInput"); + if (_client.Config.Verbose) Logging.Logger.Log(LogType.Log, Logging.Logger.VERBOSE_TAG + " Find ADS Variable:" + $"{symbol.InstancePath} : {symbol.TypeName} : TcInput"); break; } } diff --git a/Runtime/Scripts/Communication/Client/TwinCAT/TcAdsTaskBuffer.cs b/Runtime/Scripts/Communication/Client/TwinCAT/TcAdsTaskBuffer.cs index 3954869..7478ea4 100644 --- a/Runtime/Scripts/Communication/Client/TwinCAT/TcAdsTaskBuffer.cs +++ b/Runtime/Scripts/Communication/Client/TwinCAT/TcAdsTaskBuffer.cs @@ -22,7 +22,7 @@ public class TcAdsTaskBuffer : IClientBuffer private readonly List _outputVariables = new(); private readonly List _inputSymbols = new(); private readonly List _outputSymbols = new(); - private readonly Client _client; + private readonly TcAdsClient _client; private AdsClient _adsClient; private string _netId; private int _port; @@ -33,7 +33,7 @@ public class TcAdsTaskBuffer : IClientBuffer private byte[] _outputBuffer; private bool _isConnected; - public TcAdsTaskBuffer(Client client) + public TcAdsTaskBuffer(TcAdsClient client) { _client = client; } @@ -54,7 +54,7 @@ public void Connect(string netId, int port) public void Disconnect() { - WriteNullData(); + if (_client.Config.ClearBuffer) WriteNullData(); Clear(); _adsClient?.Disconnect(); _isConnected = false; @@ -172,7 +172,7 @@ private void AddSymbol(IAdsSymbol symbol) throw new ArgumentOutOfRangeException(); } - if (_client.Verbose) Logging.Logger.Log(LogType.Log, Logging.Logger.VERBOSE_TAG + " Find ADS Variable:" + $"{symbol.InstancePath} : {symbol.TypeName} : {direction}"); + if (_client.Config.Verbose) Logging.Logger.Log(LogType.Log, Logging.Logger.VERBOSE_TAG + " Find ADS Variable:" + $"{symbol.InstancePath} : {symbol.TypeName} : {direction}"); } catch (Exception exception) { diff --git a/Runtime/Scripts/System/ConfigurationManager.cs b/Runtime/Scripts/System/ConfigurationManager.cs index c637e4d..530bd4c 100644 --- a/Runtime/Scripts/System/ConfigurationManager.cs +++ b/Runtime/Scripts/System/ConfigurationManager.cs @@ -30,7 +30,7 @@ private static void RuntimeInit() private void OnEnable() { - SceneConfiguration.LoadFromDefaultPath(); + SceneConfigurationManager.LoadFile(); } private void Start() @@ -43,7 +43,7 @@ private void Start() [Button] public void SaveConfig() { - SceneConfiguration.SaveInDefaultPath(); + SceneConfigurationManager.SaveFile(); } public void ConnectClients() diff --git a/Runtime/Scripts/System/SceneConfiguration.cs b/Runtime/Scripts/System/SceneConfiguration.cs index 6b1e156..c89d768 100644 --- a/Runtime/Scripts/System/SceneConfiguration.cs +++ b/Runtime/Scripts/System/SceneConfiguration.cs @@ -1,164 +1,77 @@ -using System; using System.Collections.Generic; -using UnityEngine; using System.IO; using System.Linq; -using System.Xml.Linq; using OC.Communication.TwinCAT; using OC.Data; -using UnityEngine.SceneManagement; -using Object = UnityEngine.Object; +using Unity.Plastic.Newtonsoft.Json; +using UnityEngine; namespace OC.Project { - public static class SceneConfiguration + public class SceneConfiguration { - private const string CONFIG_FILE_NAME = "Config"; - private const string TAG = "Scene Configuration Manager"; - private const string ROOT = "SceneConfiguration"; - - public static void Create() - { - var path = FileBrowser.SaveFilePanel("Create Scene Configuration", Application.streamingAssetsPath, GetFileName(), "json"); - if (string.IsNullOrEmpty(path)) - { - return; - } - - CreateConfigurationFile(path); - } - - public static void Load() + public string SceneName; + // ReSharper disable once FieldCanBeMadeReadOnly.Local + // ReSharper disable once CollectionNeverQueried.Local + public List Clients = new (); + // ReSharper disable once NotAccessedField.Local + public List Directories = new (); + + public SceneConfiguration Create(string sceneName) { - var paths = FileBrowser.OpenFilePanel("Load Scene Configuration", Application.streamingAssetsPath, "xml", false); - if (paths == null || paths.Length == 0) - { - return; - } - - var path = paths[0]; - if (string.IsNullOrEmpty(path)) + SceneName = sceneName; + Clients.Clear(); + var clients = Object.FindObjectsByType(sortMode: FindObjectsSortMode.InstanceID).OfType().ToList(); + foreach (var client in clients) { - return; + Clients.Add(client.Config); } - LoadConfiguration(path); + var directories = Object.FindObjectsByType(sortMode: FindObjectsSortMode.InstanceID).OfType().ToList(); + if (directories.Count > 0) Directories = directories[0].ProductDataDirectories; + return this; } - public static void LoadFromDefaultPath() + public void Save(string path) { - var path = GetDefaultFilePath(); - LoadConfiguration(path); - } - - public static void SaveInDefaultPath() - { - var path = GetDefaultFilePath(); - CreateConfigurationFile(path); + var data = JsonConvert.SerializeObject(this, Formatting.Indented); + File.WriteAllText(path, data); } - private static void LoadConfiguration(string path) + public SceneConfiguration Load(string path) { - try - { - if (!File.Exists(path)) - { - return; - } - - using var stream = File.Open(path, FileMode.Open); - var document = XDocument.Load(stream); - - var root = document.Descendants(ROOT).FirstOrDefault(); - if (root is null) - { - throw new Exception($"{TAG} Configuration isn't valid! {path}"); - } - - - - var configAssets = Object.FindObjectsByType(sortMode: FindObjectsSortMode.InstanceID).OfType().ToList(); - foreach (var item in configAssets) - { - if (TryFindElementByAttribute(root, item.Component.name, out var asset)) - { - item.SetAsset(asset); - } - } - - Logging.Logger.Log(LogType.Log, $"{TAG} Configuration loaded {path}"); - - } - catch (Exception exception) + if (!File.Exists(path)) { - Logging.Logger.LogError(exception); + throw new FileLoadException($"Path: {path} isn't valid!"); } + + using var stream = File.OpenRead(path); + var config = JsonConvert.DeserializeObject(new StreamReader(stream).ReadToEnd()); + Clients = config.Clients; + Directories = config.Directories; + return this; } - private static void CreateConfigurationFile(string path) + public void ApplyToActiveScene() { - try + var clients = Object.FindObjectsByType(sortMode: FindObjectsSortMode.InstanceID).ToList(); + var productDataDiractoryManagers = Object.FindObjectsByType(sortMode: FindObjectsSortMode.InstanceID).ToList(); + + foreach (var client in clients) { - var config = new Configuration(); - var clients = Object.FindObjectsByType(sortMode: FindObjectsSortMode.InstanceID).OfType().ToList(); - - foreach (var client in clients) + foreach (var tcAdsClientConfig in Clients) { - config.Clients.Add(new TcAdsClientConfig(client)); + if (string.Equals(client.Config.Name, tcAdsClientConfig.Name)) + { + client.Config = tcAdsClientConfig; + } } - - var directories = Object.FindObjectsByType(sortMode: FindObjectsSortMode.InstanceID).OfType().ToList(); - if (directories.Count > 0) config.Directories = directories[0].ProductDataDirectories; - - var data = JsonUtility.ToJson(config); - File.WriteAllText(path, data); - - Logging.Logger.Log(LogType.Log, $"{TAG} Saved Client Configuration to {path}"); } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - } - private static string GetFileName() - { - var sceneName = SceneManager.GetActiveScene().name.Replace(" ", "_").Replace(".", "_"); - return $"{sceneName}_{CONFIG_FILE_NAME}"; - } - - private static string GetDefaultFilePath() - { - if (!Directory.Exists(Application.streamingAssetsPath)) + foreach (var productDataDiractoryManager in productDataDiractoryManagers) { - Directory.CreateDirectory(Application.streamingAssetsPath); + productDataDiractoryManager.ProductDataDirectories = Directories; } - - return $"{Application.streamingAssetsPath}/{GetFileName()}"; - } - - private static bool TryFindElementByAttribute(XContainer root, string value, out XElement xElement) - { - xElement = root.Elements().FirstOrDefault(element => element.Attribute("Name")?.Value == value); - return xElement is not null; - } - - private static XDocument CreateEmpty() - { - var document = new XDocument(); - var root = new XElement(ROOT); - document.Add(root); - return document; - } - - private class Configuration - { - // ReSharper disable once FieldCanBeMadeReadOnly.Local - // ReSharper disable once CollectionNeverQueried.Local - public List Clients = new (); - // ReSharper disable once NotAccessedField.Local - public List Directories = new (); } } -} +} \ No newline at end of file diff --git a/Runtime/Scripts/System/SceneConfiguration.cs.meta b/Runtime/Scripts/System/SceneConfiguration.cs.meta index 3d6738a..b098d5d 100644 --- a/Runtime/Scripts/System/SceneConfiguration.cs.meta +++ b/Runtime/Scripts/System/SceneConfiguration.cs.meta @@ -1,11 +1,3 @@ fileFormatVersion: 2 -guid: a5df4343d4da0c44bbd439c3ae014509 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +guid: 60e239f6c2cd4515bf7a988b9f5d9dbe +timeCreated: 1738935972 \ No newline at end of file diff --git a/Runtime/Scripts/System/SceneConfigurationManager.cs b/Runtime/Scripts/System/SceneConfigurationManager.cs new file mode 100644 index 0000000..40c6bca --- /dev/null +++ b/Runtime/Scripts/System/SceneConfigurationManager.cs @@ -0,0 +1,89 @@ +using System; +using UnityEngine; +using System.IO; +using OC.Data; +using UnityEngine.SceneManagement; + +namespace OC.Project +{ + public static class SceneConfigurationManager + { + private const string CONFIG_FILE_NAME = "Config"; + private const string TAG = "Scene Configuration Manager"; + private const string ROOT = "SceneConfiguration"; + + public static void Save() + { + var path = FileBrowser.SaveFilePanel("Create Scene Configuration", Application.streamingAssetsPath, GetFileName(), "json"); + if (string.IsNullOrEmpty(path)) + { + return; + } + + SaveFile(path); + } + + public static void Load() + { + var paths = FileBrowser.OpenFilePanel("Load Scene Configuration", Application.streamingAssetsPath, "json", false); + if (paths == null || paths.Length == 0) + { + return; + } + + var path = paths[0]; + if (string.IsNullOrEmpty(path)) return; + + LoadFile(path); + } + + public static void LoadFile(string path) + { + try + { + path = Path.ChangeExtension(path, "json"); + new SceneConfiguration().Load(path).ApplyToActiveScene(); + Logging.Logger.Log(LogType.Log, $"{TAG} Configuration loaded {path}"); + } + catch (Exception exception) + { + Logging.Logger.Log(LogType.Error, $"{TAG} {exception}"); + } + } + + public static void SaveFile(string path) + { + try + { + path = Path.ChangeExtension(path, "json"); + new SceneConfiguration().Create(GetActiveSceneName()).Save(path); + Logging.Logger.Log(LogType.Log, $"{TAG} Configuration saved {path}"); + } + catch (Exception exception) + { + Logging.Logger.Log(LogType.Error, $"{TAG} {exception}"); + } + } + + public static void LoadFile() => LoadFile(GetDefaultFilePath()); + + public static void SaveFile() => SaveFile(GetDefaultFilePath()); + + private static string GetFileName() => $"{GetActiveSceneName()}_{CONFIG_FILE_NAME}"; + + private static string GetActiveSceneName() + { + return SceneManager.GetActiveScene().name.Replace(" ", "_").Replace(".", "_"); + } + + private static string GetDefaultFilePath() + { + if (!Directory.Exists(Application.streamingAssetsPath)) + { + Directory.CreateDirectory(Application.streamingAssetsPath); + } + + return $"{Application.streamingAssetsPath}/{GetFileName()}"; + } + } +} diff --git a/Runtime/Scripts/System/SceneConfigurationManager.cs.meta b/Runtime/Scripts/System/SceneConfigurationManager.cs.meta new file mode 100644 index 0000000..3d6738a --- /dev/null +++ b/Runtime/Scripts/System/SceneConfigurationManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a5df4343d4da0c44bbd439c3ae014509 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: