diff options
Diffstat (limited to 'Software/Visual_Studio/Tango.Integration')
48 files changed, 1658 insertions, 5191 deletions
diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeClientConnectedEventArgs.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeClientConnectedEventArgs.cs index e976898ef..2bfe60477 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeClientConnectedEventArgs.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeClientConnectedEventArgs.cs @@ -9,30 +9,10 @@ namespace Tango.Integration.ExternalBridge { public class ExternalBridgeClientConnectedEventArgs : EventArgs { - private Action _confirmAction; - private Action<String> _declineAction; - public ExternalBridgeLoginRequest Request { get; set; } - public String Address { get; set; } - - public ApplicationInformation ApplicationInformation { get; set; } - - public ExternalBridgeClientConnectedEventArgs(Action confirmAction, Action<String> declineAction) - { - _confirmAction = confirmAction; - _declineAction = declineAction; - ApplicationInformation = new ApplicationInformation(); - } - - public void Confirm() - { - _confirmAction?.Invoke(); - } + public String IpAddress { get; set; } - public void Decline(String reason) - { - _declineAction?.Invoke(reason); - } + public bool Confirmed { get; set; } } } diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiver.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiver.cs deleted file mode 100644 index 143f21f42..000000000 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiver.cs +++ /dev/null @@ -1,710 +0,0 @@ -using Google.Protobuf; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Net.Sockets; -using System.Security.Authentication; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Tango.Core; -using Tango.Core.ExtensionMethods; -using Tango.Integration.Operation; -using Tango.PMR; -using Tango.PMR.Common; -using Tango.PMR.Debugging; -using Tango.PMR.Diagnostics; -using Tango.PMR.IFS; -using Tango.PMR.Integration; -using Tango.PMR.MachineStatus; -using Tango.PMR.Power; -using Tango.Transport; -using Tango.Transport.Adapters; -using Tango.Transport.Transporters; - -namespace Tango.Integration.ExternalBridge -{ - public class ExternalBridgeReceiver : BasicTransporter - { - /// <summary> - /// A dictionary containing the last time a user name has made a request or response. - /// This is used to bypass the safety operations confirmation. - /// FullName, Contact Time - /// </summary> - public static Dictionary<String, DateTime> LastSafetyLevelContactsTimes { get; private set; } - - #region Message Handler - - private class MessageHandler - { - public Action<MessageContainer> Method { get; set; } - public bool RequiresLogin { get; set; } - public ExternalBridgeLoginIntent LoginIntent { get; set; } - - public MessageHandler(Action<MessageContainer> method) - { - Method = method; - } - - public MessageHandler(Action<MessageContainer> method, ExternalBridgeLoginIntent intent) : this(method) - { - RequiresLogin = true; - LoginIntent = intent; - } - } - - #endregion - - private String _eventsToken; - private String _machineStatusToken; - private String _diagnosticsToken; - private String _debugLogsToken; - private String _applicationLogsToken; - private String _inkFillingToken; - - private IMachineOperator _machineOperator; - private Dictionary<MessageType, MessageHandler> _messageHandlers; - - #region Events - - public event EventHandler<ExternalBridgeReceiverLoginRequestEventArgs> LoginRequest; - public event EventHandler<ColorProfileRequestEventArgs> ColorProfileRequest; - public event EventHandler Disconnected; - public event EventHandler<ExternalBridgeReceiverRequestReceivedEventArgs> ReceiverRequestReceived; - - #endregion - - #region Properties - - public bool AllowSafetyLevelOperations { get; set; } - - public bool RequiresDiagnostics { get; private set; } - public bool RequiresDebugLogs { get; private set; } - public bool RequiresEventsNotification { get; private set; } - public bool RequiresMachineStatusUpdate { get; private set; } - public bool RequiresApplicationLogs { get; private set; } - public bool RequiresInkFillingStatus { get; private set; } - - public bool IsLoggedIn { get; private set; } - public ExternalBridgeLoginIntent LoginIntent { get; private set; } - public String UserName { get; private set; } - - private ExternalBridgeLoginRequest _loginInfo; - public ExternalBridgeLoginRequest LoginInfo - { - get { return _loginInfo; } - set { _loginInfo = value; RaisePropertyChangedAuto(); } - } - - public bool IsLoggedInAndRequiresDiagnostics - { - get { return IsLoggedIn && (LoginIntent == ExternalBridgeLoginIntent.Diagnostics || LoginIntent == ExternalBridgeLoginIntent.FullControl); } - } - - - #endregion - - #region Constructors - - static ExternalBridgeReceiver() - { - LastSafetyLevelContactsTimes = new Dictionary<string, DateTime>(); - } - - public ExternalBridgeReceiver(IMachineOperator machineOperator) - { - ComponentName = $"External Bridge Receiver {_component_counter++}"; - - FailsWithAdapter = true; - - _machineOperator = machineOperator; - - _messageHandlers = new Dictionary<MessageType, MessageHandler>(); - UseKeepAlive = false; - KeepAliveTimeout = TimeSpan.FromSeconds(10); - KeepAliveRetries = 4; - - _messageHandlers.Add(MessageType.ExternalBridgeLoginRequest, new MessageHandler(OnExternalBridgeLoginRequest)); - _messageHandlers.Add(MessageType.ExternalBridgeLogoutRequest, new MessageHandler(OnExternalBridgeLogoutRequest)); - - _messageHandlers.Add(MessageType.ColorProfileRequest, new MessageHandler(OnColorProfileRequest)); - - _messageHandlers.Add(MessageType.StartDiagnosticsRequest, new MessageHandler(OnStartDiagnosticsRequest, ExternalBridgeLoginIntent.Diagnostics)); - _messageHandlers.Add(MessageType.StopDiagnosticsRequest, new MessageHandler(OnStopDiagnosticsRequest, ExternalBridgeLoginIntent.Diagnostics)); - - _messageHandlers.Add(MessageType.StartDebugLogRequest, new MessageHandler(OnStartDebugLogRequest, ExternalBridgeLoginIntent.Diagnostics)); - _messageHandlers.Add(MessageType.StopDebugLogRequest, new MessageHandler(OnStopDebugLogRequest, ExternalBridgeLoginIntent.Diagnostics)); - - _messageHandlers.Add(MessageType.StartEventsNotificationRequest, new MessageHandler(OnStartEventsNotificationRequest, ExternalBridgeLoginIntent.Diagnostics)); - _messageHandlers.Add(MessageType.StopEventsNotificationRequest, new MessageHandler(OnStopEventsNotificationRequest, ExternalBridgeLoginIntent.Diagnostics)); - - _messageHandlers.Add(MessageType.StartMachineStatusUpdateRequest, new MessageHandler(OnStartMachineStatusUpdateRequest, ExternalBridgeLoginIntent.Diagnostics)); - _messageHandlers.Add(MessageType.StopMachineStatusUpdateRequest, new MessageHandler(OnStopMachineStatusUpdateRequest, ExternalBridgeLoginIntent.Diagnostics)); - - _messageHandlers.Add(MessageType.StartApplicationLogsRequest, new MessageHandler(OnStartApplicationLogsRequest, ExternalBridgeLoginIntent.Diagnostics)); - _messageHandlers.Add(MessageType.StopApplicationLogsRequest, new MessageHandler(OnStopApplicationLogsRequest, ExternalBridgeLoginIntent.Diagnostics)); - - _messageHandlers.Add(MessageType.JobRequest, new MessageHandler(OnJobRequest, ExternalBridgeLoginIntent.Diagnostics)); - - _messageHandlers.Add(MessageType.StartPowerDownRequest, new MessageHandler(OnStartPowerDownRequest, ExternalBridgeLoginIntent.Diagnostics)); - - _messageHandlers.Add(MessageType.StartInkFillingStatusRequest, new MessageHandler(OnStartInkFillingStatusRequest, ExternalBridgeLoginIntent.Diagnostics)); - } - - public ExternalBridgeReceiver(TcpClient tcpClient, IMachineOperator machineOperator) : this(machineOperator) - { - Adapter = new TcpTransportAdapter(tcpClient); - } - - public ExternalBridgeReceiver(SignalRTransportAdapter signalRAdapter, IMachineOperator machineOperator) : this(machineOperator) - { - Adapter = signalRAdapter; - } - - #endregion - - #region Override Methods - - protected override void OnRequestReceived(RequestReceivedEventArgs e) - { - base.OnRequestReceived(e); - - if (e.Handled) return; - - var container = e.Container; - - try - { - if (e.Container.Type == MessageType.ConfigureProtocolRequest) - { - var message = MessageFactory.ParseTangoMessageFromContainer<ConfigureProtocolRequest>(container); - SendResponse(new ConfigureProtocolResponse() { Confirmed = true }, container.Token, new TransportResponseConfig() { Immediate = true, Priority = QueuePriority.High }); - - Task.Factory.StartNew(() => - { - Thread.Sleep(200); - Adapter.EnableCompression = message.Message.EnableCompression; - GenericProtocol = message.Message.GenericProtocol; - }); - return; - } - - if (!AllowSafetyLevelOperations) - { - if (ExternalBridgeService.SafetyLevelOperations.Contains(container.Type)) - { - SendErrorResponse(new AuthenticationException("The specified action requires safety level permission that is not granted for the current session."), container.Token); - return; - } - } - else - { - if (UserName != null) - { - LastSafetyLevelContactsTimes[UserName] = DateTime.Now; - } - } - - if (_messageHandlers.ContainsKey(container.Type)) - { - var handler = _messageHandlers[container.Type]; - - if (handler.RequiresLogin && (!IsLoggedIn || (int)handler.LoginIntent > (int)LoginIntent)) - { - SendErrorResponse(new AuthenticationException("The specified intent does not grant the specified action."), container.Token); - return; - } - - try - { - try - { - handler.Method.Invoke(container); - } - catch (Exception ex) - { - SendErrorResponse(ex, container.Token); - } - } - catch (Exception ex) - { - if (ex is ResponseErrorException) - { - SendResponse((ex as ResponseErrorException).Container); - } - else - { - SendErrorResponse(ex, container.Token); - } - } - } - else - { - if (IsLoggedIn) - { - ExternalBridgeReceiverRequestReceivedEventArgs args = new ExternalBridgeReceiverRequestReceivedEventArgs(); - args.Container = container; - ReceiverRequestReceived?.Invoke(this, args); - - if (!args.Handled) - { - OnAnyRequest(container); - } - } - } - } - catch (Exception ex) - { - LogManager.Log(ex, "Error occurred in processing request message on external bridge receiver."); - } - } - - protected override void OnFailed(Exception ex) - { - if (ex is KeepAliveException) - { - LogManager.Log("External bridge client has failed to provide a keep alive response. Disconnecting session..."); - } - - base.OnFailed(ex); - OnDisconnected(); - } - - public async override Task Disconnect() - { - try - { - if (IsLoggedIn) - { - await SendRequest<ExternalBridgeLogoutRequest, ExternalBridgeLogoutResponse>(new ExternalBridgeLogoutRequest(), new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(3), ShouldLog = true }); - } - } - catch (Exception ex) - { - LogManager.Log(ex, "Error sending an external bridge log out request."); - } - finally - { - ClearQueues(); - } - - try - { - IsLoggedIn = false; - await base.Disconnect(); - } - catch { } - - OnDisconnected(); - } - - #endregion - - #region Virtual Methods - - protected virtual void OnDisconnected() - { - Disconnected?.Invoke(this, new EventArgs()); - } - - #endregion - - #region Message Handlers - - protected virtual void OnExternalBridgeLoginRequest(MessageContainer container) - { - var request = MessageFactory.ParseTangoMessageFromContainer<ExternalBridgeLoginRequest>(container); - - LogManager.Log($"External bridge login attempt:\nIntent: {request.Message.Intent}\nMessage:\n{request.Message.ToJsonString()}"); - - ExternalBridgeReceiverLoginRequestEventArgs args = new ExternalBridgeReceiverLoginRequestEventArgs((machine, deviceInfo, applicationInfo) => - { - //Confirm - LogManager.Log("External bridge client has logged-in successfully."); - - IsLoggedIn = true; - LoginIntent = request.Message.Intent; - UserName = request.Message.UserName; - LoginInfo = request.Message; - - var response = new ExternalBridgeLoginResponse(); - response.Authenticated = true; - response.SerialNumber = machine.SerialNumber; - response.DeviceInformation = deviceInfo; - response.ApplicationInformation = applicationInfo; - - AllowSafetyLevelOperations = request.Message.RequireSafetyLevelOperations; - - SendResponse<ExternalBridgeLoginResponse>(response, container.Token); - - UpdateMachineOperatorStatus((UpdateStatus)_machineOperator.Status); - - UseKeepAlive = true; - - if (AllowSafetyLevelOperations && UserName != null) - { - LastSafetyLevelContactsTimes[UserName] = DateTime.Now; - } - }, - (reason) => - { - //Decline - SendResponse<ExternalBridgeLoginResponse>(new ExternalBridgeLoginResponse(), container.Token, new TransportResponseConfig() { ErrorCode = ErrorCode.GeneralError, ErrorMessage = reason }); - Disconnect().GetAwaiter().GetResult(); - }); - - args.Address = Adapter.Address; - args.Request = request; - - LoginRequest?.Invoke(this, args); - } - - protected virtual void OnExternalBridgeLogoutRequest(MessageContainer container) - { - try - { - SendResponse<ExternalBridgeLogoutResponse>(new ExternalBridgeLogoutResponse(), container.Token); - } - catch (Exception ex) - { - LogManager.Log(ex); - } - finally - { - OnDisconnected(); - ClearQueues(); - } - } - - protected async virtual void OnAnyRequest(MessageContainer container) - { - if (!container.Continuous) - { - try - { - var response = await _machineOperator.SendRequest(container); - await SendResponse(response); - } - catch (Exception ex) - { - await SendErrorResponse(ex, container.Token); - } - } - else - { - try - { - _machineOperator.SendContinuousRequest(container).Subscribe((response) => - { - if (State == TransportComponentState.Connected) - { - SendResponse(response); - } - - }, (ex) => - { - if (State == TransportComponentState.Connected) - { - if (ex is ResponseErrorException) - { - SendResponse((ex as ResponseErrorException).Container); - } - else if (ex is ContinuousResponseAbortedException) - { - SendResponse((ex as ContinuousResponseAbortedException).Container); - } - } - }); - } - catch (Exception ex) - { - await SendErrorResponse(ex, container.Token); - } - } - } - - protected virtual void OnColorProfileRequest(MessageContainer container) - { - var request = MessageFactory.ParseTangoMessageFromContainer<ColorProfileRequest>(container); - - ColorProfileRequestEventArgs e = new ColorProfileRequestEventArgs(request, async () => - { - //Approved. - await SendResponse<ColorProfileResponse>(new ColorProfileResponse() - { - Approved = true - }, container.Token); - await Task.Delay(500); - await base.Disconnect(); - }, - async () => - { - //Declined. - await SendResponse<ColorProfileResponse>(new ColorProfileResponse(), container.Token); - await Task.Delay(500); - await base.Disconnect(); - }); - - ColorProfileRequest?.Invoke(this, e); - } - - protected virtual void OnStartDiagnosticsRequest(MessageContainer container) - { - _diagnosticsToken = container.Token; - SendResponse<StartDiagnosticsResponse>(new StartDiagnosticsResponse(), _diagnosticsToken); - RequiresDiagnostics = true; - } - - protected virtual void OnStopDiagnosticsRequest(MessageContainer container) - { - if (_diagnosticsToken != null) - { - RequiresDiagnostics = false; - SendResponse<StartDiagnosticsResponse>(new StartDiagnosticsResponse(), _diagnosticsToken, new TransportResponseConfig() { Completed = true }); - _diagnosticsToken = null; - SendResponse<StopDiagnosticsResponse>(new StopDiagnosticsResponse(), container.Token); - } - } - - protected virtual void OnStartDebugLogRequest(MessageContainer container) - { - _debugLogsToken = container.Token; - SendResponse<StartDebugLogResponse>(new StartDebugLogResponse(), _debugLogsToken); - RequiresDebugLogs = true; - } - - protected virtual void OnStopDebugLogRequest(MessageContainer container) - { - if (_debugLogsToken != null) - { - RequiresDebugLogs = false; - SendResponse<StartDebugLogResponse>(new StartDebugLogResponse(), _debugLogsToken, new TransportResponseConfig() { Completed = true }); - _debugLogsToken = null; - SendResponse<StopDebugLogResponse>(new StopDebugLogResponse(), container.Token); - } - } - - protected virtual void OnStartEventsNotificationRequest(MessageContainer container) - { - _eventsToken = container.Token; - SendResponse<StartEventsNotificationResponse>(new StartEventsNotificationResponse(), _eventsToken); - RequiresEventsNotification = true; - } - - protected virtual void OnStopEventsNotificationRequest(MessageContainer container) - { - if (_eventsToken != null) - { - RequiresEventsNotification = false; - SendResponse<StartEventsNotificationResponse>(new StartEventsNotificationResponse(), _eventsToken, new TransportResponseConfig() { Completed = true }); - _eventsToken = null; - SendResponse<StopEventsNotificationResponse>(new StopEventsNotificationResponse(), container.Token); - } - } - - protected virtual void OnStartMachineStatusUpdateRequest(MessageContainer container) - { - _machineStatusToken = container.Token; - SendResponse<StartMachineStatusUpdateResponse>(new StartMachineStatusUpdateResponse(), _machineStatusToken); - RequiresMachineStatusUpdate = true; - } - - protected virtual void OnStopMachineStatusUpdateRequest(MessageContainer container) - { - if (_machineStatusToken != null) - { - RequiresMachineStatusUpdate = false; - SendResponse<StartMachineStatusUpdateResponse>(new StartMachineStatusUpdateResponse(), _machineStatusToken, new TransportResponseConfig() { Completed = true }); - _machineStatusToken = null; - SendResponse<StopMachineStatusUpdateResponse>(new StopMachineStatusUpdateResponse(), container.Token); - } - } - - protected virtual void OnStartApplicationLogsRequest(MessageContainer container) - { - _applicationLogsToken = container.Token; - SendResponse<StartApplicationLogsResponse>(new StartApplicationLogsResponse(), _applicationLogsToken); - RequiresApplicationLogs = true; - } - - protected virtual void OnStopApplicationLogsRequest(MessageContainer container) - { - if (_applicationLogsToken != null) - { - RequiresApplicationLogs = false; - SendResponse<StartApplicationLogsResponse>(new StartApplicationLogsResponse(), _applicationLogsToken, new TransportResponseConfig() { Completed = true }); - _applicationLogsToken = null; - SendResponse<StopApplicationLogsResponse>(new StopApplicationLogsResponse(), container.Token); - } - } - - protected virtual void OnJobRequest(MessageContainer container) - { - if (LoginIntent != ExternalBridgeLoginIntent.FullControl) - { - throw new InvalidOperationException($"Job execution is disabled while session intent is '{LoginIntent}'."); - } - if (_machineOperator.IsPrinting) - { - throw new InvalidOperationException($"Could not execute job while machine operator status is '{_machineOperator.Status}'."); - } - else - { - OnAnyRequest(container); - } - } - - protected virtual void OnStartPowerDownRequest(MessageContainer container) - { - SendResponse(new StartPowerDownResponse() { }, container.Token, new TransportResponseConfig() { ErrorCode = ErrorCode.ContinuousResponseAborted, ErrorMessage = "Power down request is not supported via external bridge." }); - } - - protected virtual void OnStartInkFillingStatusRequest(MessageContainer container) - { - _inkFillingToken = container.Token; - UpdateInkFillingStatus(null); - RequiresInkFillingStatus = true; - } - - #endregion - - #region Continuous Updates - - public void UpdateDiagnostics(MessageContainer container) - { - try - { - if (AllowSafetyLevelOperations && UserName != null) //Usually all clients require diagnostics so we will update the last contact time here.. - { - LastSafetyLevelContactsTimes[UserName] = DateTime.Now; - } - - if (_diagnosticsToken != null) - { - var cloned = container.Clone(); - cloned.Token = _diagnosticsToken; - SendResponse(cloned); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - } - - public void UpdateDebugLogs(MessageContainer container) - { - try - { - if (_debugLogsToken != null) - { - var cloned = container.Clone(); - cloned.Token = _debugLogsToken; - SendResponse(cloned, new TransportResponseConfig() - { - Priority = QueuePriority.Low, - }); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - } - - public void UpdateEvents(MessageContainer container) - { - try - { - if (_eventsToken != null) - { - var cloned = container.Clone(); - cloned.Token = _eventsToken; - SendResponse(cloned); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - } - - public void UpdateMachineStatus(MessageContainer container) - { - try - { - if (_machineStatusToken != null) - { - var cloned = container.Clone(); - cloned.Token = _machineStatusToken; - SendResponse(cloned); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - } - - public void UpdateApplicationLogs(MessageContainer container) - { - try - { - if (_applicationLogsToken != null) - { - var cloned = container.Clone(); - cloned.Token = _applicationLogsToken; - SendResponse(cloned, new TransportResponseConfig() { Priority = QueuePriority.Low }); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - } - - public void UpdateMachineOperatorStatus(UpdateStatus status) - { - try - { - SendRequest<UpdateStatusRequest, UpdateStatusResponse>(new UpdateStatusRequest() - { - Status = status, - }); - } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - } - - public void UpdateInkFillingStatus(MessageContainer container) - { - try - { - if (_inkFillingToken != null) - { - if (container == null) - { - container = new MessageContainer() - { - Continuous = true, - Type = MessageType.StartInkFillingStatusResponse, - Data = ByteString.CopyFrom((new StartInkFillingStatusResponse() { Status = _machineOperator.InkFillingStatus }).ToBytes()) - }; - } - var cloned = container.Clone(); - cloned.Token = _inkFillingToken; - SendResponse(cloned, new TransportResponseConfig()); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - } - - #endregion - } -} diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiverLoginRequestEventArgs.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiverLoginRequestEventArgs.cs deleted file mode 100644 index 1ea33dbce..000000000 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiverLoginRequestEventArgs.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tango.BL.Entities; -using Tango.PMR.Connection; -using Tango.PMR.Integration; - -namespace Tango.Integration.ExternalBridge -{ - public class ExternalBridgeReceiverLoginRequestEventArgs : EventArgs - { - private Action<Machine, DeviceInformation, ApplicationInformation> _confirm; - private Action<String> _decline; - - public ExternalBridgeReceiverLoginRequestEventArgs(Action<Machine, DeviceInformation, ApplicationInformation> confirm, Action<String> decline) - { - _confirm = confirm; - _decline = decline; - } - - public ExternalBridgeLoginRequest Request { get; set; } - - public String Address { get; set; } - - public void Confirm(Machine machine, DeviceInformation deviceInformation, ApplicationInformation applicationInformation) - { - _confirm(machine, deviceInformation, applicationInformation); - } - - public void Decline(String reason) - { - _decline(reason); - } - } -} diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiverRequestReceivedEventArgs.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiverRequestReceivedEventArgs.cs deleted file mode 100644 index 682de264c..000000000 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiverRequestReceivedEventArgs.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tango.PMR.Common; - -namespace Tango.Integration.ExternalBridge -{ - public class ExternalBridgeReceiverRequestReceivedEventArgs - { - public MessageContainer Container { get; set; } - public bool Handled { get; set; } - } -} diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeRequestHandlerMethodAttribute.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeRequestHandlerMethodAttribute.cs deleted file mode 100644 index 7ddedb0b9..000000000 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeRequestHandlerMethodAttribute.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tango.PMR.Common; - -namespace Tango.Integration.ExternalBridge -{ - [AttributeUsage(AttributeTargets.Method)] - public class ExternalBridgeRequestHandlerMethodAttribute : Attribute - { - public Type Type { get; set; } - - public RequestHandlerLoggingMode LoggingMode { get; set; } - - public ExternalBridgeRequestHandlerMethodAttribute(Type type) - { - Type = type; - } - - public ExternalBridgeRequestHandlerMethodAttribute(Type type, RequestHandlerLoggingMode loggingMode) : this(type) - { - LoggingMode = loggingMode; - } - } -} diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeScanner.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeScanner.cs index 694502d2e..b84942643 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeScanner.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeScanner.cs @@ -1,5 +1,4 @@ -using Microsoft.AspNet.SignalR.Client; -using System; +using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; @@ -13,10 +12,8 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; -using Tango.BL.Entities; using Tango.Core; using Tango.Core.Helpers; -using Tango.Integration.ExternalBridge.Web; using Tango.Logging; using Tango.PMR; using Tango.PMR.Common; @@ -34,15 +31,8 @@ namespace Tango.Integration.ExternalBridge { private Thread _tcpDiscoveryThread; private Thread _usbDiscoveryThread; - private Thread _signalRDiscoveryThread; private UdpClient _server; private IntegrationSettings _settings; - private HubConnection _connection; - private IHubProxy _proxy; - - public event EventHandler<IExternalBridgeClient> MachineDiscovered; - - public event EventHandler<IExternalBridgeClient> MachineLost; private SynchronizedObservableCollection<IExternalBridgeClient> _availableMachines; /// <summary> @@ -54,16 +44,6 @@ namespace Tango.Integration.ExternalBridge private set { _availableMachines = value; RaisePropertyChangedAuto(); } } - /// <summary> - /// Gets or sets the SignalR configuration. - /// </summary> - public ExternalBridgeSignalRConfiguration SignalRConfiguration { get; set; } - - /// <summary> - /// Gets or sets the known machines. - /// </summary> - public List<Machine> KnownMachines { get; set; } - private bool _isStarted; /// <summary> /// Gets or sets a value indicating whether this instance is started. @@ -80,14 +60,8 @@ namespace Tango.Integration.ExternalBridge public ExternalBridgeScanner() { _settings = SettingsManager.Default.GetOrCreate<IntegrationSettings>(); + _server = new UdpClient(_settings.ExternalBridgeServiceDiscoveryPort); AvailableMachines = new SynchronizedObservableCollection<IExternalBridgeClient>(); - KnownMachines = new List<Machine>(); - SignalRConfiguration = new ExternalBridgeSignalRConfiguration(); - } - - public ExternalBridgeScanner(List<Machine> knownMachines) : this() - { - KnownMachines = knownMachines; } /// <summary> @@ -99,13 +73,6 @@ namespace Tango.Integration.ExternalBridge { LogManager.Log("External bridge scanner started..."); - if (_server == null) - { - _server = new UdpClient(); - _server.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - _server.Client.Bind(new IPEndPoint(IPAddress.Any, _settings.ExternalBridgeServiceDiscoveryPort)); - } - IsStarted = true; foreach (var machine in AvailableMachines.OfType<ExternalBridgeTcpClient>().ToList()) @@ -113,11 +80,6 @@ namespace Tango.Integration.ExternalBridge AvailableMachines.Remove(machine); } - foreach (var machine in AvailableMachines.OfType<ExternalBridgeSignalRClient>().ToList()) - { - AvailableMachines.Remove(machine); - } - _tcpDiscoveryThread = new Thread(TcpDiscoveryThreadMethod); _tcpDiscoveryThread.IsBackground = true; _tcpDiscoveryThread.Start(); @@ -125,37 +87,6 @@ namespace Tango.Integration.ExternalBridge _usbDiscoveryThread = new Thread(UsbDiscoveryThreadMethod); _usbDiscoveryThread.IsBackground = true; _usbDiscoveryThread.Start(); - - if (SignalRConfiguration.Enabled) - { - try - { - _connection = new HubConnection(SignalRConfiguration.Address); - _proxy = _connection.CreateHubProxy(SignalRConfiguration.Hub); - - bool signalRStarted = false; - - _connection.StateChanged += (x) => - { - if (x.NewState == ConnectionState.Connected) - { - if (!signalRStarted) - { - signalRStarted = true; - _signalRDiscoveryThread = new Thread(SignalRDiscoveryThreadMethod); - _signalRDiscoveryThread.IsBackground = true; - _signalRDiscoveryThread.Start(); - } - } - }; - - _connection.Start(); - } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - } } } @@ -187,9 +118,7 @@ namespace Tango.Integration.ExternalBridge LogManager.Log("Found a new machine via USB " + device.Description); ThreadsHelper.InvokeUINow(() => { - var machine = new ExternalBridgeUsbClient(device.Port, device.Description, _settings.EmbeddedSerialBaudRate); - AvailableMachines.Add(machine); - MachineDiscovered?.Invoke(this, machine); + AvailableMachines.Add(new ExternalBridgeUsbClient(device.Port, device.Description, _settings.EmbeddedSerialBaudRate)); }); } } @@ -202,7 +131,7 @@ namespace Tango.Integration.ExternalBridge /// <summary> /// TCP discovery thread method. /// </summary> - //[DebuggerStepThrough] + [DebuggerStepThrough] private void TcpDiscoveryThreadMethod() { while (IsStarted) @@ -232,7 +161,6 @@ namespace Tango.Integration.ExternalBridge { LogManager.Log("Disconnected machine detected via TCP: " + disconnected_machine.SerialNumber); AvailableMachines.Remove(disconnected_machine); - MachineLost?.Invoke(this, disconnected_machine); } continue; @@ -240,35 +168,14 @@ namespace Tango.Integration.ExternalBridge if (!AvailableMachines.OfType<ExternalBridgeTcpClient>().ToList().Exists(x => x.SerialNumber == packet.SerialNumber && x.IPAddress == address)) { - ExternalBridgeTcpClient newMachine = null; - var knownMachine = KnownMachines.FirstOrDefault(x => x.SerialNumber == packet.SerialNumber); + ExternalBridgeTcpClient newMachine = new ExternalBridgeTcpClient(packet.SerialNumber, address); - if (knownMachine == null && KnownMachines.Count == 0) - { - newMachine = new ExternalBridgeTcpClient(packet.SerialNumber, address); - } - else if (knownMachine != null) - { - newMachine = new ExternalBridgeTcpClient(knownMachine, address); - } + LogManager.Log("Found a new machine via TCP " + newMachine.SerialNumber); - if (newMachine != null) + ThreadsHelper.InvokeUINow(() => { - LogManager.Log("Found a new machine via TCP " + newMachine.SerialNumber); - - ThreadsHelper.InvokeUINow(() => - { - if (AvailableMachines.Count > 0) - { - AvailableMachines.Insert(1, newMachine); - } - else - { - AvailableMachines.Add(newMachine); - } - MachineDiscovered?.Invoke(this, newMachine); - }); - } + AvailableMachines.Insert(1, newMachine); + }); } } catch (Exception ex) @@ -278,65 +185,6 @@ namespace Tango.Integration.ExternalBridge } } - private void SignalRDiscoveryThreadMethod() - { - while (IsStarted && SignalRConfiguration.Enabled) - { - if (_connection.State == ConnectionState.Connected) - { - try - { - var machines = _proxy.Invoke<List<MachineInfo>>("GetAvailableMachines").Result; - - foreach (var machine in AvailableMachines.OfType<ExternalBridgeSignalRClient>().ToList().Where(x => !machines.Exists(y => y.SerialNumber == x.SerialNumber))) - { - AvailableMachines.Remove(machine); - MachineLost?.Invoke(this, machine); - } - - foreach (var machine in machines.Where(x => !AvailableMachines.OfType<ExternalBridgeSignalRClient>().ToList().Exists(y => y.SerialNumber == x.SerialNumber))) - { - ExternalBridgeSignalRClient newMachine = null; - var knownMachine = KnownMachines.FirstOrDefault(x => x.SerialNumber == machine.SerialNumber); - - if (knownMachine == null && KnownMachines.Count == 0) - { - newMachine = new ExternalBridgeSignalRClient(SignalRConfiguration.Address, SignalRConfiguration.Hub, machine); - } - else if (knownMachine != null) - { - newMachine = new ExternalBridgeSignalRClient(SignalRConfiguration.Address, SignalRConfiguration.Hub, knownMachine, machine); - } - - if (newMachine != null) - { - LogManager.Log("Found a new machine via SignalR " + newMachine.SerialNumber); - - ThreadsHelper.InvokeUINow(() => - { - if (AvailableMachines.Count > 0) - { - AvailableMachines.Insert(1, newMachine); - } - else - { - AvailableMachines.Add(newMachine); - } - MachineDiscovered?.Invoke(this, newMachine); - }); - } - } - } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - } - - Thread.Sleep(5000); - } - } - private DateTime ParseDateTime(String dateTime) { try @@ -360,7 +208,6 @@ namespace Tango.Integration.ExternalBridge { LogManager.Log("External bridge client failed or disposed. Removing from available machines..."); AvailableMachines.Remove(sender as IExternalBridgeClient); - MachineLost?.Invoke(this, sender as IExternalBridgeClient); } } } diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeService.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeService.cs index 4218f9e9a..7ad03f3a7 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeService.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeService.cs @@ -21,41 +21,23 @@ using System.Security.Authentication; using Tango.Settings; using Tango.Core.ExtensionMethods; using Tango.PMR.MachineStatus; -using Tango.PMR.Power; -using Tango.Core; -using Microsoft.AspNet.SignalR.Client; -using Tango.Integration.ExternalBridge.Web; -using Tango.Core.Threading; -using System.Diagnostics; -using System.Reflection; -using Newtonsoft.Json; -using System.Collections.ObjectModel; namespace Tango.Integration.ExternalBridge { - public class ExternalBridgeService : ExtendedObject, IExternalBridgeService + public class ExternalBridgeService : BasicTransporter, IExternalBridgeService { - private List<ExternalBridgeReceiver> _receivers; private UdpDiscoveryService<ExternalBridgeUdpDiscoveryPacket> _discoveryService; private TcpServer _tcpServer; + private bool _send_app_logs; + private String _app_logs_token; + private Dictionary<MessageType, Action<MessageContainer>> _messageHandlers; private int _discovery_port = 8888; //Will be overridden by settings in constructor.. private int _external_bridge_port = 1984; //Will be overridden by settings in constructor.. - private HubConnection _connection; - private IHubProxy _proxy; - private bool _isSignalRConnected; - private System.Timers.Timer _signalrPingTimer; - private Dictionary<String, RequestHandler> _requestHandlers; - private static JsonSerializerSettings _genericMessageSettings = new JsonSerializerSettings() - { - TypeNameHandling = TypeNameHandling.All - }; - - private class RequestHandler - { - public IExternalBridgeRequestHandler Handler { get; set; } - public MethodInfo Method { get; set; } - public RequestHandlerLoggingMode LoggingMode { get; set; } - } + private String _eventsNotificationsToken; + private String _machineStatusUpdateToken; + private String _diagnosticsNotificationToken; + private String _debugLogsNotificationToken; + private bool _resend_diagnostics_and_debug; #region Events @@ -67,7 +49,7 @@ namespace Tango.Integration.ExternalBridge /// <summary> /// Occurs when the last client has been disconnected. /// </summary> - public event EventHandler FullControlSessionDisconnected; + public event EventHandler ClientDisconnected; /// <summary> /// Occurs when the service has received a new color profile request. @@ -78,29 +60,6 @@ namespace Tango.Integration.ExternalBridge #region Properties - public static HashSet<MessageType> SafetyLevelOperations { get; private set; } - - /// <summary> - /// Gets the collection of logged-in receivers. - /// </summary> - public List<ExternalBridgeReceiver> ActiveReceivers - { - get - { - return _receivers.Where(x => x.IsLoggedIn).ToList(); - } - } - - /// <summary> - /// Gets or sets the TCP transport adapter write mode when creating a TCP receiver. - /// </summary> - public TcpTransportAdapterWriteMode TcpTransportAdapterWriteMode { get; set; } - - /// <summary> - /// Gets or sets the SignalR configuration. - /// </summary> - public ExternalBridgeSignalRConfiguration SignalRConfiguration { get; set; } - private IMachineOperator _machineOperator; /// <summary> /// Gets or sets the machine operator. @@ -150,60 +109,45 @@ namespace Tango.Integration.ExternalBridge } } - private bool _hasSessions; + private bool _isInSession; /// <summary> - /// Gets a value indicating whether there are any connected sessions. + /// Gets a value indicating whether a remote client is authenticated and in session. /// </summary> - public bool HasSessions + public bool IsInSession { - get { return _hasSessions; } - private set { _hasSessions = value; RaisePropertyChangedAuto(); } + get { return _isInSession; } + private set { _isInSession = value; RaisePropertyChangedAuto(); } } - private ExternalBridgeReceiver _fullControlSessionReceiver; /// <summary> - /// Gets the current full control session receiver. + /// Gets the current session login intent. /// </summary> - public ExternalBridgeReceiver FullControlSessionReceiver - { - get { return _fullControlSessionReceiver; } - private set { _fullControlSessionReceiver = value; RaisePropertyChangedAuto(); } - } + public ExternalBridgeLoginIntent SessionIntent { get; private set; } #endregion #region Constructors /// <summary> - /// Initializes the <see cref="ExternalBridgeService"/> class. - /// </summary> - static ExternalBridgeService() - { - SafetyLevelOperations = new HashSet<MessageType>(); - } - - /// <summary> /// Initializes a new instance of the <see cref="ExternalBridgeService"/> class. /// </summary> public ExternalBridgeService() { - _requestHandlers = new Dictionary<string, RequestHandler>(); - - SignalRConfiguration = new ExternalBridgeSignalRConfiguration(); - - TcpTransportAdapterWriteMode = TcpTransportAdapterWriteMode.Interval; - - _receivers = new List<ExternalBridgeReceiver>(); - var settings = SettingsManager.Default.GetOrCreate<IntegrationSettings>(); _discovery_port = settings.ExternalBridgeServiceDiscoveryPort; _external_bridge_port = settings.ExternalBridgeServicePort; + _messageHandlers = new Dictionary<MessageType, Action<MessageContainer>>(); + RegisterMessageHandlers(); + _tcpServer = new TcpServer(_external_bridge_port); _tcpServer.ClientConnected += _tcpServer_ClientConnected; LogManager.NewLog += LogManager_NewLog; + + KeepAliveTimeout = TimeSpan.FromSeconds(5); + KeepAliveRetries = 2; } /// <summary> @@ -252,12 +196,12 @@ namespace Tango.Integration.ExternalBridge { if (MachineOperator != null) { + MachineOperator.StateChanged -= MachineOperator_StateChanged; + MachineOperator.StateChanged += MachineOperator_StateChanged; MachineOperator.StatusChanged -= MachineOperator_StatusChanged; MachineOperator.StatusChanged += MachineOperator_StatusChanged; MachineOperator.PendingResponseReceived -= MachineOperator_PendingResponseReceived; MachineOperator.PendingResponseReceived += MachineOperator_PendingResponseReceived; - MachineOperator.EventsNotification -= MachineOperator_EventsNotification; - MachineOperator.EventsNotification += MachineOperator_EventsNotification; } } @@ -272,551 +216,603 @@ namespace Tango.Integration.ExternalBridge /// <param name="e">The <see cref="ClientConnectedEventArgs"/> instance containing the event data.</param> private async void _tcpServer_ClientConnected(object sender, ClientConnectedEventArgs e) { - LogManager.Log("External bridge TCP client connected from: " + e.Socket.GetIPAddress()); - ExternalBridgeReceiver receiver = new ExternalBridgeReceiver(e.Socket, MachineOperator); - (receiver.Adapter as TcpTransportAdapter).WriteMode = TcpTransportAdapterWriteMode; - receiver.LoginRequest += Receiver_LoginRequest; - receiver.ColorProfileRequest += Receiver_ColorProfileRequest; - receiver.Disconnected += Receiver_Disconnected; - receiver.ReceiverRequestReceived += Receiver_ReceiverRequestReceived; - _receivers.Add(receiver); - await receiver.Connect(); - RaisePropertyChanged(nameof(ActiveReceivers)); + if (!IsInSession) + { + UseKeepAlive = false; + LogManager.Log("External bridge client connected from: " + e.Socket.GetIPAddress()); + Adapter = new TcpTransportAdapter(e.Socket); + await Connect(); + } + else + { + e.Socket.Dispose(); + } } - private async void OnSignalRSessionCreated(String sessionID) + /// <summary> + /// Machines the operator state changed. + /// </summary> + /// <param name="sender">The sender.</param> + /// <param name="e">The e.</param> + private void MachineOperator_StateChanged(object sender, TransportComponentState e) { - try + //Do nothing right now. + if (e != TransportComponentState.Connected) { - LogManager.Log("External bridge SignalR client connected."); - - var adapter = new SignalRTransportAdapter(SignalRConfiguration.Address, SignalRConfiguration.Hub, SignalRTransportAdapterMode.JoinSession, Machine.SerialNumber, sessionID); ; - - ExternalBridgeReceiver receiver = new ExternalBridgeReceiver(adapter, MachineOperator); - receiver.LoginRequest += Receiver_LoginRequest; - receiver.ColorProfileRequest += Receiver_ColorProfileRequest; - receiver.Disconnected += Receiver_Disconnected; - receiver.ReceiverRequestReceived += Receiver_ReceiverRequestReceived; - _receivers.Add(receiver); - await receiver.Connect(); - RaisePropertyChanged(nameof(ActiveReceivers)); - } - catch (Exception ex) - { - LogManager.Log(ex, "Error initializing SignalR ExternalBridgeReceiver when session created."); + _resend_diagnostics_and_debug = true; } } - private void MachineOperator_StatusChanged(object sender, MachineStatuses status) + private async void MachineOperator_StatusChanged(object sender, MachineStatuses e) { - try + if (e == MachineStatuses.ReadyToDye && _machineOperator.State == TransportComponentState.Connected) { - _receivers.ToList().Where(x => x.IsLoggedInAndRequiresDiagnostics).ToList().ForEach(x => x.UpdateMachineOperatorStatus((UpdateStatus)status)); + if (IsInSession && _resend_diagnostics_and_debug) + { + _resend_diagnostics_and_debug = false; + + if (_diagnosticsNotificationToken != null) + { + var msg = MessageFactory.CreateTangoMessage<StartDiagnosticsRequest>(_diagnosticsNotificationToken); + _machineOperator.SendContinuousRequest<StartDiagnosticsRequest, StartDiagnosticsResponse>(msg); + } + if (_debugLogsNotificationToken != null) + { + var msg = MessageFactory.CreateTangoMessage<StartDebugLogRequest>(_debugLogsNotificationToken); + _machineOperator.SendContinuousRequest<StartDebugLogRequest, StartDebugLogResponse>(msg); + } + } } - catch (Exception ex) + + if (IsInSession) { - LogManager.Log(ex, "Error updating status of external bridge service client."); + try + { + UpdateStatus s = (UpdateStatus)e; + + await SendRequest<UpdateStatusRequest, UpdateStatusResponse>(new UpdateStatusRequest() + { + Status = s, + }); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error updating status of external bridge service client."); + } } } private void LogManager_NewLog(object sender, Tango.Logging.LogItemBase e) { - var toSend = _receivers.ToList().Where(x => x.IsLoggedInAndRequiresDiagnostics && x.RequiresApplicationLogs).ToList(); - - if (_receivers.Count > 0) + if (State == TransportComponentState.Connected && _send_app_logs) { - var msg = MessageFactory.CreateTangoMessage<StartApplicationLogsResponse>(new StartApplicationLogsResponse() + try { - LogItem = ByteString.CopyFrom(e.Serialize()) - }); - - msg.ToBytes(); - - toSend.ToList().Where(x => x.State == TransportComponentState.Connected).ToList().ForEach(x => x.UpdateApplicationLogs(msg.Container)); + SendResponse<StartApplicationLogsResponse>(new StartApplicationLogsResponse() + { + LogItem = ByteString.CopyFrom(e.Serialize()) + }, _app_logs_token); + } + catch { } } } + private void MachineOperator_PendingResponseReceived(object sender, MessageContainer container) { OnOperatorResponseReceived(container); } - private void MachineOperator_EventsNotification(object sender, StartEventsNotificationResponse e) + #endregion + + #region Public Methods + + /// <summary> + /// Starts this instance. + /// </summary> + public void Start() { - try + if (!IsStarted) { - MessageContainer container = new MessageContainer(); - container.Type = MessageType.StartEventsNotificationResponse; - container.Continuous = true; - container.Data = e.ToByteString(); + _tcpServer.Start(); + _discoveryService.Start(); - _receivers.ToList().Where(x => x.IsLoggedInAndRequiresDiagnostics && x.RequiresEventsNotification).ToList().ForEach(x => x.UpdateEvents(container)); - } - catch (Exception ex) - { - LogManager.Log(ex, "Error on external bridge machine events broadcast."); + IsStarted = true; + _enabled = true; + RaisePropertyChanged(nameof(Enabled)); } } - #endregion - - #region Receiver Events Handlers - - private void Receiver_Disconnected(object sender, EventArgs e) + /// <summary> + /// Stops this instance. + /// </summary> + public async void Stop() { - var receiver = sender as ExternalBridgeReceiver; - - receiver.LoginRequest -= Receiver_LoginRequest; - receiver.ColorProfileRequest -= Receiver_ColorProfileRequest; - receiver.Disconnected -= Receiver_Disconnected; - receiver.ReceiverRequestReceived -= Receiver_ReceiverRequestReceived; - - _receivers.Remove(receiver); - - if (receiver.LoginIntent == ExternalBridgeLoginIntent.FullControl) + if (IsStarted) { - FullControlSessionDisconnected?.Invoke(this, new EventArgs()); - } - - HasSessions = _receivers.Count(x => x.IsLoggedIn) > 0; + _tcpServer.Stop(); + _discoveryService.Stop(); - FullControlSessionReceiver = _receivers.SingleOrDefault(x => x.IsLoggedIn && x.LoginIntent == ExternalBridgeLoginIntent.FullControl); + IsStarted = false; + IsInSession = false; + _enabled = false; + RaisePropertyChanged(nameof(Enabled)); - //Notify request handlers about this receiver disconnected. - foreach (var requestHandler in _requestHandlers.ToList().Select(x => x.Value.Handler)) - { try { - requestHandler.OnReceiverDisconnected(receiver); + await Disconnect(); } - catch { } //Ignore exceptions on handler. + catch { } } - - RaisePropertyChanged(nameof(ActiveReceivers)); } - private void Receiver_ColorProfileRequest(object sender, ColorProfileRequestEventArgs e) + /// <summary> + /// Disconnects the current remote client session. + /// </summary> + public async void DisconnectSession() { - ColorProfileRequest?.Invoke(this, e); + await Disconnect(); } - private void Receiver_LoginRequest(object sender, ExternalBridgeReceiverLoginRequestEventArgs e) - { - var request = e.Request; - - if (request.Intent == ExternalBridgeLoginIntent.FullControl && _receivers.Any(x => x.IsLoggedIn && x.LoginIntent == ExternalBridgeLoginIntent.FullControl)) - { - e.Decline("Only one full control client is allowed."); - return; - } - - if (request.Intent == ExternalBridgeLoginIntent.FullControl && MachineOperator.IsPrinting) - { - e.Decline($"External bridge client login failed because the machine is currently printing and '{ExternalBridgeLoginIntent.FullControl}' intent was requested."); - return; - } - - ExternalBridgeClientConnectedEventArgs args = null; - - args = new ExternalBridgeClientConnectedEventArgs(() => - { - //Confirmed - e.Confirm(Machine, MachineOperator.DeviceInformation, args.ApplicationInformation); - HasSessions = true; - - if (request.Intent == ExternalBridgeLoginIntent.FullControl) - { - FullControlSessionReceiver = sender as ExternalBridgeReceiver; - } - - RaisePropertyChanged(nameof(ActiveReceivers)); - }, (reason) => - { - //Declined - e.Decline(reason); - }); + #endregion - args.Request = request; - args.Address = e.Address; - ConnectionRequest?.Invoke(this, args); - } + #region Override Methods - private void Receiver_ReceiverRequestReceived(object sender, ExternalBridgeReceiverRequestReceivedEventArgs e) + protected override void OnRequestReceived(MessageContainer container) { - ExternalBridgeReceiver receiver = sender as ExternalBridgeReceiver; + base.OnRequestReceived(container); - if (e.Container.Type == MessageType.GenericRequest || _requestHandlers.ContainsKey(e.Container.Type.ToString())) + try { - e.Handled = true; - - ThreadFactory.StartNew(() => + if (Enabled) { - try + if (container.Type == MessageType.ConnectRequest || container.Type == MessageType.DisconnectRequest) { - var message = MessageFactory.ExtractMessageFromContainer(e.Container); - - if (e.Container.Type != MessageType.GenericRequest) //Handle standard PMR messages. + //Do nothing ! + } + else + { + if (IsInSession) { - var handler = _requestHandlers[e.Container.Type.ToString()]; - - if (handler.Method.ReturnType == typeof(Task)) + if (container.Type == MessageType.ExternalBridgeLoginRequest) { - ((Task)handler.Method.Invoke(handler.Handler, new object[] - { - message, - e.Container.Token, - sender, - })).Wait(); + SendErrorResponse(new AuthenticationException("Machine is already in session."), container.Token); + return; } - else - { - handler.Method.Invoke(handler.Handler, new object[] - { - message, - e.Container.Token, - sender, - }); - } - } - else //Handle GenericRequest with inner JSON/BSON formated generic message. - { - var genericType = Type.GetType((message as GenericRequest).Type); - if (genericType != null) + if (_messageHandlers.ContainsKey(container.Type)) { try { - if (_requestHandlers.ContainsKey(genericType.FullName)) + try { - var innerMessage = GenericMessageSerializer.DeserializeFromByteString(genericType, (message as GenericRequest).Data, receiver.GenericProtocol); - - var handler = _requestHandlers[genericType.FullName]; - - if (handler.LoggingMode == RequestHandlerLoggingMode.LogRequestName || handler.LoggingMode == RequestHandlerLoggingMode.LogRequestNameAndContent) - { - String content = "."; - - if (handler.LoggingMode == RequestHandlerLoggingMode.LogRequestNameAndContent) - { - content = $":\n{innerMessage.ToJsonString()}"; - } - - LogManager.Log($"'{innerMessage.GetType().Name}' received on '{handler.Method.DeclaringType.Name}.{handler.Method.Name}'{content}"); - } - - if (handler.Method.ReturnType == typeof(Task)) - { - ((Task)handler.Method.Invoke(handler.Handler, new object[] - { - innerMessage, - e.Container.Token, - sender, - })).Wait(); - } - else - { - handler.Method.Invoke(handler.Handler, new object[] - { - innerMessage, - e.Container.Token, - sender, - }); - } + _messageHandlers[container.Type](container); } - else + catch (Exception ex) { - receiver.SendErrorResponse(new NotSupportedException("Request message not supported on this PPC version."), e.Container.Token); + SendErrorResponse(ex, container.Token); } } catch (Exception ex) { - LogManager.Log(ex.GetFirstIfAggregate(), $"Error invoking external bridge handler for request '{genericType.Name}'."); - - try + if (ex is ResponseErrorException) { - receiver.SendErrorResponse(ex.GetFirstIfAggregate(), e.Container.Token); + SendResponse((ex as ResponseErrorException).Container); + } + else + { + SendErrorResponse(ex, container.Token); } - catch { } } } else { - receiver.SendErrorResponse(new NotSupportedException("Request message not supported on this PPC version."), e.Container.Token); + OnAnyRequest(container); } } - } - catch (Exception ex) - { - LogManager.Log(ex, $"An error occurred while trying or invoking an external bridge request handler for '{e.Container.Type}'."); - try + else { - receiver.SendErrorResponse(ex.GetFirstIfAggregate(), e.Container.Token); + if (container.Type == MessageType.ExternalBridgeLoginRequest) + { + OnExternalBridgeLoginRequest(container); + } + else if (container.Type == MessageType.ColorProfileRequest) + { + OnColorProfileRequest(container); + } } - catch { } } - }); + } + } + catch (Exception ex) + { + LogManager.Log(ex, String.Format("An error occurred while processing a request message '{0}' from the remote host.", container.Type)); } } - #endregion + public async override Task Disconnect() + { + _send_app_logs = false; - #region Public Methods + try + { + if (IsInSession) + { + await SendRequest<ExternalBridgeLogoutRequest, ExternalBridgeLogoutResponse>(new ExternalBridgeLogoutRequest(), TimeSpan.FromSeconds(0.5)); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error sending an external bridge log out request."); + } + finally + { + ClearQueues(); + } - /// <summary> - /// Starts this instance. - /// </summary> - public void Start() + OnClientDisconnected(); + } + + protected override void OnFailed(Exception ex) { - if (!IsStarted) + if (ex is KeepAliveException) { - LogManager.Log("Starting external bridge service..."); + LogManager.Log("External bridge client has failed to provide a keep alive response. Disconnecting session..."); + } + + base.OnFailed(ex); + } + #endregion + + #region Virtual Methods + + protected async virtual void OnClientDisconnected() + { + _eventsNotificationsToken = null; + _machineStatusUpdateToken = null; + _diagnosticsNotificationToken = null; + _debugLogsNotificationToken = null; + IsInSession = false; + _send_app_logs = false; - LogManager.Log("Starting TCP server..."); + if (MachineOperator.State == TransportComponentState.Connected) + { try { - _tcpServer.Start(); + await MachineOperator.SendRequest(new StopDiagnosticsRequest()); } catch (Exception ex) { - LogManager.Log(ex, "Error starting external bridge TCP server."); + LogManager.Log(ex); } - LogManager.Log("Starting discovery service..."); try { - _discoveryService.Start(); + await MachineOperator.SendRequest(new StopDebugLogRequest()); } catch (Exception ex) { - LogManager.Log(ex, "Error starting external bridge discovery service."); + LogManager.Log(ex); } + } - if (SignalRConfiguration.Enabled) - { - StartSignalR(); - } + ClientDisconnected?.Invoke(this, new EventArgs()); - IsStarted = true; - _enabled = true; - RaisePropertyChanged(nameof(Enabled)); + try + { + await base.Disconnect(); } + catch (Exception ex) + { + LogManager.Log(ex); + } + + LogManager.Log("External bridge client disconnected."); } - private void StartSignalR() + protected virtual void OnOperatorResponseReceived(MessageContainer container) { - if (!_enabled || _isSignalRConnected) return; - try { - try - { - if (_connection != null) - { - _connection.Dispose(); - } - } - catch { } - - LogManager.Log("Starting SignalR service..."); - - _connection = new HubConnection(SignalRConfiguration.Address); - _proxy = _connection.CreateHubProxy(SignalRConfiguration.Hub); - _proxy.On<String>("OnSessionCreated", OnSignalRSessionCreated); - _connection.Start(); - _connection.StateChanged += (x) => + if (IsInSession) { - if (x.NewState == ConnectionState.Connected) + if (container.Type == MessageType.StartEventsNotificationResponse) { - try + if (_eventsNotificationsToken != null) { - LogManager.Log("External Bridge Service SignalR Connected. Registering machine..."); - - _proxy.Invoke("RegisterMachine", new MachineInfo() - { - SerialNumber = Machine.SerialNumber, - Organization = Machine.Organization.Name, - }); - - _isSignalRConnected = true; - - if (_signalrPingTimer == null) - { - _signalrPingTimer = new System.Timers.Timer(TimeSpan.FromMinutes(5).TotalMilliseconds); - _signalrPingTimer.Elapsed += _signalrPingTimer_Elapsed; - _signalrPingTimer.Start(); - } + container.Token = _eventsNotificationsToken; + SendResponse(container); } - catch (Exception ex) + } + if (container.Type == MessageType.StartMachineStatusUpdateResponse) + { + if (_machineStatusUpdateToken != null) { - LogManager.Log(ex, "Error registering machine via SignalR."); + container.Token = _machineStatusUpdateToken; + SendResponse(container); } } - else if (x.NewState == ConnectionState.Disconnected) + else if (container.Type == MessageType.StartDiagnosticsResponse) { - _isSignalRConnected = false; - - if (Enabled) + if (_diagnosticsNotificationToken != null) { - LogManager.Log("External Bridge Service SignalR Disconnected/Failed. Reconnecting in 1 minute..."); - TimeoutTask.StartNew(StartSignalR, TimeSpan.FromMinutes(1)); + container.Token = _diagnosticsNotificationToken; + SendResponse(container); } } - else if (x.NewState == ConnectionState.Reconnecting) + else if (container.Type == MessageType.StartDebugLogResponse) { - LogManager.Log("External Bridge Service SignalR Connection Lost. Reconnecting..."); - //Will go invoke state change again with "connected" if successful... + if (_debugLogsNotificationToken != null) + { + container.Token = _debugLogsNotificationToken; + SendResponse(container); + } } - }; + } } - catch (Exception ex) - { - LogManager.Log(ex, "Error initializing External Bridge SignalR. Will try again in 5 minutes..."); + catch { } + } - TimeoutTask.StartNew(StartSignalR, TimeSpan.FromMinutes(5)); - } + #endregion + + #region Message Handlers + + private void RegisterMessageHandlers() + { + _messageHandlers.Add(MessageType.ExternalBridgeLogoutRequest, OnExternalBridgeLogoutRequest); + + _messageHandlers.Add(MessageType.StartApplicationLogsRequest, OnStartApplicationLogsRequest); + _messageHandlers.Add(MessageType.StopApplicationLogsRequest, OnStopApplicationLogsRequest); + + _messageHandlers.Add(MessageType.JobRequest, OnJobRequest); + + //Events + _messageHandlers.Add(MessageType.StartEventsNotificationRequest, OnStartEventsNotificationRequest); + _messageHandlers.Add(MessageType.StopEventsNotificationRequest, OnStopEventsNotificationRequest); + + //Machine Status + _messageHandlers.Add(MessageType.StartMachineStatusUpdateRequest, OnStartMachineStatusUpdateRequest); + _messageHandlers.Add(MessageType.StopMachineStatusUpdateRequest, OnStopMachineStatusUpdateRequest); + + //Diagnostics + _messageHandlers.Add(MessageType.StartDiagnosticsRequest, OnStartDiagnosticsRequest); + + //Debug Logs + _messageHandlers.Add(MessageType.StartDebugLogRequest, OnStartDebugLogRequest); } - private async void _signalrPingTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + protected virtual async void OnAnyRequest(MessageContainer container) { - if (Enabled && SignalRConfiguration.Enabled) + if (SessionIntent == ExternalBridgeLoginIntent.ColorProfile) { - if (_proxy != null) - { - try - { - var result = await _proxy.Invoke<String>("Ping"); - } - catch - { - Debug.WriteLine("Error pinging to machine service via SignalR."); - } - } + await SendErrorResponse(new AuthenticationException("The specified intent does not grant the specified action."), container.Token); + return; } - } - /// <summary> - /// Stops this instance. - /// </summary> - public async void Stop() - { - if (IsStarted) + if (!container.Continuous) { try { - _tcpServer.Stop(); - _discoveryService.Stop(); + var response = await MachineOperator.SendRequest(container); + await SendResponse(response); } + //catch (TimeoutException) + //{ + + //} catch (Exception ex) { - LogManager.Log(ex, "Error disposing TCP discovery services."); + await SendErrorResponse(ex, container.Token); } - - foreach (var receiver in _receivers.ToList()) + } + else + { + try { - try + MachineOperator.SendContinuousRequest(container).Subscribe((response) => { - await receiver.Disconnect(); - } - catch (Exception ex) + if (Enabled && IsInSession) + { + SendResponse(response); + } + + }, (ex) => { - LogManager.Log(ex, $"Error disconnecting receiver {receiver.ComponentName}."); - } + if (Enabled) + { + if (ex is ResponseErrorException) + { + SendResponse((ex as ResponseErrorException).Container); + } + } + }); + } + catch (Exception ex) + { + await SendErrorResponse(ex, container.Token); } + } + } - _enabled = false; + protected async virtual void OnExternalBridgeLoginRequest(MessageContainer container) + { + var request = MessageFactory.ParseTangoMessageFromContainer<ExternalBridgeLoginRequest>(container); + + LogManager.Log($"External bridge login attempt:\nIntent: {request.Message.Intent}\nMessage:\n{request.Message.ToJsonString()}"); - if (SignalRConfiguration.Enabled) + if (MachineOperator.Status != MachineStatuses.Printing || request.Message.Intent != ExternalBridgeLoginIntent.FullControl) + { + ExternalBridgeClientConnectedEventArgs args = new ExternalBridgeClientConnectedEventArgs(); + args.Request = request; + args.IpAddress = Adapter.Address; + ConnectionRequest?.Invoke(this, args); + + var response = new ExternalBridgeLoginResponse(); + response.Authenticated = args.Confirmed; + response.SerialNumber = Machine.SerialNumber; + response.DeviceInformation = MachineOperator.DeviceInformation; + + IsInSession = args.Confirmed; + + if (IsInSession) { - try - { - _isSignalRConnected = false; - await _proxy.Invoke("UnregisterMachine"); - _connection.Stop(); - _connection.Dispose(); - } - catch (Exception ex) - { - LogManager.Log(ex, "Error disposing SignalR connection."); - } + LogManager.Log("External bridge client has logged-in successfully."); + UseKeepAlive = true; + MachineOperator.EnableDiagnostics = false; + MachineOperator.EnableEmbeddedDebugging = false; + SessionIntent = request.Message.Intent; + } + else + { + LogManager.Log("External bridge client login failed, invalid password."); } - IsStarted = false; - HasSessions = false; - RaisePropertyChanged(nameof(Enabled)); + await SendResponse<ExternalBridgeLoginResponse>(response, container.Token, null, null, IsInSession ? null : "Invalid password or intent."); + } + else + { + LogManager.Log($"External bridge client login failed because the machine is currently printing and '{ExternalBridgeLoginIntent.FullControl}' intent was requested."); + await SendResponse<ExternalBridgeLoginResponse>(new ExternalBridgeLoginResponse(), container.Token, false, ErrorCode.GeneralError, $"Machine connection with '{ExternalBridgeLoginIntent.FullControl}' intent is not permitted while printing."); } } - /// <summary> - /// Disconnects the current remote client session. - /// </summary> - public async void DisconnectFullControlSession() + protected async virtual void OnExternalBridgeLogoutRequest(MessageContainer container) { - var sessionReceiver = _receivers.SingleOrDefault(x => x.IsLoggedIn && x.LoginIntent == ExternalBridgeLoginIntent.FullControl); - if (sessionReceiver != null) + try + { + await SendResponse<ExternalBridgeLogoutResponse>(new ExternalBridgeLogoutResponse(), container.Token); + } + catch (Exception ex) { - await sessionReceiver.Disconnect(); + LogManager.Log(ex); } + finally + { + ClearQueues(); + } + + OnClientDisconnected(); } - #endregion + protected virtual void OnStartApplicationLogsRequest(MessageContainer container) + { + if (SessionIntent == ExternalBridgeLoginIntent.Diagnostics || SessionIntent == ExternalBridgeLoginIntent.FullControl) + { + _app_logs_token = container.Token; + _send_app_logs = true; + SendResponse<StartApplicationLogsResponse>(new StartApplicationLogsResponse(), container.Token); + } + else + { + throw new AuthenticationException("The specified intent does not grant the specified action."); + } + } - #region Virtual Methods + protected virtual void OnStopApplicationLogsRequest(MessageContainer container) + { + if (SessionIntent == ExternalBridgeLoginIntent.Diagnostics || SessionIntent == ExternalBridgeLoginIntent.FullControl) + { + _send_app_logs = false; + SendResponse<StopApplicationLogsResponse>(new StopApplicationLogsResponse() { }, container.Token); + SendResponse<StartApplicationLogsResponse>(new StartApplicationLogsResponse() { }, _app_logs_token, true); + } + else + { + throw new AuthenticationException("The specified intent does not grant the specified action."); + } + } - protected virtual void OnOperatorResponseReceived(MessageContainer container) + protected virtual void OnJobRequest(MessageContainer container) { - try + if (SessionIntent != ExternalBridgeLoginIntent.FullControl) { - switch (container.Type) - { - case MessageType.StartDiagnosticsResponse: - _receivers.ToList().Where(x => x.IsLoggedInAndRequiresDiagnostics && x.RequiresDiagnostics).ToList().ForEach(x => x.UpdateDiagnostics(container)); - break; - case MessageType.StartDebugLogResponse: - _receivers.ToList().Where(x => x.IsLoggedInAndRequiresDiagnostics && x.RequiresDebugLogs).ToList().ForEach(x => x.UpdateDebugLogs(container)); - break; - case MessageType.StartEventsNotificationResponse: - //_receivers.ToList().Where(x => x.IsLoggedInAndRequiresDiagnostics && x.RequiresEventsNotification).ToList().ForEach(x => x.UpdateEvents(container)); - break; - case MessageType.StartMachineStatusUpdateResponse: - _receivers.ToList().Where(x => x.IsLoggedInAndRequiresDiagnostics && x.RequiresMachineStatusUpdate).ToList().ForEach(x => x.UpdateMachineStatus(container)); - break; - case MessageType.StartInkFillingStatusResponse: - _receivers.ToList().Where(x => x.IsLoggedInAndRequiresDiagnostics && x.RequiresInkFillingStatus).ToList().ForEach(x => x.UpdateInkFillingStatus(container)); - break; - } + throw new InvalidOperationException($"Job execution is disabled while session intent is '{SessionIntent}'."); + } + if (MachineOperator.Status != MachineStatuses.ReadyToDye) + { + throw new InvalidOperationException($"Could not execute job while machine operator status is '{MachineOperator.Status}'."); + } + else + { + OnAnyRequest(container); } - catch { } } - #endregion + protected virtual void OnStartEventsNotificationRequest(MessageContainer container) + { + _eventsNotificationsToken = container.Token; + SendResponse<StartEventsNotificationResponse>(new StartEventsNotificationResponse(), container.Token); + } + + protected virtual void OnStopEventsNotificationRequest(MessageContainer container) + { + if (_eventsNotificationsToken != null) + { + SendResponse<StartEventsNotificationResponse>(new StartEventsNotificationResponse(), _eventsNotificationsToken, true); + _eventsNotificationsToken = null; + SendResponse<StopEventsNotificationResponse>(new StopEventsNotificationResponse(), container.Token); + } + } - #region Handlers Registration + protected virtual void OnStartMachineStatusUpdateRequest(MessageContainer container) + { + _machineStatusUpdateToken = container.Token; + SendResponse<StartMachineStatusUpdateResponse>(new StartMachineStatusUpdateResponse(), container.Token); + } - public void RegisterRequestHandler(IExternalBridgeRequestHandler handler) + protected virtual void OnStopMachineStatusUpdateRequest(MessageContainer container) { - foreach (var method in handler.GetType().GetMethods()) + if (_machineStatusUpdateToken != null) { - var att = method.GetCustomAttribute<ExternalBridgeRequestHandlerMethodAttribute>(); - if (att != null) - { - _requestHandlers.Add(att.Type is IMessage ? att.Type.Name : att.Type.FullName, new RequestHandler() - { - Handler = handler, - Method = method, - LoggingMode = att.LoggingMode, - }); - } + SendResponse<StartMachineStatusUpdateResponse>(new StartMachineStatusUpdateResponse(), _machineStatusUpdateToken, true); + _machineStatusUpdateToken = null; + SendResponse<StopMachineStatusUpdateResponse>(new StopMachineStatusUpdateResponse(), container.Token); + } + } + + protected virtual void OnStartDiagnosticsRequest(MessageContainer container) + { + if (_diagnosticsNotificationToken == null) + { + _diagnosticsNotificationToken = container.Token; + _machineOperator.SendContinuousRequest(container); } } - public void UnregisterRequestHandler(IExternalBridgeRequestHandler handler) + protected virtual void OnStartDebugLogRequest(MessageContainer container) { - foreach (var h in _requestHandlers.Where(x => x.Value.Handler == handler).ToList()) + if (_debugLogsNotificationToken == null) { - _requestHandlers.Remove(h.Key); + _debugLogsNotificationToken = container.Token; + _machineOperator.SendContinuousRequest(container); } } + private void OnColorProfileRequest(MessageContainer container) + { + var request = MessageFactory.ParseTangoMessageFromContainer<ColorProfileRequest>(container); + + ColorProfileRequestEventArgs e = new ColorProfileRequestEventArgs(request, async () => + { + //Approved. + await SendResponse<ColorProfileResponse>(new ColorProfileResponse() + { + Approved = true + }, container.Token); + await Task.Delay(500); + await base.Disconnect(); + }, + async () => + { + //Declined. + await SendResponse<ColorProfileResponse>(new ColorProfileResponse(), container.Token); + await Task.Delay(500); + await base.Disconnect(); + }); + + ColorProfileRequest?.Invoke(this, e); + } + #endregion } } diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeSignalRClient.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeSignalRClient.cs deleted file mode 100644 index a8f01437c..000000000 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeSignalRClient.cs +++ /dev/null @@ -1,124 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Security.Authentication; -using System.Text; -using System.Threading.Tasks; -using Tango.BL; -using Tango.BL.Entities; -using Tango.Integration.ExternalBridge.Web; -using Tango.Integration.Operation; -using Tango.PMR.Integration; -using Tango.Settings; -using Tango.Transport; -using Tango.Transport.Adapters; - -namespace Tango.Integration.ExternalBridge -{ - public class ExternalBridgeSignalRClient : ExternalBridgeTcpClient - { - public ExternalBridgeSignalRClient(String url, String hub, MachineInfo machineInfo) - { - ComponentName = $"External Bridge SignalR Client {_component_counter++}"; - - SerialNumber = machineInfo.SerialNumber; - IPAddress = machineInfo.IPAddress; - Machine = ObservablesStaticCollections.Instance.Machines.SingleOrDefault(x => x.SerialNumber == SerialNumber); - Adapter = new SignalRTransportAdapter(url, hub, SignalRTransportAdapterMode.CreateSession, SerialNumber, null, IPAddress); - - KeepAliveTimeout = TimeSpan.FromSeconds(5); - KeepAliveRetries = 2; - UseKeepAlive = false; - } - - public ExternalBridgeSignalRClient(String url, String hub, Machine machine, MachineInfo machineInfo) - { - ComponentName = $"External Bridge SignalR Client {_component_counter++}"; - - SerialNumber = machine.SerialNumber; - IPAddress = machineInfo.IPAddress; - Machine = machine; - Adapter = new SignalRTransportAdapter(url, hub, SignalRTransportAdapterMode.CreateSession, SerialNumber, null, IPAddress); - - KeepAliveTimeout = TimeSpan.FromSeconds(5); - KeepAliveRetries = 2; - UseKeepAlive = false; - } - - /// <summary> - /// Connects to a remote external bridge service using the specified login. - /// </summary> - /// <param name="login">The login request.</param> - /// <param name="protocol">Optional protocol configuration.</param> - /// <returns></returns> - /// <exception cref="AuthenticationException"></exception> - public override async Task Connect(ExternalBridgeLoginRequest login, ConfigureProtocolRequest protocol = null) - { - if (State != TransportComponentState.Connected) - { - try - { - Adapter.EnableCompression = false; - GenericProtocol = GenericMessageProtocol.Json; - - await Adapter.Connect(); - - State = TransportComponentState.Connected; - StartThreads(); - - LogManager.Log($"{ComponentName}: External Bridge SignalR Client Connected..."); - - TimeSpan? timeout = null; - - if (login.RequireSafetyLevelOperations) - { - timeout = TimeSpan.FromSeconds(35); - } - - var response = await SendRequest<ExternalBridgeLoginRequest, ExternalBridgeLoginResponse>(login, new TransportRequestConfig() { ShouldLog = true, Timeout = timeout }); - - if (protocol != null) - { - try - { - var configureResponse = await SendRequest<ConfigureProtocolRequest, ConfigureProtocolResponse>(protocol, new TransportRequestConfig() { ShouldLog = true }); - if (configureResponse.Message.Confirmed) - { - await Task.Delay(500); - Adapter.EnableCompression = protocol.EnableCompression; - GenericProtocol = protocol.GenericProtocol; - } - } - catch (Exception ex) - { - LogManager.Log(ex, $"{ComponentName}: Could not configure remote machine protocol. Could be an old PPC version."); - } - } - - ApplicationInformation = response.Message.ApplicationInformation; - - SessionLogger.CreateSession(); - - DeviceInformation = response.Message.DeviceInformation; - if (!response.Message.Authenticated) - { - await Adapter.Disconnect(); - throw new AuthenticationException(response.Container.ErrorMessage); - } - } - catch (Exception ex) - { - try - { - await Adapter.Disconnect(); - } - catch { } - - throw ex; - } - - ApplyContinuousChannelsConfiguration(); - } - } - } -} diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeSignalRConfiguration.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeSignalRConfiguration.cs deleted file mode 100644 index cd511aa9b..000000000 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeSignalRConfiguration.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Tango.Integration.ExternalBridge -{ - public class ExternalBridgeSignalRConfiguration - { - public bool Enabled { get; set; } - public String Address { get; set; } - public String Hub { get; set; } - } -} diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeTcpClient.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeTcpClient.cs index 0b2a0c608..8acff77d4 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeTcpClient.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeTcpClient.cs @@ -14,7 +14,6 @@ using Tango.PMR; using Tango.PMR.Common; using Tango.PMR.Connection; using Tango.PMR.Integration; -using Tango.PMR.MachineStatus; using Tango.Settings; using Tango.Transport; using Tango.Transport.Adapters; @@ -31,8 +30,6 @@ namespace Tango.Integration.ExternalBridge { private bool _logs_sent; - public event EventHandler<LogItemBase> ApplicationLogAvailable; - #region Properties private String _serialNumber; @@ -74,113 +71,54 @@ namespace Tango.Integration.ExternalBridge } } - public bool InjectApplicationLogsToDefaultLogManager { get; set; } = true; - /// <summary> /// Gets a value indicating whether this client requires authentication. /// </summary> public bool RequiresAuthentication => true; - /// <summary> - /// Gets or sets the login request message when using <see cref="Connect"/>. - /// </summary> - public ExternalBridgeLoginRequest LoginRequest { get; set; } - - /// <summary> - /// Gets or sets the configure protocol request message when using <see cref="Connect"/>. - /// </summary> - public ConfigureProtocolRequest ConfigureProtocolRequest { get; set; } - - private ApplicationInformation _applicationInformation; - /// <summary> - /// Gets or sets the remote application information (PPC). - /// </summary> - public ApplicationInformation ApplicationInformation - { - get { return _applicationInformation; } - protected set { _applicationInformation = value; RaisePropertyChangedAuto(); } - } - #endregion - /// <summary> - /// Connects to a remote external bridge service using the specified <see cref="LoginRequest"/>. - /// </summary> - /// <param name="login">The login.</param> - /// <returns></returns> - /// <exception cref="AuthenticationException">The machine password is invalid.</exception> public override Task Connect() { - if (LoginRequest == null) - { - throw new InvalidOperationException("No LoginRequest was not specified."); - } - return Connect(LoginRequest, ConfigureProtocolRequest); + throw new NotImplementedException("External Bridge TCP client must connect through the dedicated connect method."); } /// <summary> /// Connects to a remote external bridge service using the specified login. /// </summary> - /// <param name="login">The login request.</param> - /// <param name="protocol">Optional protocol configuration.</param> + /// <param name="login">The login.</param> /// <returns></returns> - /// <exception cref="AuthenticationException"></exception> - public virtual async Task Connect(ExternalBridgeLoginRequest login, ConfigureProtocolRequest protocol = null) + /// <exception cref="AuthenticationException">The machine password is invalid.</exception> + public async Task Connect(ExternalBridgeLoginRequest login) { if (State != TransportComponentState.Connected) { try { - Adapter.EnableCompression = false; - GenericProtocol = GenericMessageProtocol.Json; - + Adapter = new TcpTransportAdapter(IPAddress, SettingsManager.Default.GetOrCreate<IntegrationSettings>().ExternalBridgeServicePort); await Adapter.Connect(); State = TransportComponentState.Connected; StartThreads(); - LogManager.Log($"{ComponentName}: External Bridge TCP Client Connected..."); + LogManager.Log("External Bridge TCP Client Connected..."); - TimeSpan? timeout = null; - if (login.RequireSafetyLevelOperations) - { - timeout = TimeSpan.FromSeconds(35); - } - - var response = await SendRequest<ExternalBridgeLoginRequest, ExternalBridgeLoginResponse>(login, new TransportRequestConfig() { ShouldLog = true, Timeout = timeout }); - - if (protocol != null) - { - try - { - var configureResponse = await SendRequest<ConfigureProtocolRequest, ConfigureProtocolResponse>(protocol, new TransportRequestConfig() { ShouldLog = true }); - if (configureResponse.Message.Confirmed) - { - await Task.Delay(500); - Adapter.EnableCompression = protocol.EnableCompression; - GenericProtocol = protocol.GenericProtocol; - } - } - catch (Exception ex) - { - LogManager.Log(ex, $"{ComponentName}: Could not configure remote machine protocol. Could be an old PPC version."); - } - } - - ApplicationInformation = response.Message.ApplicationInformation; - - SessionLogger.CreateSession(); + LogRequestSent(login); + var response = await SendRequest<ExternalBridgeLoginRequest, ExternalBridgeLoginResponse>(login); DeviceInformation = response.Message.DeviceInformation; if (!response.Message.Authenticated) { await Adapter.Disconnect(); throw new AuthenticationException(response.Container.ErrorMessage); } + + Status = MachineStatuses.ReadyToDye; } catch (Exception ex) { + LogRequestFailed(login, ex); try { await Adapter.Disconnect(); @@ -190,23 +128,15 @@ namespace Tango.Integration.ExternalBridge throw ex; } - ApplyContinuousChannelsConfiguration(); + OnEnableDiagnosticsChanged(EnableDiagnostics); + OnEnableEmbeddedDebuggingChanged(EnableEmbeddedDebugging); + OnEnableEventsNotification(EnableEventsNotification); + OnEnableApplicationLogsChanged(EnableApplicationLogs); + OnEnableMachineStatusUpdatesChanged(EnableMachineStatusUpdates); } } - protected virtual void ApplyContinuousChannelsConfiguration() - { - OnEnableDiagnosticsChanged(EnableDiagnostics); - OnEnableEmbeddedDebuggingChanged(EnableEmbeddedDebugging); - OnEnableEventsNotification(EnableEventsNotification); - OnEnableApplicationLogsChanged(EnableApplicationLogs); - OnEnableMachineStatusUpdatesChanged(EnableMachineStatusUpdates); - OnEnableInkFillingStatus(EnableInkFillingStatus); - //TODO: Uncomment this only when Machine Studio enables automatic thread loading (ExternalBridgeTCPClient). - //OnEnableAutomaticThreadLoadingChanged(EnableAutomaticThreadLoading); - } - - protected async void OnEnableApplicationLogsChanged(bool value) + private async void OnEnableApplicationLogsChanged(bool value) { if (value && State == TransportComponentState.Connected && !_logs_sent) { @@ -215,13 +145,14 @@ namespace Tango.Integration.ExternalBridge bool responseLogged = false; _logs_sent = true; - SendContinuousRequest<StartApplicationLogsRequest, StartApplicationLogsResponse>(request, new TransportContinuousRequestConfig() { ShouldLog = true }).ObserveOn(new NewThreadScheduler()) + SendContinuousRequest<StartApplicationLogsRequest, StartApplicationLogsResponse>(request).ObserveOn(new NewThreadScheduler()) .Subscribe ( (response) => { if (!responseLogged) { + LogResponseReceived(response.Message); responseLogged = true; } @@ -230,11 +161,18 @@ namespace Tango.Integration.ExternalBridge (ex) => { _logs_sent = false; + + if (!(ex is ContinuousResponseAbortedException)) + { + LogRequestFailed(request, ex); + } }, () => { _logs_sent = false; }); + + LogRequestSent(request); } else if (_logs_sent) { @@ -246,9 +184,14 @@ namespace Tango.Integration.ExternalBridge try { - var res = await SendRequest<StopApplicationLogsRequest, StopApplicationLogsResponse>(req, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(req); + var res = await SendRequest<StopApplicationLogsRequest, StopApplicationLogsResponse>(req); + LogResponseReceived(res.Message); + } + catch (Exception ex) + { + LogRequestFailed(req, ex); } - catch { } } } } @@ -261,13 +204,7 @@ namespace Tango.Integration.ExternalBridge { LogItemBase log = LogItemBase.Deserialize(response.Message.LogItem.ToArray()); log.LogObject = "External Bridge"; - - if (InjectApplicationLogsToDefaultLogManager) - { - LogManager.Log(log); - } - - ApplicationLogAvailable?.Invoke(this, log); + LogManager.Log(log); } } catch (Exception ex) @@ -281,32 +218,27 @@ namespace Tango.Integration.ExternalBridge if (State == TransportComponentState.Connected) { ExternalBridgeLogoutRequest request = new ExternalBridgeLogoutRequest(); + LogRequestSent(request); try { - var response = await SendRequest<ExternalBridgeLogoutRequest, ExternalBridgeLogoutResponse>(request, new TransportRequestConfig() { ShouldLog = true }); - } - catch { } + var response = await SendRequest<ExternalBridgeLogoutRequest, ExternalBridgeLogoutResponse>(request); + LogResponseReceived(response.Message); - Status = MachineStatuses.Standby; + Status = MachineStatuses.Standby; + } + catch (Exception ex) + { + LogRequestFailed(request, ex); + } } State = TransportComponentState.Disconnected; - - NotifyContinuousRequestMessagesDisconnection(); - - SessionLogger.EndSession(); - if (Adapter != null) { await Adapter.Disconnect(); } - LogManager.Log($"{ComponentName} disconnected."); - } - - internal ExternalBridgeTcpClient() - { - + LogManager.Log("External Bridge TCP client disconnected."); } /// <summary> @@ -316,34 +248,13 @@ namespace Tango.Integration.ExternalBridge /// <param name="ipAddress">The machine IP address.</param> public ExternalBridgeTcpClient(String serialNumber, String ipAddress) { - ComponentName = $"External Bridge TCP Client {_component_counter++}"; SerialNumber = serialNumber; - - if (ObservablesStaticCollections.Instance.IsInitialized) - { - Machine = ObservablesStaticCollections.Instance.Machines.SingleOrDefault(x => x.SerialNumber == serialNumber); - } - IPAddress = ipAddress; - KeepAliveTimeout = TimeSpan.FromSeconds(5); - KeepAliveRetries = 2; - UseKeepAlive = false; - EnableDiagnostics = true; - - Adapter = new TcpTransportAdapter(IPAddress, SettingsManager.Default.GetOrCreate<IntegrationSettings>().ExternalBridgeServicePort); - } - - public ExternalBridgeTcpClient(Machine machine, String ipAddress) - { - ComponentName = $"External Bridge TCP Client {_component_counter++}"; - Machine = machine; - SerialNumber = Machine.SerialNumber; + Machine = ObservablesStaticCollections.Instance.Machines.SingleOrDefault(x => x.SerialNumber == serialNumber); IPAddress = ipAddress; KeepAliveTimeout = TimeSpan.FromSeconds(5); KeepAliveRetries = 2; UseKeepAlive = false; EnableDiagnostics = true; - - Adapter = new TcpTransportAdapter(IPAddress, SettingsManager.Default.GetOrCreate<IntegrationSettings>().ExternalBridgeServicePort); } /// <summary> @@ -361,22 +272,13 @@ namespace Tango.Integration.ExternalBridge /// Called when a new request has been received. /// </summary> /// <param name="request">The request.</param> - protected async override void OnRequestReceived(RequestReceivedEventArgs e) + protected async override void OnRequestReceived(MessageContainer request) { - base.OnRequestReceived(e); - - var container = e.Container; + base.OnRequestReceived(request); - if (container.Type == MessageType.ExternalBridgeLogoutRequest) + if (request.Type == MessageType.ExternalBridgeLogoutRequest) { - try - { - await SendResponse<ExternalBridgeLogoutResponse>(new ExternalBridgeLogoutResponse(), container.Token); - } - catch { } - - await Task.Delay(2000); - + await SendResponse<ExternalBridgeLogoutResponse>(new ExternalBridgeLogoutResponse(), request.Token); try { State = TransportComponentState.Disconnected; @@ -387,19 +289,10 @@ namespace Tango.Integration.ExternalBridge LogManager.Log("External Bridge TCP client disconnected by the remote host."); } catch { } - - SessionLogger.EndSession(); SessionClosed?.Invoke(this, new EventArgs()); - - NotifyContinuousRequestMessagesDisconnection(); } } - protected override void OnMachineStateChanged(MachineState state) - { - //Do Nothing... - } - /// <summary> /// Occurs when the remote host has closed the session. /// </summary> @@ -408,7 +301,7 @@ namespace Tango.Integration.ExternalBridge /// <summary> /// Gets the database machine associated with this client. /// </summary> - public Machine Machine { get; protected set; } + public Machine Machine { get; private set; } /// <summary> /// Sets the database machine. diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeUsbClient.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeUsbClient.cs index d7246fe7b..0767d73d5 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeUsbClient.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeUsbClient.cs @@ -68,11 +68,6 @@ namespace Tango.Integration.ExternalBridge } /// <summary> - /// Gets or sets a value indicating whether transport compression is required by the remote machine. - /// </summary> - public bool CompressionEnabled { get; set; } - - /// <summary> /// Connects the transport component. /// </summary> /// <returns></returns> @@ -98,7 +93,6 @@ namespace Tango.Integration.ExternalBridge /// <param name="device">The device.</param> public ExternalBridgeUsbClient(String comPort, String device,UsbSerialBaudRates baudRate = UsbSerialBaudRates.BR_115200) { - ComponentName = $"External Bridge USB Client {_component_counter++}"; ComPort = comPort; Device = device; BaudRate = baudRate; diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeRequestHandler.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeRequestHandler.cs deleted file mode 100644 index 753afc899..000000000 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeRequestHandler.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Google.Protobuf; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Tango.Integration.ExternalBridge -{ - /// <summary> - /// Represents an <see cref="IExternalBridgeService"/> request handler. - /// </summary> - public interface IExternalBridgeRequestHandler - { - /// <summary> - /// Called when any of the external bridge clients (receivers) has disconnected. - /// </summary> - /// <param name="receiver">The receiver.</param> - void OnReceiverDisconnected(ExternalBridgeReceiver receiver); - } -} diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeSecureClient.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeSecureClient.cs index aaf7efc2d..7d35963d4 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeSecureClient.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeSecureClient.cs @@ -21,9 +21,8 @@ namespace Tango.Integration.ExternalBridge /// <summary> /// Connects to a remote external bridge service using the specified login. /// </summary> - /// <param name="login">The login request.</param> - /// <param name="protocol">Optional protocol configuration.</param> + /// <param name="login">The login.</param> /// <returns></returns> - Task Connect(ExternalBridgeLoginRequest login, ConfigureProtocolRequest protocol = null); + Task Connect(ExternalBridgeLoginRequest login); } } diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeService.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeService.cs index c7d2c8d5c..c0b41fd00 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeService.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeService.cs @@ -1,7 +1,5 @@ -using Google.Protobuf; -using System; +using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -9,27 +7,21 @@ using Tango.BL.Entities; using Tango.Integration.Operation; using Tango.PMR.Integration; using Tango.Transport; -using Tango.Transport.Adapters; using Tango.Transport.Transporters; namespace Tango.Integration.ExternalBridge { - public interface IExternalBridgeService + public interface IExternalBridgeService : ITransporter { /// <summary> - /// Gets the collection of logged-in receivers. - /// </summary> - List<ExternalBridgeReceiver> ActiveReceivers { get; } - - /// <summary> /// Occurs when a new client is waiting for authentication. /// </summary> event EventHandler<ExternalBridgeClientConnectedEventArgs> ConnectionRequest; /// <summary> - /// Occurs when the current full control session has disconnected. + /// Occurs when the last client has been disconnected. /// </summary> - event EventHandler FullControlSessionDisconnected; + event EventHandler ClientDisconnected; /// <summary> /// Occurs when the service has received a new color profile request. @@ -47,21 +39,6 @@ namespace Tango.Integration.ExternalBridge Machine Machine { get; set; } /// <summary> - /// Gets or sets the SignalR configuration. - /// </summary> - ExternalBridgeSignalRConfiguration SignalRConfiguration { get; set; } - - /// <summary> - /// Gets the current full control session receiver. - /// </summary> - ExternalBridgeReceiver FullControlSessionReceiver { get; } - - /// <summary> - /// Gets or sets the TCP transport adapter write mode when creating a TCP receiver. - /// </summary> - TcpTransportAdapterWriteMode TcpTransportAdapterWriteMode { get; set; } - - /// <summary> /// Gets a value indicating whether this instance is started. /// </summary> bool IsStarted { get; } @@ -72,9 +49,9 @@ namespace Tango.Integration.ExternalBridge bool Enabled { get; set; } /// <summary> - /// Gets a value indicating whether there are any connected sessions. + /// Gets a value indicating whether a remote client is authenticated and in session. /// </summary> - bool HasSessions { get; } + bool IsInSession { get; } /// <summary> /// Starts this instance. @@ -89,18 +66,11 @@ namespace Tango.Integration.ExternalBridge /// <summary> /// Disconnects the current remote client session. /// </summary> - void DisconnectFullControlSession(); - - /// <summary> - /// Registers the request handler. - /// </summary> - /// <param name="handler">The handler.</param> - void RegisterRequestHandler(IExternalBridgeRequestHandler handler); + void DisconnectSession(); /// <summary> - /// Unregisters the request handler. + /// Gets the current session login intent. /// </summary> - /// <param name="handler">The handler.</param> - void UnregisterRequestHandler(IExternalBridgeRequestHandler handler); + ExternalBridgeLoginIntent SessionIntent { get; } } } diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/RequestHandlerLoggingMode.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/RequestHandlerLoggingMode.cs deleted file mode 100644 index c4b07e173..000000000 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/RequestHandlerLoggingMode.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Tango.Integration.ExternalBridge -{ - public enum RequestHandlerLoggingMode - { - None, - LogRequestName, - LogRequestNameAndContent, - } -} diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/Web/MachineInfo.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/Web/MachineInfo.cs deleted file mode 100644 index cccc24c35..000000000 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/Web/MachineInfo.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tango.PMR.Integration; -using Tango.Transport; - -namespace Tango.Integration.ExternalBridge.Web -{ - public class MachineInfo - { - public String SerialNumber { get; set; } - public String Organization { get; set; } - public String IPAddress { get; set; } - - public MachineInfo() - { - IPAddress = "Unknown"; - } - } -} diff --git a/Software/Visual_Studio/Tango.Integration/JobRuns/BasicJobRunsLogger.cs b/Software/Visual_Studio/Tango.Integration/JobRuns/BasicJobRunsLogger.cs index 64ad60db5..bacae9324 100644 --- a/Software/Visual_Studio/Tango.Integration/JobRuns/BasicJobRunsLogger.cs +++ b/Software/Visual_Studio/Tango.Integration/JobRuns/BasicJobRunsLogger.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Tango.BL; -using Tango.BL.Builders; using Tango.BL.Entities; using Tango.BL.Enumerations; using Tango.Core; @@ -18,8 +17,8 @@ namespace Tango.Integration.JobRuns /// <seealso cref="Tango.Integration.JobRuns.IJobRunsLogger" /> public class BasicJobRunsLogger : ExtendedObject, IJobRunsLogger { + private DateTime _start_date; private Job _job; - private Machine _defaultMachine; #region Properties @@ -36,12 +35,7 @@ namespace Tango.Integration.JobRuns /// <summary> /// Gets or sets the job designations of which the logger should log (supports multiple flags). /// </summary> - public JobDesignations JobDesignationFilter { get; set; } - - /// <summary> - /// Gets or sets the job run source when logging job runs. - /// </summary> - public JobSource JobSource { get; set; } + public JobDesignations JobDesignation { get; set; } #endregion @@ -53,7 +47,7 @@ namespace Tango.Integration.JobRuns /// <param name="machineOperator">The machine operator.</param> public BasicJobRunsLogger(IMachineOperator machineOperator) { - JobDesignationFilter = JobDesignations.Default | JobDesignations.SampleDye | JobDesignations.FineTuning; + JobDesignation = JobDesignations.Default; MachineOperator = machineOperator; Init(); } @@ -75,15 +69,38 @@ namespace Tango.Integration.JobRuns MachineOperator.PrintingAborted += Machine_PrintingAborted; MachineOperator.PrintingFailed -= Machine_PrintingFailed; MachineOperator.PrintingFailed += Machine_PrintingFailed; - MachineOperator.HeadCleaningEnded += MachineOperator_HeadCleaningEnded; } private bool ShouldLog() { - return IsStarted && _job != null && JobDesignationFilter.HasFlag(_job.Designation); + return IsStarted && _job != null && JobDesignation.HasFlag(_job.Designation); + } + + #endregion + + #region Public Methods + + /// <summary> + /// Starts the logger. + /// </summary> + public void Start() + { + IsStarted = true; + } + + /// <summary> + /// Stops the logger. + /// </summary> + public void Stop() + { + IsStarted = false; } - private void InsertJobRun(PrintingEventArgs e, JobRunStatus status, Exception exception) + #endregion + + #region Event Handlers + + private void Machine_PrintingFailed(object sender, PrintingFailedEventArgs e) { if (ShouldLog()) { @@ -95,65 +112,15 @@ namespace Tango.Integration.JobRuns { using (var db = ObservablesContext.CreateDefault()) { - JobRun run = new JobRun(); - - run.UserGuid = _job.UserGuid; - run.StartDate = e.StartDate; - run.UploadingStartDate = e.UploadingStartTime; - run.HeatingStartDate = e.HeatingStartTime; - run.ActualStartDate = e.ActualStartTime; - run.EndDate = DateTime.UtcNow; - run.JobName = _job.Name; - run.Source = JobSource; - run.Designation = _job.Designation; - run.JobGuid = _job.Guid; - run.RmlGuid = _job.RmlGuid; - run.MachineGuid = _job.MachineGuid; - run.JobRunStatus = status; - run.EndPosition = e.JobHandler.Status.Progress; - //run.JobLength = _job.LengthIncludingNumberOfUnits; //Should I use this or the below ?? - run.JobLength = e.JobHandler.Status.TotalProgress; - run.LiquidQuantities = e.LiquidQuantities; - run.IsGradient = _job.Segments.Any(x => x.BrushStops.Count > 1); - run.GradientResolutionCm = MachineOperator.GradientGenerationConfiguration.ResolutionCM; - run.JobString = _job.ToJobFileWhenLoaded().ToString(); - - //Set individual liquid quantities - - //Cyan - var cyan = run.LiquidQuantities.SingleOrDefault(x => x.LiquidType == LiquidTypes.Cyan); - run.CyanQuantity = cyan != null ? cyan.Quantity : 0; - - //Magenta - var magenta = run.LiquidQuantities.SingleOrDefault(x => x.LiquidType == LiquidTypes.Magenta); - run.MagentaQuantity = magenta != null ? magenta.Quantity : 0; - - //Yellow - var yellow = run.LiquidQuantities.SingleOrDefault(x => x.LiquidType == LiquidTypes.Yellow); - run.YellowQuantity = yellow != null ? yellow.Quantity : 0; - - //Black - var black = run.LiquidQuantities.SingleOrDefault(x => x.LiquidType == LiquidTypes.Black); - run.BlackQuantity = black != null ? black.Quantity : 0; - - //TI - var ti = run.LiquidQuantities.SingleOrDefault(x => x.LiquidType == LiquidTypes.TransparentInk); - run.TransparentQuantity = ti != null ? ti.Quantity : 0; - - //Lubricant - var lubricant = run.LiquidQuantities.SingleOrDefault(x => x.LiquidType == LiquidTypes.Lubricant); - run.LubricantQuantity = lubricant != null ? lubricant.Quantity : 0; - - //Cleaner - var cleaner = run.LiquidQuantities.SingleOrDefault(x => x.LiquidType == LiquidTypes.Cleaner); - run.CleanerQuantity = cleaner != null ? cleaner.Quantity : 0; - - if (exception != null) + db.JobRuns.Add(new JobRun() { - run.FailedMessage = exception.FlattenMessage(); - } - - db.JobRuns.Add(run); + StartDate = _start_date, + EndDate = DateTime.UtcNow, + JobGuid = _job.Guid, + JobRunStatus = JobRunStatus.Failed, + EndPosition = e.JobHandler.Status.Progress, + FailedMessage = e.Exception.Message, + }); e.Job.LastRun = DateTime.UtcNow; _job.LastRun = DateTime.UtcNow; @@ -170,158 +137,103 @@ namespace Tango.Integration.JobRuns } catch (Exception ex) { - LogManager.Log(ex, "Error logging the last job run to the database."); + LogManager.Log(ex, "Error logging the current job run to the database."); } }); } } } - private void InsertHeadCleaningJobRun(HeadCleaningEndedEventArgs e) + private void Machine_PrintingAborted(object sender, PrintingEventArgs e) { - if (IsStarted && _defaultMachine != null) + if (ShouldLog()) { - Task.Factory.StartNew(() => + if (e.Job.Guid == _job.Guid) { - try + Task.Factory.StartNew(() => { - using (var db = ObservablesContext.CreateDefault()) + try { - JobRun run = new JobRun(); - - run.IsHeadCleaning = true; - run.StartDate = e.StartDate; - run.UploadingStartDate = e.StartDate; - run.HeatingStartDate = e.StartDate; - run.ActualStartDate = e.StartDate; - run.EndDate = DateTime.UtcNow; - run.JobName = "HEAD CLEANING"; - run.Source = JobSource; - run.MachineGuid = _defaultMachine.Guid; - run.JobRunStatus = e.Status; - run.EndPosition = e.EndPosition; - run.JobLength = e.Length; - run.LiquidQuantities = e.LiquidQuantities; - - //Set individual liquid quantities - - //Cyan - var cyan = run.LiquidQuantities.SingleOrDefault(x => x.LiquidType == LiquidTypes.Cyan); - run.CyanQuantity = cyan != null ? cyan.Quantity : 0; - - //Magenta - var magenta = run.LiquidQuantities.SingleOrDefault(x => x.LiquidType == LiquidTypes.Magenta); - run.MagentaQuantity = magenta != null ? magenta.Quantity : 0; - - //Yellow - var yellow = run.LiquidQuantities.SingleOrDefault(x => x.LiquidType == LiquidTypes.Yellow); - run.YellowQuantity = yellow != null ? yellow.Quantity : 0; - - //Black - var black = run.LiquidQuantities.SingleOrDefault(x => x.LiquidType == LiquidTypes.Black); - run.BlackQuantity = black != null ? black.Quantity : 0; - - //TI - var ti = run.LiquidQuantities.SingleOrDefault(x => x.LiquidType == LiquidTypes.TransparentInk); - run.TransparentQuantity = ti != null ? ti.Quantity : 0; - - //Lubricant - var lubricant = run.LiquidQuantities.SingleOrDefault(x => x.LiquidType == LiquidTypes.Lubricant); - run.LubricantQuantity = lubricant != null ? lubricant.Quantity : 0; + using (var db = ObservablesContext.CreateDefault()) + { + db.JobRuns.Add(new JobRun() + { + StartDate = _start_date, + EndDate = DateTime.UtcNow, + JobGuid = _job.Guid, + EndPosition = e.JobHandler.Status.Progress, + JobRunStatus = JobRunStatus.Aborted, + }); - //Cleaner - var cleaner = run.LiquidQuantities.SingleOrDefault(x => x.LiquidType == LiquidTypes.Cleaner); - run.CleanerQuantity = cleaner != null ? cleaner.Quantity : 0; + e.Job.LastRun = DateTime.UtcNow; + _job.LastRun = DateTime.UtcNow; - //if (exception != null) - //{ - // run.FailedMessage = exception.FlattenMessage(); - //} + var job = db.Jobs.SingleOrDefault(x => x.Guid == _job.Guid); - db.JobRuns.Add(run); + if (job != null) + { + job.LastRun = DateTime.UtcNow; + } - db.SaveChanges(); + db.SaveChanges(); + } } - } - catch (Exception ex) - { - LogManager.Log(ex, "Error logging the last head cleaning job run to the database."); - } - }); + catch (Exception ex) + { + LogManager.Log(ex, "Error logging the current job run to the database."); + } + }); + } } } - #endregion - - #region Public Methods - - /// <summary> - /// Starts the logger. - /// </summary> - public void Start() - { - IsStarted = true; - } - - /// <summary> - /// Stops the logger. - /// </summary> - public void Stop() - { - IsStarted = false; - } - - /// <summary> - /// Sets the head cleaning parameters. - /// </summary> - /// <param name="machine">The machine.</param> - public void SetDefaultMachine(Machine machine) - { - _defaultMachine = machine; - } - - #endregion - - #region Event Handlers - - private void Machine_PrintingFailed(object sender, PrintingFailedEventArgs e) - { - InsertJobRun(e, JobRunStatus.Failed, e.Exception); - } - - private void Machine_PrintingAborted(object sender, PrintingEventArgs e) - { - InsertJobRun(e, JobRunStatus.Aborted, null); - } - private void Machine_PrintingCompleted(object sender, PrintingEventArgs e) { - InsertJobRun(e, JobRunStatus.Completed, null); - } - - private async void Machine_PrintingStarted(object sender, PrintingEventArgs e) - { - _job = e.Job; - - if (e.IsResumed) + if (ShouldLog()) { - try + if (e.Job.Guid == _job.Guid) { - using (ObservablesContext db = ObservablesContext.CreateDefault()) + Task.Factory.StartNew(() => { - _job = await new JobBuilder(db).Set(e.Job.Guid).WithConfiguration().WithSegments().WithBrushStops().BuildAsync(); - } - } - catch (Exception ex) - { - LogManager.Log(ex, "Error loading resumed job from database."); + try + { + using (var db = ObservablesContext.CreateDefault()) + { + db.JobRuns.Add(new JobRun() + { + StartDate = _start_date, + EndDate = DateTime.UtcNow, + JobGuid = _job.Guid, + EndPosition = e.JobHandler.Status.Progress, + JobRunStatus = JobRunStatus.Completed, + }); + + e.Job.LastRun = DateTime.UtcNow; + _job.LastRun = DateTime.UtcNow; + + var job = db.Jobs.SingleOrDefault(x => x.Guid == _job.Guid); + + if (job != null) + { + job.LastRun = DateTime.UtcNow; + } + + db.SaveChanges(); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error logging the current job run to the database."); + } + }); } } } - private void MachineOperator_HeadCleaningEnded(object sender, HeadCleaningEndedEventArgs e) + private void Machine_PrintingStarted(object sender, PrintingEventArgs e) { - InsertHeadCleaningJobRun(e); + _job = e.Job; + _start_date = DateTime.UtcNow; } #endregion diff --git a/Software/Visual_Studio/Tango.Integration/JobRuns/IJobRunsLogger.cs b/Software/Visual_Studio/Tango.Integration/JobRuns/IJobRunsLogger.cs index 386298bb9..8c4174311 100644 --- a/Software/Visual_Studio/Tango.Integration/JobRuns/IJobRunsLogger.cs +++ b/Software/Visual_Studio/Tango.Integration/JobRuns/IJobRunsLogger.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Tango.BL.Entities; using Tango.BL.Enumerations; using Tango.Integration.Operation; @@ -22,12 +21,7 @@ namespace Tango.Integration.JobRuns /// <summary> /// Gets or sets the job designations of which the logger should log (supports multiple flags). /// </summary> - JobDesignations JobDesignationFilter { get; set; } - - /// <summary> - /// Gets or sets the job run source when logging job runs. - /// </summary> - JobSource JobSource { get; set; } + JobDesignations JobDesignation { get; set; } /// <summary> /// Gets a value indicating whether this instance is started. @@ -43,11 +37,5 @@ namespace Tango.Integration.JobRuns /// Stops the logger. /// </summary> void Stop(); - - /// <summary> - /// Sets the head cleaning parameters. - /// </summary> - /// <param name="machine">The machine.</param> - void SetDefaultMachine(Machine machine); } } diff --git a/Software/Visual_Studio/Tango.Integration/Logging/EmbeddedLogFileParser.cs b/Software/Visual_Studio/Tango.Integration/Logging/EmbeddedLogFileParser.cs index 7e3e45c54..98a3ac543 100644 --- a/Software/Visual_Studio/Tango.Integration/Logging/EmbeddedLogFileParser.cs +++ b/Software/Visual_Studio/Tango.Integration/Logging/EmbeddedLogFileParser.cs @@ -21,7 +21,7 @@ namespace Tango.Integration.Logging FileLogger logger = MachineOperator.EmbeddedLogManager.RegisteredLoggers.FirstOrDefault(x => x.GetType() == typeof(FileLogger)) as FileLogger; String logFile = logger != null ? logger.LogFile : null; - HashSet<string> dateStrings = new HashSet<string>(); + if (Directory.Exists(MachineOperator.EmbeddedLogsFolder)) { foreach (var file in Directory.GetFiles(MachineOperator.EmbeddedLogsFolder, "*.log").Where(x => x != logFile)) @@ -29,20 +29,8 @@ namespace Tango.Integration.Logging try { String dateString = Path.GetFileNameWithoutExtension(file).Replace(MachineOperator.EmbeddedLogsTag + "-", ""); - int indexPos = dateString.IndexOf(FileLogger.FILE_SET_EXTENSION); - int indexOfFile = 0; - if (indexPos > 0) - { - string fileNameIndex = dateString.Substring(indexPos + FileLogger.FILE_SET_EXTENSION.Length); - int.TryParse(fileNameIndex, out indexOfFile); - dateString = dateString.Substring(0, indexPos); - } - if (!dateStrings.Contains(dateString)) - { - dateStrings.Add(dateString); - DateTime date = DateTime.ParseExact(dateString, "dd-MM-yyyy_HH-mm-ss", CultureInfo.InvariantCulture); - logFiles.Add(new LogFile() { DateTime = date, File = file, PartOfSet = indexOfFile > 0, }); - } + DateTime date = DateTime.ParseExact(dateString, "dd-MM-yyyy_HH-mm-ss", CultureInfo.InvariantCulture); + logFiles.Add(new LogFile() { DateTime = date, File = file }); } catch (Exception ex) { @@ -57,33 +45,8 @@ namespace Tango.Integration.Logging public List<EmbeddedLogItem> Parse(LogFile logFile) { List<EmbeddedLogItem> logItems = new List<EmbeddedLogItem>(); - List<LogFile> logFiles = new List<LogFile>(); - FileLogger logger = LogManager.Default.RegisteredLoggers.FirstOrDefault(x => x.GetType() == typeof(FileLogger)) as FileLogger; - if (logFile.PartOfSet) - { - string fileName = Path.GetFileNameWithoutExtension(logFile.File); - string extension = Path.GetExtension(logFile.File); - int indexPos = fileName.IndexOf(FileLogger.FILE_SET_EXTENSION); - if (indexPos > 0) - { - fileName = fileName.Substring(0, indexPos); - } - string[] fileEntries = Directory.GetFiles(FileLogger.DefaultLogsFolder, $"{fileName}*{extension}").Where(x => Path.GetFileName(x).StartsWith(logger.Tag) && x != logger.LogFile).OrderBy(x => x).ToArray(); - foreach (var file in fileEntries) - { - Parse(file, logFile.DateTime, ref logItems); - } - } - else - { - Parse(logFile.File, logFile.DateTime, ref logItems); - } - return logItems; - } - public void Parse(string file, DateTime datetime, ref List<EmbeddedLogItem> logItems) - { - String text = File.ReadAllText(file); + String text = File.ReadAllText(logFile.File); var logs = Regex.Split(text, @"(\[\d{2}:\d{2}:\d{2}.\d{2}\])"); for (int i = 1; i < logs.Length; i += 2) @@ -99,13 +62,13 @@ namespace Tango.Integration.Logging { Category = (PMR.Debugging.DebugLogCategory)Enum.Parse(typeof(PMR.Debugging.DebugLogCategory), entries[1]), FileName = entries[3], - LineNumber = int.Parse(entries[5]), - ModuleId = int.Parse(entries[7]), - Filter = int.Parse(entries[9]), + LineNumber = uint.Parse(entries[5]), + ModuleId = uint.Parse(entries[7]), + Filter = uint.Parse(entries[9]), Message = new String(entries[10].Skip(2).ToArray()) }); - item.TimeStamp = new DateTime(datetime.Year, datetime.Month, datetime.Day, date.Hour, date.Minute, date.Second, date.Millisecond); + item.TimeStamp = new DateTime(logFile.DateTime.Year, logFile.DateTime.Month, logFile.DateTime.Day, date.Hour, date.Minute, date.Second, date.Millisecond); logItems.Add(item); } @@ -114,13 +77,8 @@ namespace Tango.Integration.Logging LogManager.Default.Log(ex, "Could not parse log line: " + logs[i]); } } - } - public List<EmbeddedLogItem> Parse(string file, DateTime fileDate) - { - List<EmbeddedLogItem> logs = new List<EmbeddedLogItem>(); - Parse(file, fileDate, ref logs); - return logs; + return logItems; } } } diff --git a/Software/Visual_Studio/Tango.Integration/Operation/CachedJobOperation.cs b/Software/Visual_Studio/Tango.Integration/Operation/CachedJobOperation.cs deleted file mode 100644 index cca0ca516..000000000 --- a/Software/Visual_Studio/Tango.Integration/Operation/CachedJobOperation.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tango.BL.DTO; -using Tango.PMR.MachineStatus; - -namespace Tango.Integration.Operation -{ - public class CachedJobOperation - { - public JobDTO JobDTO { get; set; } - public MachineStatus MachineStatus { get; set; } - public ProcessParametersTableDTO ProcessParametersDTO { get; set; } - public ConfigurationDTO MachineConfigurationDTO { get; set; } - } -} diff --git a/Software/Visual_Studio/Tango.Integration/Operation/DefaultGradientGenerationConfiguration.cs b/Software/Visual_Studio/Tango.Integration/Operation/DefaultGradientGenerationConfiguration.cs index ef275479b..1f8cf6ada 100644 --- a/Software/Visual_Studio/Tango.Integration/Operation/DefaultGradientGenerationConfiguration.cs +++ b/Software/Visual_Studio/Tango.Integration/Operation/DefaultGradientGenerationConfiguration.cs @@ -9,7 +9,6 @@ using Tango.BL.Enumerations; using Tango.ColorConversion; using Tango.Core; using Tango.Core.ExtensionMethods; -using Tango.PMR.ColorLab; namespace Tango.Integration.Operation { @@ -57,8 +56,6 @@ namespace Tango.Integration.Operation ResolutionCM = 500; } - #region Standard Method - /// <summary> /// Creates a collection of brush stops representing the required gradient steps. /// </summary> @@ -69,11 +66,6 @@ namespace Tango.Integration.Operation /// <returns></returns> public List<BrushStop> Generate(Segment segment, Job job, ProcessParametersTable processParameters, Action<PreparingJobProgressEventArgs> progress = null) { - if (processParameters.ProcessParametersTablesGroup.Rml.UseColorLibGradients) - { - return GenerateUsingColorLib(segment, job, processParameters, progress); - } - aborted = false; List<BrushStop> stops = new List<BrushStop>(); @@ -100,18 +92,16 @@ namespace Tango.Integration.Operation stop.SetLiquidVolumes(job.Machine.Configuration, job.Rml, processParameters); } - if ((stop.BrushColorSpace == ColorSpaces.RGB || stop.BrushColorSpace == ColorSpaces.LAB) && !stop.IsTransparent && !stop.IsWhite) + if (stop.BrushColorSpace == ColorSpaces.RGB || stop.BrushColorSpace == ColorSpaces.LAB) { - var output = converter.Convert(stop, false); + var output = converter.Convert(segment.Job, stop.Color, false); output.ApplyOnBrushStop(stop, processParameters); } } var refStop = clonedStops.First().Clone(segment); - decimal segment_length = (decimal)segment.Length; - - for (decimal cm = 0; cm <= segment_length; cm += (ResolutionCM / 100M)) + for (double cm = 0; cm <= segment.Length; cm += (ResolutionCM / 100d)) { if (aborted) return stops; @@ -137,7 +127,7 @@ namespace Tango.Integration.Operation { Job = job, Total = job.Segments.Sum(x => x.Length), - Progress = previousSegmentsLength + (double)cm, + Progress = previousSegmentsLength + cm, }); } @@ -240,72 +230,6 @@ namespace Tango.Integration.Operation return color; } - #endregion - - #region ColorLib Method - - public List<BrushStop> GenerateUsingColorLib(Segment segment, Job job, ProcessParametersTable processParameters, Action<PreparingJobProgressEventArgs> progress = null) - { - aborted = false; - - List<BrushStop> stops = segment.BrushStops.Select(x => x.Clone()).ToList(); - - var refStop = segment.BrushStops.First().Clone(segment); - - IColorConverter converter = new DefaultColorConverter(); - - foreach (var stop in stops) - { - if (aborted) return stops; - - if (stop.LiquidVolumes == null) - { - stop.SetLiquidVolumes(job.Machine.Configuration, job.Rml, processParameters); - } - } - - var conversionOutput = converter.GenerateGradient(stops, segment.Length, job.Rml, job.Machine.Configuration); - - List<BrushStop> newStops = new List<BrushStop>(); - - int stopIndex = 1; - - foreach (var stop in conversionOutput.Stops) - { - var newStop = refStop.Clone(segment); - - newStop.OffsetPercent = stop.Offset * 100d; - newStop.OffsetMeters = segment.Length * stop.Offset; - newStop.StopIndex = stopIndex++; - - newStop.SetVolume(LiquidTypes.Cyan, GetStopVolume(stop, PMR.ColorLab.LiquidType.Cyan)); - newStop.SetVolume(LiquidTypes.Magenta, GetStopVolume(stop, PMR.ColorLab.LiquidType.Magenta)); - newStop.SetVolume(LiquidTypes.Yellow, GetStopVolume(stop, PMR.ColorLab.LiquidType.Yellow)); - newStop.SetVolume(LiquidTypes.Black, GetStopVolume(stop, PMR.ColorLab.LiquidType.Black)); - - newStop.SetLiquidVolumes(job.Machine.Configuration, job.Rml, processParameters); - - newStops.Add(newStop); - } - - progress?.Invoke(new PreparingJobProgressEventArgs() - { - Job = job, - Total = 100, - Progress = 100, - }); - - return newStops; - } - - private double GetStopVolume(GradientOutputStop stop, PMR.ColorLab.LiquidType liquidType) - { - var liquid = stop.OutputLiquids.SingleOrDefault(x => x.LiquidType == liquidType); - return liquid != null ? liquid.Volume : 0; - } - - #endregion - /// <summary> /// Aborts the current generation. /// </summary> diff --git a/Software/Visual_Studio/Tango.Integration/Operation/DefaultMachineEventsStateProvider.cs b/Software/Visual_Studio/Tango.Integration/Operation/DefaultMachineEventsStateProvider.cs index 79b6e59cb..8c376ea3e 100644 --- a/Software/Visual_Studio/Tango.Integration/Operation/DefaultMachineEventsStateProvider.cs +++ b/Software/Visual_Studio/Tango.Integration/Operation/DefaultMachineEventsStateProvider.cs @@ -16,11 +16,11 @@ namespace Tango.Integration.Operation /// <seealso cref="Tango.Integration.Operation.IMachineEventsStateProvider" /> public class DefaultMachineEventsStateProvider : ExtendedObject, IMachineEventsStateProvider { - private ReadOnlyObservableCollection<MachinesEvent> _events; + private ReadOnlyCollection<MachinesEvent> _events; /// <summary> /// Gets the current machine events. /// </summary> - public ReadOnlyObservableCollection<MachinesEvent> Events + public ReadOnlyCollection<MachinesEvent> Events { get { @@ -64,7 +64,7 @@ namespace Tango.Integration.Operation /// </summary> public DefaultMachineEventsStateProvider() { - _events = new ReadOnlyObservableCollection<MachinesEvent>(new ObservableCollection<MachinesEvent>()); + _events = new ReadOnlyCollection<MachinesEvent>(new Collection<MachinesEvent>()); } /// <summary> @@ -79,7 +79,7 @@ namespace Tango.Integration.Operation List<MachinesEvent> newEvents = receivedEvents.Where(x => !_events.ToList().Exists(y => y.Type == x.Type)).ToList(); List<MachinesEvent> oldEvents = _events.Where(x => !receivedEvents.Exists(y => y.Type == x.Type)).ToList(); - _events = new ReadOnlyObservableCollection<MachinesEvent>(new ObservableCollection<MachinesEvent>(receivedEvents)); + _events = new ReadOnlyCollection<MachinesEvent>(receivedEvents); if (newEvents.Count > 0) { @@ -93,7 +93,7 @@ namespace Tango.Integration.Operation if (newEvents.Count > 0 || oldEvents.Count > 0) { RaisePropertyChanged(nameof(Events)); - OnEventsChanged(_events); + OnEventsChanged(newEvents.Concat(oldEvents)); } OnEventsReceived(_events); @@ -142,7 +142,7 @@ namespace Tango.Integration.Operation /// </summary> public void Reset() { - _events = new ReadOnlyObservableCollection<MachinesEvent>(new ObservableCollection<MachinesEvent>(new List<MachinesEvent>())); + _events = new ReadOnlyCollection<MachinesEvent>(new List<MachinesEvent>()); RaisePropertyChanged(nameof(Events)); OnEventsChanged(new List<MachinesEvent>()); } diff --git a/Software/Visual_Studio/Tango.Integration/Operation/HeadCleaningEndedEventArgs.cs b/Software/Visual_Studio/Tango.Integration/Operation/HeadCleaningEndedEventArgs.cs deleted file mode 100644 index 0929c1254..000000000 --- a/Software/Visual_Studio/Tango.Integration/Operation/HeadCleaningEndedEventArgs.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tango.BL.Enumerations; -using Tango.BL.ValueObjects; - -namespace Tango.Integration.Operation -{ - public class HeadCleaningEndedEventArgs : EventArgs - { - public List<JobRunLiquidQuantity> LiquidQuantities { get; set; } - public DateTime StartDate { get; set; } - public double EndPosition { get; set; } - public double Length { get; set; } - public JobRunStatus Status { get; set; } - - public HeadCleaningEndedEventArgs() - { - LiquidQuantities = new List<JobRunLiquidQuantity>(); - } - } -} diff --git a/Software/Visual_Studio/Tango.Integration/Operation/HeadCleaningHandler.cs b/Software/Visual_Studio/Tango.Integration/Operation/HeadCleaningHandler.cs deleted file mode 100644 index d82666a60..000000000 --- a/Software/Visual_Studio/Tango.Integration/Operation/HeadCleaningHandler.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tango.Core; -using Tango.PMR.Printing; - -namespace Tango.Integration.Operation -{ - public class HeadCleaningHandler : ExtendedObject - { - private Action _abortAction; - - public event EventHandler<HeadCleaningStatusChangedEventArgs> StatusChanged; - public event EventHandler<Exception> Failed; - public event EventHandler Completed; - - private StartHeadCleaningResponse _status; - public StartHeadCleaningResponse Status - { - get { return _status; } - set { _status = value; RaisePropertyChangedAuto(); } - } - - public HeadCleaningHandler(Action abortAction) - { - _abortAction = abortAction; - - Status = new StartHeadCleaningResponse() - { - Total = 100, - Progress = 0, - Status = "Initializing..." - }; - } - - internal void RaiseStatusChanged(StartHeadCleaningResponse status) - { - OnStatusChanged(status); - } - - internal void RaiseFailed(Exception ex) - { - OnFailed(ex); - } - - internal void RaiseCompleted() - { - OnCompleted(); - } - - private void OnStatusChanged(StartHeadCleaningResponse status) - { - Status = status; - StatusChanged?.Invoke(this, new HeadCleaningStatusChangedEventArgs() - { - Status = status - }); - } - - private void OnCompleted() - { - Completed?.Invoke(this, new EventArgs()); - } - - private void OnFailed(Exception ex) - { - Failed?.Invoke(this, ex); - } - - public Task Abort() - { - return Task.Factory.StartNew(() => - { - _abortAction.Invoke(); - }); - } - } -} diff --git a/Software/Visual_Studio/Tango.Integration/Operation/HeadCleaningStatusChangedEventArgs.cs b/Software/Visual_Studio/Tango.Integration/Operation/HeadCleaningStatusChangedEventArgs.cs deleted file mode 100644 index 6ec55ce21..000000000 --- a/Software/Visual_Studio/Tango.Integration/Operation/HeadCleaningStatusChangedEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tango.PMR.Printing; - -namespace Tango.Integration.Operation -{ - public class HeadCleaningStatusChangedEventArgs : EventArgs - { - public StartHeadCleaningResponse Status { get; set; } - } -} diff --git a/Software/Visual_Studio/Tango.Integration/Operation/IMachineEventsStateProvider.cs b/Software/Visual_Studio/Tango.Integration/Operation/IMachineEventsStateProvider.cs index e6084c12a..2cf00904f 100644 --- a/Software/Visual_Studio/Tango.Integration/Operation/IMachineEventsStateProvider.cs +++ b/Software/Visual_Studio/Tango.Integration/Operation/IMachineEventsStateProvider.cs @@ -17,7 +17,7 @@ namespace Tango.Integration.Operation /// <summary> /// Gets the current machine events. /// </summary> - ReadOnlyObservableCollection<MachinesEvent> Events { get; } + ReadOnlyCollection<MachinesEvent> Events { get; } /// <summary> /// Gets or sets a value indicating whether this instance has events. diff --git a/Software/Visual_Studio/Tango.Integration/Operation/IMachineOperator.cs b/Software/Visual_Studio/Tango.Integration/Operation/IMachineOperator.cs index e7d3cd0e8..733f7a981 100644 --- a/Software/Visual_Studio/Tango.Integration/Operation/IMachineOperator.cs +++ b/Software/Visual_Studio/Tango.Integration/Operation/IMachineOperator.cs @@ -23,9 +23,6 @@ using Tango.PMR.FirmwareUpgrade; using Tango.Integration.JobRuns; using Tango.Integration.Emergency; using Tango.PMR.MachineStatus; -using Tango.PMR.ThreadLoading; -using Tango.PMR.Power; -using Tango.PMR.IFS; namespace Tango.Integration.Operation { @@ -51,21 +48,11 @@ namespace Tango.Integration.Operation JobUnitsMethods JobUnitsMethod { get; set; } /// <summary> - /// Gets or sets the way of calculating how much liquid was spent during the job. - /// </summary> - JobLiquidQuantityCalculationMode JobLiquidQuantityCalculationMode { get; set; } - - /// <summary> /// Gets the current machine status. /// </summary> MachineStatuses Status { get; } /// <summary> - /// Gets a value indicating whether the machine is connected and status is not disconnected. - /// </summary> - bool IsConnected { get; } - - /// <summary> /// Gets or sets a value indicating whether to enable liquid quantity validation before starting the job. /// The validation is done using the reported <see cref="MachineStatus"/>. /// </summary> @@ -77,16 +64,6 @@ namespace Tango.Integration.Operation MachineStatus MachineStatus { get; } /// <summary> - /// Gets the current thread loading status. - /// </summary> - StartThreadLoadingResponse ThreadLoadingStatus { get; } - - /// <summary> - /// Gets the ink filling status. - /// </summary> - InkFillingStatus InkFillingStatus { get; } - - /// <summary> /// Gets or sets the firmware upgrade mode. /// </summary> FirmwareUpgradeModes FirmwareUpgradeMode { get; set; } @@ -122,11 +99,6 @@ namespace Tango.Integration.Operation bool CanPrint { get; } /// <summary> - /// Gets or sets the general continuous request timeout. - /// </summary> - TimeSpan ContinuousRequestTimeout { get; set; } - - /// <summary> /// Occurs when the machine <see cref="Status"/> has changed. /// </summary> event EventHandler<MachineStatuses> StatusChanged; @@ -167,94 +139,49 @@ namespace Tango.Integration.Operation event EventHandler<ResumingJobEventArgs> ResumingJob; /// <summary> - /// Occurs when there is new diagnostics data available. + /// Occurs when a request has been sent. /// </summary> - event EventHandler<StartDiagnosticsResponse> DiagnosticsDataAvailable; + event EventHandler<IMessage> RequestSent; /// <summary> - /// Occurs when an events notification has been received from the embedded device. + /// Occurs when a request response has been received. /// </summary> - event EventHandler<StartEventsNotificationResponse> EventsNotification; + event EventHandler<IMessage> ResponseReceived; /// <summary> - /// Occurs when a new debug log is available. + /// Occurs when a response has been sent. /// </summary> - event EventHandler<StartDebugLogResponse> DebugLogAvailable; + event EventHandler<IMessage> ResponseSent; /// <summary> - /// Occurs when machine embedded device status has changed. + /// Occurs when a request has failed. /// </summary> - event EventHandler<MachineStatus> MachineStatusChanged; + event EventHandler<RequestFailedEventArgs> RequestFailed; /// <summary> - /// Occurs when a new cartridge validation request has been received. - /// </summary> - event EventHandler<CartridgeValidationEventArgs> CartridgeValidationRequestReceived; - - /// <summary> - /// Occurs when the machine was connected and device has reported IsAfterReset. - /// </summary> - event EventHandler FirmwareStarted; - - /// <summary> - /// Occurs when the power up sequence has started. - /// </summary> - event EventHandler<StartPowerUpResponse> PowerUpStarted; - - /// <summary> - /// Occurs when the power up sequence progress has changed. - /// </summary> - event EventHandler<StartPowerUpResponse> PowerUpProgress; - - /// <summary> - /// Occurs when power up sequence has completed successfully. - /// </summary> - event EventHandler<StartPowerUpResponse> PowerUpCompleted; - - /// <summary> - /// Occurs when power up sequence has failed. - /// </summary> - event EventHandler<StartPowerUpResponse> PowerUpFailed; - - /// <summary> - /// Occurs when power up sequence has ended. Could be due to no response to the request! - /// </summary> - event EventHandler PowerUpEnded; - - /// <summary> - /// Occurs when power down has started. - /// </summary> - event EventHandler<PowerDownStartedEventArgs> PowerDownStarted; - - /// <summary> - /// Occurs when the thread loading status has changed. - /// </summary> - event EventHandler<StartThreadLoadingResponse> ThreadLoadingStatusChanged; - - /// <summary> - /// Occurs when a thread loading confirmation is required. + /// Occurs when there is new diagnostics data available. /// </summary> - event EventHandler<ThreadLoadingConfirmationRequiredEventArgs> ThreadLoadingConfirmationRequired; + event EventHandler<StartDiagnosticsResponse> DiagnosticsDataAvailable; /// <summary> - /// Occurs when thread loading has completed. + /// Occurs when an events notification has been received from the embedded device. /// </summary> - event EventHandler<StartThreadLoadingResponse> ThreadLoadingCompleted; + event EventHandler<StartEventsNotificationResponse> EventsNotification; /// <summary> - /// Occurs when thread loading has failed. + /// Occurs when a new debug log is available. /// </summary> - event EventHandler<StartThreadLoadingResponse> ThreadLoadingFailed; + event EventHandler<StartDebugLogResponse> DebugLogAvailable; /// <summary> - /// Occurs when a head cleaning job has ended. + /// Occurs when machine embedded device status has changed. /// </summary> - event EventHandler<HeadCleaningEndedEventArgs> HeadCleaningEnded; + event EventHandler<MachineStatus> MachineStatusChanged; /// <summary> - /// Occurs when the ink filling status has changed. + /// Occurs when a new cartridge validation request has been received. /// </summary> - event EventHandler<InkFillingStatusChangedEventArgs> InkFillingStatusChanged; + event EventHandler<CartridgeValidationEventArgs> CartridgeValidationRequestReceived; /// <summary> /// Gets or sets a value indicating whether direct the embedded device to send diagnostics messages. @@ -282,21 +209,6 @@ namespace Tango.Integration.Operation bool EnableMachineStatusUpdates { get; set; } /// <summary> - /// Gets or sets a value indicating whether to enable automatic thread loading support. - /// </summary> - bool EnableAutomaticThreadLoading { get; set; } - - /// <summary> - /// Gets or sets a value indicating whether to enable the power sequence tracking. - /// </summary> - bool EnablePowerUpSequence { get; set; } - - /// <summary> - /// Gets or sets a value indicating whether to enable the ink/waste filling status channel. - /// </summary> - bool EnableInkFillingStatus { get; set; } - - /// <summary> /// Gets the last process parameters table sent to the embedded device. /// </summary> ProcessParametersTable CurrentProcessParameters { get; } @@ -331,6 +243,15 @@ namespace Tango.Integration.Operation Task<JobHandler> Print(Job job); /// <summary> + /// Executes a print stub for emulating a full job. + /// The process parameters table will be calculated using color conversion gamut region. + /// This method cannot accept brush stops with 'Volume' as color space. + /// </summary> + /// <param name="job">The job.</param> + /// <returns></returns> + Task<JobHandler> PrintStub(Job job); + + /// <summary> /// Prints the specified job using the specified job parameters. /// </summary> /// <param name="job">The job.</param> @@ -476,12 +397,6 @@ namespace Tango.Integration.Operation Task<StubFpgaWriteRegResponse> Reset(); /// <summary> - /// Directs the embedded device to switch to stand-by mode. - /// </summary> - /// <returns></returns> - Task StandBy(); - - /// <summary> /// Resets the device through the DFU channel. /// </summary> /// <returns></returns> @@ -491,9 +406,8 @@ namespace Tango.Integration.Operation /// Upgrades the firmware. /// </summary> /// <param name="tfpStream">The TFP stream (Tango Firmware Package File).</param> - /// <param name="isEmulated">Specify whether the connected machine is emulated and to skip the actual DFU interface.</param> /// <returns></returns> - Task<FirmwareUpgradeHandler> UpgradeFirmware(Stream tfpStream, bool isEmulated = false); + Task<FirmwareUpgradeHandler> UpgradeFirmware(Stream tfpStream); /// <summary> /// Directs the embedded device to validate the last uploaded firmware package. @@ -519,43 +433,5 @@ namespace Tango.Integration.Operation /// </summary> /// <returns></returns> StorageManager CreateStorageManager(); - - /// <summary> - /// Turns off the machine. - /// </summary> - /// <returns></returns> - Task<PowerDownHandler> PowerDown(); - - /// <summary> - /// Starts a manual head cleaning process. - /// </summary> - /// <returns></returns> - Task<HeadCleaningHandler> PerformHeadCleaning(); - - /// <summary> - /// Starts the automatic thread loading process. - /// </summary> - /// <returns></returns> - Task StartThreadLoading(); - - /// <summary> - /// Continues the current thread loading. - /// </summary> - /// <param name="processParameters">The process parameters.</param> - /// <returns></returns> - Task ContinueThreadLoading(ProcessParametersTable processParameters); - - /// <summary> - /// Attempts to jog the thread in order to check whether there are no thread breaking issues. - /// </summary> - /// <returns></returns> - Task AttemptThreadJogging(); - - /// <summary> - /// Emulates a hardware event that will last for the specified timeout. - /// </summary> - /// <param name="ev">Type of the event.</param> - /// <param name="timeout">The timeout.</param> - void PushEmulatedEvent(Event ev, TimeSpan timeout); } } diff --git a/Software/Visual_Studio/Tango.Integration/Operation/InkFillingStatusChangedEventArgs.cs b/Software/Visual_Studio/Tango.Integration/Operation/InkFillingStatusChangedEventArgs.cs deleted file mode 100644 index e674dc777..000000000 --- a/Software/Visual_Studio/Tango.Integration/Operation/InkFillingStatusChangedEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tango.PMR.IFS; - -namespace Tango.Integration.Operation -{ - public class InkFillingStatusChangedEventArgs : EventArgs - { - public InkFillingStatus Status { get; set; } - } -} diff --git a/Software/Visual_Studio/Tango.Integration/Operation/InsufficientLiquidQuantityException.cs b/Software/Visual_Studio/Tango.Integration/Operation/InsufficientLiquidQuantityException.cs index 797d4f498..a1c18370b 100644 --- a/Software/Visual_Studio/Tango.Integration/Operation/InsufficientLiquidQuantityException.cs +++ b/Software/Visual_Studio/Tango.Integration/Operation/InsufficientLiquidQuantityException.cs @@ -14,25 +14,11 @@ namespace Tango.Integration.Operation public IdsPack IdsPack { get; set; } public int Current { get; set; } public int Required { get; set; } - public int Maximum { get; set; } public bool IsValid { get { return Current >= Required; } } - - public bool IsOverMax - { - get { return Required > Maximum; } - } - - public String Message { get; set; } - public IDSPackLevel() - { - Maximum = 130000000; - Required = 0; - Current = 0; - } } public InsufficientLiquidQuantityException(String message) : base(message) @@ -41,7 +27,5 @@ namespace Tango.Integration.Operation } public List<IDSPackLevel> IdsPackLevels { get; internal set; } - - } } diff --git a/Software/Visual_Studio/Tango.Integration/Operation/JobHandler.cs b/Software/Visual_Studio/Tango.Integration/Operation/JobHandler.cs index fce815bc3..4b0066d7f 100644 --- a/Software/Visual_Studio/Tango.Integration/Operation/JobHandler.cs +++ b/Software/Visual_Studio/Tango.Integration/Operation/JobHandler.cs @@ -17,15 +17,13 @@ namespace Tango.Integration.Operation /// <seealso cref="Tango.Core.ExtendedObject" /> public class JobHandler : ExtendedObject { - protected Action _cancelAction; - protected List<Segment> _effectiveSegments; - protected String _lastStatusMessage; - protected int _last_unit; - protected bool _finalizing; - protected JobHandlerModes _mode; - protected double _last_progress; - protected const int PROGRESS_REPORT_RANGE_METERS = 5; - protected bool loggedContinueMessage; + private Action _cancelAction; + private List<Segment> _effectiveSegments; + private String _lastStatusMessage; + private int _last_unit; + private bool _finalizing; + private JobHandlerModes _mode; + private double _last_progress; #region Events @@ -79,40 +77,15 @@ namespace Tango.Integration.Operation /// </summary> public event EventHandler<SpoolChangeRequiredEventArgs> SpoolChangeRequired; - /// <summary> - /// Occurs when <see cref="CanCancel"/> has changed. - /// </summary> - public event EventHandler CanCancelChanged; - #endregion #region Properties - private JobStatus _jobStatus; - /// <summary> - /// Gets or sets the current job status that was used to invalidate this handler. - /// </summary> - public JobStatus JobStatus - { - get { return _jobStatus; } - set { _jobStatus = value; RaisePropertyChangedAuto(); } - } - /// <summary> /// Gets a value indicating whether this handler job has been canceled. /// </summary> public bool IsCanceled { get; internal set; } - private bool _canCancel; - /// <summary> - /// Gets a value indicating whether the job can be canceled. - /// </summary> - public bool CanCancel - { - get { return _canCancel; } - internal set { _canCancel = value; RaisePropertyChangedAuto(); CanCancelChanged?.Invoke(this, new EventArgs()); } - } - /// <summary> /// Gets the process parameters. /// </summary> @@ -147,14 +120,14 @@ namespace Tango.Integration.Operation /// </summary> public JobHandler() { - CanCancel = true; + } /// <summary> /// Initializes a new instance of the <see cref="JobHandler"/> class. /// </summary> /// <param name="cancelAction">The cancel action.</param> - public JobHandler(Action cancelAction, Job job, JobTicket jobTicket, ProcessParametersTable processParameters, JobHandlerModes mode) : this() + internal JobHandler(Action cancelAction, Job job, JobTicket jobTicket, ProcessParametersTable processParameters, JobHandlerModes mode) : this() { _mode = mode; @@ -171,7 +144,7 @@ namespace Tango.Integration.Operation _effectiveSegments = Job.EffectiveSegments.ToList(); - _cancelAction = () => { cancelAction(); }; + _cancelAction = () => { IsCanceled = true; cancelAction(); }; Status = new RunningJobStatus(); @@ -205,7 +178,7 @@ namespace Tango.Integration.Operation //Create all segments int segment_index = 1; - for (int j = 0; j < Math.Max(Job.NumberOfUnits, 1); j++) + for (int j = 0; j < Job.NumberOfUnits; j++) { for (int i = 0; i < _effectiveSegments.Count; i++) { @@ -241,7 +214,7 @@ namespace Tango.Integration.Operation /// Raises the status received event. /// </summary> /// <param name="status">The status.</param> - public void RaiseStatusReceived(JobStatus status) + internal void RaiseStatusReceived(JobStatus status) { InvalidateJobProgress(status); } @@ -250,11 +223,10 @@ namespace Tango.Integration.Operation /// Raises the failed event. /// </summary> /// <param name="ex">The ex.</param> - public void RaiseFailed(Exception ex) + internal void RaiseFailed(Exception ex) { - LogManager.Log($"Job failed at position {Status.Progress}/{Status.TotalProgress}..."); Status.IsFailed = true; - RaiseStatusChanged(); + StatusChanged?.Invoke(this, Status); RaisePropertyChanged(nameof(Status)); Failed?.Invoke(this, ex); Stopped?.Invoke(this, new EventArgs()); @@ -263,36 +235,13 @@ namespace Tango.Integration.Operation /// <summary> /// Raises the completed event. /// </summary> - public void RaiseCompleted() + internal void RaiseCompleted() { - //This will compensate on any missing progress from Shlomo, but also will tell the wrong progress if job is really completed with a large progress mistake. - // Might be worth to compensate only on small drifts like the below (ProgressMinusSettingsUp)... - //InvalidateJobProgress(new JobStatus() - //{ - // Progress = Status.TotalProgress, - // CurrentSegmentIndex = 0, - //}); - - LogManager.Log($"Job completed at position {Status.Progress}/{Status.TotalProgress}..."); - - //If drift is smaller than 10cm auto correct it. - if (Math.Abs(Status.TotalProgressMinusSettingUp - Status.ProgressMinusSettingUp) < 0.1) - { - LogManager.Log($"Job completed with a small drift in the progress minus setting up calculation. ({Status.ProgressMinusSettingUp}/{Status.TotalProgressMinusSettingUp}). Compensating..."); - Status.ProgressMinusSettingUp = Status.TotalProgressMinusSettingUp; - } - //If the overall progress is correct? Fix the minus setting up. There is a problem with the delta calc! - else if (Status.Progress == Status.TotalProgress) - { - LogManager.Log($"Job completed with a small drift in the progress minus setting up calculation but the overall progress seems OK. ({Status.ProgressMinusSettingUp}/{Status.TotalProgressMinusSettingUp}). Compensating..."); - Status.ProgressMinusSettingUp = Status.TotalProgressMinusSettingUp; - } - Status.Segments.Last().Completed = true; Status.RemainingUnits = 0; Status.IsFinalizing = false; Status.IsCompleted = true; - RaiseStatusChanged(); + StatusChanged?.Invoke(this, Status); RaisePropertyChanged(nameof(Status)); Completed?.Invoke(this, new EventArgs()); Stopped?.Invoke(this, new EventArgs()); @@ -301,11 +250,10 @@ namespace Tango.Integration.Operation /// <summary> /// Raises the canceled event. /// </summary> - public void RaiseCanceled() + internal void RaiseCanceled() { - LogManager.Log($"Job canceled at position {Status.Progress}/{Status.TotalProgress}..."); Status.IsCanceled = true; - RaiseStatusChanged(); + StatusChanged?.Invoke(this, Status); RaisePropertyChanged(nameof(Status)); Canceled?.Invoke(this, new EventArgs()); Stopped?.Invoke(this, new EventArgs()); @@ -327,342 +275,71 @@ namespace Tango.Integration.Operation #region Private Methods - //protected virtual void InvalidateJobProgress(JobStatus s) - //{ - // JobStatus = s; - // bool invalidProgress = false; - - // if (_last_progress != s.Progress) - // { - // if (s.Progress <= PROGRESS_REPORT_RANGE_METERS || s.Progress >= Status.TotalProgress - PROGRESS_REPORT_RANGE_METERS) - // { - // LogManager.Log($"Updating job progress {s.Progress}/{Status.TotalProgress}..."); - // } - // else if (!loggedContinueMessage) - // { - // loggedContinueMessage = true; - // LogManager.Log($"Progress logging will continue {PROGRESS_REPORT_RANGE_METERS} meters before completion..."); - // } - // } - - // if (s.Progress < 0) - // { - // LogManager.Log($"Invalid job progress received '{s.Progress}'.", LogCategory.Error); - // invalidProgress = true; - // } - - // if (s.Progress > Status.TotalProgress) - // { - // LogManager.Log($"Invalid job progress received '{s.Progress}' while total progress is '{Status.TotalProgress}'.", LogCategory.Error); - // invalidProgress = true; - // } - - // if (s.Progress < _last_progress) - // { - // LogManager.Log($"Invalid job progress received '{s.Progress}' while last progress was '{_last_progress}'."); - // invalidProgress = true; - // } - - // if (invalidProgress) - // { - // return; - // } - - // _last_progress = s.Progress; - - // //Job Status - // if (IsCanceled) - // { - // Status.IsCanceled = IsCanceled; - // RaiseStatusChanged(); - // return; - // } - - // List<Segment> unit_segments = new List<Segment>(); - // double delta = s.Progress - Status.Progress; - - // Status.Progress = s.Progress; - // Status.RemainingTime = Status.TotalTime - Job.TranslateProgressToTime(Status.Progress, ProcessParameters); - // Status.RemainingProgress = Status.TotalProgress - Status.Progress; - - // if (Status.SettingUpProgress < Status.SettingUpTotalProgress) - // { - // Status.SettingUpProgress += delta; - // } - // else - // { - // if (Status.IsSettingUp && Status.Progress > 0) - // { - // Status.IsSettingUp = false; - // } - - // Status.ProgressMinusSettingUp += delta; - // } - - // if (s.Progress < Job.LengthIncludingNumberOfUnits || _mode == JobHandlerModes.SettingUp) - // { - // Status.ProgressWithoutFinalization += delta; - - // unit_segments = _effectiveSegments.ToList(); - - // if (Job.EnableInterSegment && Job.NumberOfUnits > 1 && Status.RemainingUnits > 1) - // { - // unit_segments.Add(Job.CreateInterSegment(Job.InterSegmentLength)); - // } - - // if (unit_segments.Count != Status.CurrentUnitSegments.Count) - // { - // Status.CurrentUnitSegments = unit_segments; - // } - - // Status.CurrentUnitTotalProgress = Status.RemainingUnits > 1 && Job.EnableInterSegment ? Job.Length + (Job.InterSegmentLength) : Job.Length; - - // if (_mode == JobHandlerModes.Finalization) - // { - // Status.CurrentUnitProgress += delta; - // } - // else - // { - // if (!Status.IsSettingUp) - // { - // Status.CurrentUnitProgress += delta; - // } - // } - - // if (Status.CurrentUnitProgress >= Status.CurrentUnitTotalProgress) - // { - // Status.CurrentUnitProgress = 0; - // Status.CurrentUnit++; - // } - - // Status.RemainingUnits = Job.NumberOfUnits - Status.CurrentUnit; - - // if (s.Message != _lastStatusMessage && s.Message != String.Empty) - // { - // Status.Message = s.Message; - // } - // else - // { - // Status.Message = null; - // } - - // _lastStatusMessage = s.Message; - - // RaiseStatusChanged(); - - // //Segments Completion - - // if (Status.CurrentUnit > _last_unit) - // { - // foreach (var segment in Status.CurrentUnitSegments) - // { - // segment.Started = false; - // segment.Completed = false; - // } - - // if (Job.NumberOfUnits > 1) - // { - // RaiseUnitCompleted(_last_unit); - // } - // } - - // _last_unit = Status.CurrentUnit; - - - // for (int i = 0; i < Status.CurrentUnitSegments.Count; i++) - // { - // Segment segment = Status.CurrentUnitSegments[i]; - // double previousSegmentsLengthWithThis = Status.CurrentUnitSegments.Take(i + 1).Sum(x => x.LengthWithFactor); - // TimeSpan segmentsDuration = Job.TranslateProgressToTime(previousSegmentsLengthWithThis, ProcessParameters); - // TimeSpan segmentRemainingTime = segmentsDuration - Job.TranslateProgressToTime(Status.CurrentUnitProgress, ProcessParameters); - - // if (i == 0 && Status.CurrentUnitProgress > 0) - // { - // if (!segment.Started) - // { - // segment.Started = true; - // RaiseSegmentStarted(segment); - // } - // } - - // if (Status.CurrentUnitProgress >= previousSegmentsLengthWithThis) - // { - // if (!segment.Completed) - // { - // segment.Completed = true; - // RaiseSegmentCompleted(segment); - // } - - // if (i < Status.CurrentUnitSegments.Count - 1) - // { - // if (!Status.CurrentUnitSegments[i + 1].Started) - // { - // Status.CurrentUnitSegments[i + 1].Started = true; - // RaiseSegmentStarted(Status.CurrentUnitSegments[i + 1]); - // } - // } - // } - - // if (segment.Started && !segment.Completed) - // { - // segment.RemainingTime = segmentRemainingTime; - // } - // } - - - // //Set Segment Completion for All Segments List - // for (int i = 0; i < Status.Segments.Count; i++) - // { - // Segment segment = Status.Segments[i]; - // double previousSegmentsLengthWithThis = Status.Segments.Take(i + 1).Sum(x => x.LengthWithFactor); - // TimeSpan segmentsDuration = Job.TranslateProgressToTime(previousSegmentsLengthWithThis, ProcessParameters); - // TimeSpan segmentRemainingTime = segmentsDuration - Job.TranslateProgressToTime(Status.Progress, ProcessParameters); - - // segment.Progress = Math.Min(Math.Max((previousSegmentsLengthWithThis - segment.Length - Status.Progress) * -1, 0), segment.Length); - - // if (i == 0 && Status.Progress > 0) - // { - // if (!segment.Started) - // { - // segment.Started = true; - // Status.CurrentSegment = segment; - // } - // } - - // if (Status.Progress >= previousSegmentsLengthWithThis) - // { - // if (!segment.Completed) - // { - // segment.Completed = true; - // } - - // if (i < Status.Segments.Count - 1) - // { - // if (!Status.Segments[i + 1].Started) - // { - // Status.Segments[i + 1].Started = true; - // Status.CurrentSegment = Status.Segments[i + 1]; - // } - // } - // } - - // if (segment.Started && !segment.Completed) - // { - // segment.RemainingTime = segmentRemainingTime; - // } - // } - // } - // else - // { - // //Finalizing - // if (!_finalizing) - // { - // _finalizing = true; - // Status.IsFinalizing = true; - // var last_Segment = _effectiveSegments.Last().Clone(); - // last_Segment.Length = ProcessParameters.DryerBufferLengthMeters; - // Status.CurrentUnitSegments = new List<Segment> { last_Segment }; - // Status.CurrentUnitTotalProgress = last_Segment.Length; - // Status.CurrentUnitProgress = 0; - // Status.ProgressWithoutFinalization = Status.TotalProgressWithoutFinalization; - // RaiseFinalizing(); - // } - - // Status.CurrentUnitProgress += delta; - // Status.FinalizingProgress += delta; - // } - //} - - protected virtual void InvalidateJobProgress(JobStatus s) + private void InvalidateJobProgress(JobStatus s) { - JobStatus = s; + bool invalidProgress = false; - if (_last_progress != s.Progress) - { - if (s.Progress <= PROGRESS_REPORT_RANGE_METERS || s.Progress >= Status.TotalProgress - PROGRESS_REPORT_RANGE_METERS) - { - LogManager.Log($"Updating job progress {s.Progress}/{Status.TotalProgress}..."); - } - else if (!loggedContinueMessage) - { - loggedContinueMessage = true; - LogManager.Log($"Progress logging will continue {PROGRESS_REPORT_RANGE_METERS} meters before completion..."); - } - } + LogManager.Log($"Updating job progress {s.Progress}/{Status.TotalProgress}..."); if (s.Progress < 0) { LogManager.Log($"Invalid job progress received '{s.Progress}'.", LogCategory.Error); - return; + invalidProgress = true; } if (s.Progress > Status.TotalProgress) { LogManager.Log($"Invalid job progress received '{s.Progress}' while total progress is '{Status.TotalProgress}'.", LogCategory.Error); - return; + invalidProgress = true; } if (s.Progress < _last_progress) { LogManager.Log($"Invalid job progress received '{s.Progress}' while last progress was '{_last_progress}'."); + invalidProgress = true; + } + + if (invalidProgress) + { + return; } _last_progress = s.Progress; + //Job Status + if (IsCanceled) + { + Status.IsCanceled = IsCanceled; + StatusChanged?.Invoke(this, Status); + return; + } + List<Segment> unit_segments = new List<Segment>(); + double delta = s.Progress - Status.Progress; Status.Progress = s.Progress; Status.RemainingTime = Status.TotalTime - Job.TranslateProgressToTime(Status.Progress, ProcessParameters); Status.RemainingProgress = Status.TotalProgress - Status.Progress; - if (s.Progress < Status.SettingUpTotalProgress || Status.SettingUpProgress < Status.SettingUpTotalProgress) + if (Status.SettingUpProgress < Status.SettingUpTotalProgress) { - Status.SettingUpProgress = Math.Min(s.Progress, this.Status.SettingUpTotalProgress); - Status.IsSettingUp = true; + Status.SettingUpProgress += delta; } - if (s.Progress >= Status.SettingUpTotalProgress) + else { if (Status.IsSettingUp && Status.Progress > 0) { Status.IsSettingUp = false; } - Status.ProgressMinusSettingUp = s.Progress - this.Status.SettingUpTotalProgress; + Status.ProgressMinusSettingUp += delta; } - int units = (int)Math.Max(Job.NumberOfUnits, 1); - if (s.Progress < Job.LengthIncludingNumberOfUnits || _mode == JobHandlerModes.SettingUp) { - Status.ProgressWithoutFinalization = s.Progress; + Status.ProgressWithoutFinalization += delta; unit_segments = _effectiveSegments.ToList(); - Status.CurrentUnitProgress = 0.0; - double previousUnitsLengthWithoutThis = 0.0; - for (int index = 0; index < units; ++index) - { - Status.CurrentUnit = index; - double unitLength = !Job.EnableInterSegment || index >= units - 1 ? Job.Length : Job.Length + Job.InterSegmentLength; - if (_mode == JobHandlerModes.Finalization) - { - if (s.Progress < unitLength + previousUnitsLengthWithoutThis) - { - Status.CurrentUnitProgress = s.Progress - previousUnitsLengthWithoutThis; - break; - } - } - else if (s.Progress <= previousUnitsLengthWithoutThis + unitLength + Status.SettingUpProgress) - { - if (!Status.IsSettingUp) - { - Status.CurrentUnitProgress = s.Progress - previousUnitsLengthWithoutThis - this.Status.SettingUpProgress; - break; - } - break; - } - previousUnitsLengthWithoutThis += unitLength; - } - Status.RemainingUnits = this.Job.NumberOfUnits - this.Status.CurrentUnit; if (Job.EnableInterSegment && Job.NumberOfUnits > 1 && Status.RemainingUnits > 1) { @@ -676,6 +353,26 @@ namespace Tango.Integration.Operation Status.CurrentUnitTotalProgress = Status.RemainingUnits > 1 && Job.EnableInterSegment ? Job.Length + (Job.InterSegmentLength) : Job.Length; + if (_mode == JobHandlerModes.Finalization) + { + Status.CurrentUnitProgress += delta; + } + else + { + if (!Status.IsSettingUp) + { + Status.CurrentUnitProgress += delta; + } + } + + if (Status.CurrentUnitProgress >= Status.CurrentUnitTotalProgress) + { + Status.CurrentUnitProgress = 0; + Status.CurrentUnit++; + } + + Status.RemainingUnits = Job.NumberOfUnits - Status.CurrentUnit; + if (s.Message != _lastStatusMessage && s.Message != String.Empty) { Status.Message = s.Message; @@ -687,10 +384,10 @@ namespace Tango.Integration.Operation _lastStatusMessage = s.Message; - - RaiseStatusChanged(); + StatusChanged?.Invoke(this, Status); //Segments Completion + if (Status.CurrentUnit > _last_unit) { foreach (var segment in Status.CurrentUnitSegments) @@ -701,7 +398,7 @@ namespace Tango.Integration.Operation if (Job.NumberOfUnits > 1) { - RaiseUnitCompleted(_last_unit); + UnitCompleted?.Invoke(this, _last_unit); } } @@ -720,7 +417,7 @@ namespace Tango.Integration.Operation if (!segment.Started) { segment.Started = true; - RaiseSegmentStarted(segment); + SegmentStarted?.Invoke(this, segment); } } @@ -729,7 +426,7 @@ namespace Tango.Integration.Operation if (!segment.Completed) { segment.Completed = true; - RaiseSegmentCompleted(segment); + SegmentCompleted?.Invoke(this, segment); } if (i < Status.CurrentUnitSegments.Count - 1) @@ -737,7 +434,7 @@ namespace Tango.Integration.Operation if (!Status.CurrentUnitSegments[i + 1].Started) { Status.CurrentUnitSegments[i + 1].Started = true; - RaiseSegmentStarted(Status.CurrentUnitSegments[i + 1]); + SegmentStarted?.Invoke(this, Status.CurrentUnitSegments[i + 1]); } } } @@ -748,6 +445,7 @@ namespace Tango.Integration.Operation } } + //Set Segment Completion for All Segments List for (int i = 0; i < Status.Segments.Count; i++) { @@ -803,60 +501,12 @@ namespace Tango.Integration.Operation Status.CurrentUnitTotalProgress = last_Segment.Length; Status.CurrentUnitProgress = 0; Status.ProgressWithoutFinalization = Status.TotalProgressWithoutFinalization; - RaiseFinalizing(); + Finalizing?.Invoke(this, new EventArgs()); } - Status.CurrentUnitProgress = s.Progress - Job.LengthIncludingNumberOfUnits; - Status.FinalizingProgress = s.Progress - Status.TotalProgressWithoutFinalization; - } - } - - #endregion - - #region Protected Methods - - protected void RaiseStatusChanged() - { - StatusChanged?.Invoke(this, Status); - } - - protected void RaiseSegmentStarted(Segment segment) - { - if (segment.IsInterSegment) - { - LogManager.Log($"Inter Segment started."); - } - else - { - LogManager.Log($"Segment {segment.SegmentIndex} of unit {Status.CurrentUnit + 1} started..."); - } - - SegmentStarted?.Invoke(this, segment); - } - - protected void RaiseSegmentCompleted(Segment segment) - { - if (segment.IsInterSegment) - { - LogManager.Log($"Inter Segment completed."); + Status.CurrentUnitProgress += delta; + Status.FinalizingProgress += delta; } - else - { - LogManager.Log($"Segment {segment.SegmentIndex} of unit {Status.CurrentUnit + 1} completed."); - } - SegmentCompleted?.Invoke(this, segment); - } - - protected void RaiseUnitCompleted(int unit) - { - LogManager.Log($"Unit {unit + 1} completed..."); - UnitCompleted?.Invoke(this, unit); - } - - protected void RaiseFinalizing() - { - LogManager.Log($"Finalizing..."); - Finalizing?.Invoke(this, new EventArgs()); } #endregion diff --git a/Software/Visual_Studio/Tango.Integration/Operation/JobLiquidQuantityCalculationMode.cs b/Software/Visual_Studio/Tango.Integration/Operation/JobLiquidQuantityCalculationMode.cs deleted file mode 100644 index 0c2cc1bb3..000000000 --- a/Software/Visual_Studio/Tango.Integration/Operation/JobLiquidQuantityCalculationMode.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Tango.Integration.Operation -{ - /// <summary> - /// Represents a machine operator liquid quantity calculation mode which will determine the amount of liquid spent when job has stopped. - /// </summary> - public enum JobLiquidQuantityCalculationMode - { - /// <summary> - /// Calculates the liquid quantities using the <see cref="PMR.MachineStatus.MachineStatus.IDSPacksLevels"/> before and after job run. - /// </summary> - MachineStatus, - /// <summary> - /// Calculates the liquid quantities using the job details, stop position and an integral. - /// </summary> - Integral - } -} diff --git a/Software/Visual_Studio/Tango.Integration/Operation/MachineOperator.cs b/Software/Visual_Studio/Tango.Integration/Operation/MachineOperator.cs index bce386bfe..180db3b1d 100644 --- a/Software/Visual_Studio/Tango.Integration/Operation/MachineOperator.cs +++ b/Software/Visual_Studio/Tango.Integration/Operation/MachineOperator.cs @@ -40,11 +40,6 @@ using Tango.Integration.Emergency; using Tango.PMR.MachineStatus; using Newtonsoft.Json; using Tango.PMR.Integration; -using System.Globalization; -using Tango.PMR.Power; -using Tango.PMR.ThreadLoading; -using Tango.BL.DTO; -using Tango.PMR.IFS; namespace Tango.Integration.Operation { @@ -58,39 +53,17 @@ namespace Tango.Integration.Operation public const String FIRMWARE_UPGRADE_FOLDER_NAME = "UpgradePackage"; public const String FIRMWARE_UPGRADE_CONFIG_FILE_NAME = "package.cfg"; public const String JOB_DESCRIPTION_FILE_NAME = "job_segments.jdf"; - public const int MAX_DISPENSER_NANOLITER = 130000000; - public const double MAX_MIDTANK_LITERS = 1.8; - public const double EMPTY_MIDTANK_LITERS = 0.2; - public const double LOW_MIDTANK_LITERS = 0.3; - public const double OVERALL_TEMPERATURE_OK = 35; - public const double OVERALL_TEMPERATURE_WARNING = 35; - public const double OVERALL_TEMPERATURE_ERROR = 40; private bool _diagnosticsSent; private bool _eventsSent; private bool _debugSent; private bool _machineStatusSent; - private bool _inkFillingStatusSent; - private bool _threadLoadingSent; + private EmbeddedLogItem _last_embedded_debug_log; private static RunningJobStatus _last_job_status; - private bool _isPowerDownRequestInProgress; - private bool _isHeadCleaningInProgress; - private List<BL.ValueObjects.JobRunLiquidQuantity> _lastJobLiquidQuantities; - private DateTime _diagnosticsTime; - private MachineStatus _machineStatusBeforeJobStart; - private Configuration _machineConfiguration; - - private DateTime _jobStartDate; - private DateTime? _jobUploadingStartDate; - private DateTime? _jobHeatingStartDate; - private DateTime? _jobActualStartDate; - private List<Event> _emulatedEvents; public static String EmbeddedLogsFolder { get; private set; } public static String EmbeddedLogsTag { get; private set; } - public static SessionFileLogger SessionLogger { get; set; } - public static String CachedJobOperationFile { get; set; } #region Constructors @@ -109,15 +82,6 @@ namespace Tango.Integration.Operation FileLogger fileLogger = new FileLogger(EmbeddedLogsFolder, EmbeddedLogsTag) { Enabled = true }; EmbeddedLogManager.RegisterLogger(fileLogger); } - - if (SessionLogger == null) - { - SessionLogger = new SessionFileLogger(); - LogManager.Default.RegisterLogger(SessionLogger); - } - - - CachedJobOperationFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Twine", "Tango", "Job Resume", Path.GetFileNameWithoutExtension(AppDomain.CurrentDomain.FriendlyName), "CachedJobOperation.cache"); } /// <summary> @@ -125,15 +89,12 @@ namespace Tango.Integration.Operation /// </summary> public MachineOperator() : base() { - _emulatedEvents = new List<Event>(); - ComponentName = $"Machine Operator {_component_counter++}"; DeviceInformation = new DeviceInformation(); MachineEventsStateProvider = new DefaultMachineEventsStateProvider(); JobRunsLogger = new BasicJobRunsLogger(this); JobRunsLogger.Start(); EnableEventsNotification = true; EnableMachineStatusUpdates = true; - EnableInkFillingStatus = true; EnableJobResume = true; LogEmbeddedDebuggingToFile = true; FirmwareUpgradeMode = FirmwareUpgradeModes.DFU | FirmwareUpgradeModes.TFP_PACKAGE; @@ -141,8 +102,6 @@ namespace Tango.Integration.Operation EmergencyNotificationProvider = new UsbEmergencyNotificationProvider("COM1"); EnableJobLiquidQuantityValidation = true; FailsWithAdapter = true; - ContinuousRequestTimeout = TimeSpan.FromSeconds(2); - ResetInkFllingStatus(); } /// <summary> @@ -189,6 +148,26 @@ namespace Tango.Integration.Operation public event EventHandler<CartridgeValidationEventArgs> CartridgeValidationRequestReceived; /// <summary> + /// Occurs when a request has been sent. + /// </summary> + public event EventHandler<IMessage> RequestSent; + + /// <summary> + /// Occurs when a response has been sent. + /// </summary> + public event EventHandler<IMessage> ResponseSent; + + /// <summary> + /// Occurs when a request has timed out. + /// </summary> + public event EventHandler<RequestFailedEventArgs> RequestFailed; + + /// <summary> + /// Occurs when a request response has been received. + /// </summary> + public event EventHandler<IMessage> ResponseReceived; + + /// <summary> /// Reports about the job printing preparation progress. /// </summary> public event EventHandler<PreparingJobProgressEventArgs> PreparingJobProgress; @@ -223,89 +202,11 @@ namespace Tango.Integration.Operation /// </summary> public event EventHandler<ResumingJobEventArgs> ResumingJob; - /// <summary> - /// Occurs when the machine was connected and device has reported IsAfterReset. - /// </summary> - public event EventHandler FirmwareStarted; - - /// <summary> - /// Occurs when power down has started. - /// </summary> - public event EventHandler<PowerDownStartedEventArgs> PowerDownStarted; - - /// <summary> - /// Occurs when the thread loading status has changed. - /// </summary> - public event EventHandler<StartThreadLoadingResponse> ThreadLoadingStatusChanged; - - /// <summary> - /// Occurs when a thread loading confirmation is required. - /// </summary> - public event EventHandler<ThreadLoadingConfirmationRequiredEventArgs> ThreadLoadingConfirmationRequired; - - /// <summary> - /// Occurs when thread loading has completed. - /// </summary> - public event EventHandler<StartThreadLoadingResponse> ThreadLoadingCompleted; - - /// <summary> - /// Occurs when thread loading has failed. - /// </summary> - public event EventHandler<StartThreadLoadingResponse> ThreadLoadingFailed; - - /// <summary> - /// Occurs when the power up sequence has started. - /// </summary> - public event EventHandler<StartPowerUpResponse> PowerUpStarted; - - /// <summary> - /// Occurs when the power up sequence progress has changed. - /// </summary> - public event EventHandler<StartPowerUpResponse> PowerUpProgress; - - /// <summary> - /// Occurs when power up sequence has completed successfully. - /// </summary> - public event EventHandler<StartPowerUpResponse> PowerUpCompleted; - - /// <summary> - /// Occurs when power up sequence has failed. - /// </summary> - public event EventHandler<StartPowerUpResponse> PowerUpFailed; - - /// <summary> - /// Occurs when power up sequence has ended. Could be due to no response to the request! - /// </summary> - public event EventHandler PowerUpEnded; - - /// <summary> - /// Occurs when a head cleaning job has ended. - /// </summary> - public event EventHandler<HeadCleaningEndedEventArgs> HeadCleaningEnded; - - /// <summary> - /// Occurs when the ink filling status has changed. - /// </summary> - public event EventHandler<InkFillingStatusChangedEventArgs> InkFillingStatusChanged; - #endregion #region Properties /// <summary> - /// Gets or sets a value indicating whether to create a new designated session log file each successful connection. - /// This log file will contain standard logs that have occurred between the last connection and disconnection states. - /// </summary> - public static bool EnableSessionLogFile - { - get { return SessionLogger.Enabled; } - set - { - SessionLogger.Enabled = value; - } - } - - /// <summary> /// Gets or sets the job handling mode. /// </summary> public JobHandlerModes JobHandlingMode { get; set; } @@ -320,11 +221,6 @@ namespace Tango.Integration.Operation /// </summary> public JobUnitsMethods JobUnitsMethod { get; set; } - /// <summary> - /// Gets or sets the way of calculating how much liquid was spent during the job. - /// </summary> - public JobLiquidQuantityCalculationMode JobLiquidQuantityCalculationMode { get; set; } - private MachineStatuses _status; /// <summary> /// Gets the current machine status. @@ -341,20 +237,11 @@ namespace Tango.Integration.Operation OnStatusChanged(value); RaisePropertyChanged(nameof(IsPrinting)); RaisePropertyChanged(nameof(CanPrint)); - RaisePropertyChanged(nameof(IsConnected)); LogManager.Log("Machine operator status changed: " + _status); } } } - /// <summary> - /// Gets a value indicating whether the machine is connected and status is not disconnected. - /// </summary> - public bool IsConnected - { - get { return State == TransportComponentState.Connected && Status != MachineStatuses.Disconnected; } - } - private MachineStatus _machineStatus; /// <summary> /// Gets the machine embedded device status. @@ -362,27 +249,7 @@ namespace Tango.Integration.Operation public MachineStatus MachineStatus { get { return _machineStatus; } - private set { _machineStatus = value; RaisePropertyChangedAuto(); } - } - - private InkFillingStatus _inkFillingStatus; - /// <summary> - /// Gets or sets the ink filling status. - /// </summary> - public InkFillingStatus InkFillingStatus - { - get { return _inkFillingStatus; } - private set { _inkFillingStatus = value; RaisePropertyChangedAuto(); } - } - - private StartThreadLoadingResponse _threadLoadingStatus; - /// <summary> - /// Gets the current thread loading status. - /// </summary> - public StartThreadLoadingResponse ThreadLoadingStatus - { - get { return _threadLoadingStatus; } - private set { _threadLoadingStatus = value; RaisePropertyChangedAuto(); } + set { _machineStatus = value; RaisePropertyChangedAuto(); } } /// <summary> @@ -414,7 +281,7 @@ namespace Tango.Integration.Operation { get { - return Status == MachineStatuses.ReadyToDye || Status == MachineStatuses.PowerUp || Status == MachineStatuses.Standby; + return Status == MachineStatuses.ReadyToDye; } } @@ -520,36 +387,6 @@ namespace Tango.Integration.Operation } } - private bool _enableInkFillingStatus; - public bool EnableInkFillingStatus - { - get { return _enableInkFillingStatus; } - set - { - if (_enableInkFillingStatus != value) - { - _enableInkFillingStatus = value; - RaisePropertyChangedAuto(); - OnEnableInkFillingStatus(value); - } - } - } - - private bool _enableAutomaticThreadLoading; - /// <summary> - /// Gets or sets a value indicating whether to enable automatic thread loading support. - /// </summary> - public bool EnableAutomaticThreadLoading - { - get { return _enableAutomaticThreadLoading; } - set - { - _enableAutomaticThreadLoading = value; - RaisePropertyChangedAuto(); - OnEnableAutomaticThreadLoadingChanged(value); - } - } - private bool _enableJobResume; /// <summary> /// Gets or sets a value indicating whether to check whether a job is in progress after connection was successful. @@ -579,16 +416,6 @@ namespace Tango.Integration.Operation } } - private bool _enablePowerUpSequence; - /// <summary> - /// Gets or sets a value indicating whether to enable the power sequence tracking. - /// </summary> - public bool EnablePowerUpSequence - { - get { return _enablePowerUpSequence; } - set { _enablePowerUpSequence = value; RaisePropertyChangedAuto(); } - } - /// <summary> /// Gets or sets the machine events state provider used to get notifications about current machine events and errors. /// </summary> @@ -634,11 +461,6 @@ namespace Tango.Integration.Operation /// </summary> public IEmergencyNotificationProvider EmergencyNotificationProvider { get; set; } - /// <summary> - /// Gets or sets the general continuous request timeout. - /// </summary> - public TimeSpan ContinuousRequestTimeout { get; set; } - #endregion #region Virtual Methods @@ -656,34 +478,33 @@ namespace Tango.Integration.Operation bool responseLogged = false; _diagnosticsSent = true; - LogManager.Log($"Sending '{nameof(StartDiagnosticsRequest)}'..."); - - SendContinuousRequest<StartDiagnosticsRequest, StartDiagnosticsResponse>(request, new TransportContinuousRequestConfig() { ShouldLog = false }).ObserveOn(new NewThreadScheduler()).Subscribe( + SendContinuousRequest<StartDiagnosticsRequest, StartDiagnosticsResponse>(request).ObserveOn(new NewThreadScheduler()).Subscribe( (response) => { + OnDiagnosticsDataAvailable(response); + if (!responseLogged) { - _diagnosticsTime = DateTime.Now; + LogResponseReceived(response.Message); responseLogged = true; } - else - { - _diagnosticsTime = _diagnosticsTime.Add(TimeSpan.FromMilliseconds(response.Message.ElapsedMilli)); - } - - response.Message.DateTime = _diagnosticsTime.ToString("MM/dd/yyyy HH:mm:ss.fff"); - - OnDiagnosticsDataAvailable(response); }, (ex) => { _diagnosticsSent = false; + + if (!(ex is ContinuousResponseAbortedException)) + { + LogRequestFailed(request, ex); + } }, () => { _diagnosticsSent = false; LogManager.Log("Diagnostics response completed!?", LogCategory.Warning); }); + + LogRequestSent(request); } else if (_diagnosticsSent) { @@ -695,9 +516,14 @@ namespace Tango.Integration.Operation try { - var res = await SendRequest<StopDiagnosticsRequest, StopDiagnosticsResponse>(req, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(req); + var res = await SendRequest<StopDiagnosticsRequest, StopDiagnosticsResponse>(req); + LogResponseReceived(res.Message); + } + catch (Exception ex) + { + LogRequestFailed(req, ex); } - catch { } } } } @@ -715,25 +541,33 @@ namespace Tango.Integration.Operation bool responseLogged = false; _eventsSent = true; - SendContinuousRequest<StartEventsNotificationRequest, StartEventsNotificationResponse>(request, new TransportContinuousRequestConfig() { ShouldLog = true }).ObserveOn(new NewThreadScheduler()).Subscribe( + SendContinuousRequest<StartEventsNotificationRequest, StartEventsNotificationResponse>(request).ObserveOn(new NewThreadScheduler()).Subscribe( (response) => { OnEventsNotification(response); if (!responseLogged) { + LogResponseReceived(response.Message); responseLogged = true; } }, (ex) => { _eventsSent = false; + + if (!(ex is ContinuousResponseAbortedException)) + { + LogRequestFailed(request, ex); + } }, () => { _eventsSent = false; LogManager.Log("Events Notification response completed!?", LogCategory.Warning); }); + + LogRequestSent(request); } else if (_eventsSent) { @@ -745,9 +579,14 @@ namespace Tango.Integration.Operation try { - var res = await SendRequest<StopEventsNotificationRequest, StopEventsNotificationResponse>(req, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(req); + var res = await SendRequest<StopEventsNotificationRequest, StopEventsNotificationResponse>(req); + LogResponseReceived(res.Message); + } + catch (Exception ex) + { + LogRequestFailed(req, ex); } - catch { } } } } @@ -765,13 +604,14 @@ namespace Tango.Integration.Operation bool responseLogged = false; _debugSent = true; - SendContinuousRequest<StartDebugLogRequest, StartDebugLogResponse>(request, new TransportContinuousRequestConfig() { ShouldLog = true }).ObserveOn(new NewThreadScheduler()) + SendContinuousRequest<StartDebugLogRequest, StartDebugLogResponse>(request).ObserveOn(new NewThreadScheduler()) .Subscribe ( (response) => { if (!responseLogged) { + LogResponseReceived(response.Message); responseLogged = true; } @@ -780,11 +620,18 @@ namespace Tango.Integration.Operation (ex) => { _debugSent = false; + + if (!(ex is ContinuousResponseAbortedException)) + { + LogRequestFailed(request, ex); + } }, () => { _debugSent = false; }); + + LogRequestSent(request); } else if (_debugSent) { @@ -796,9 +643,14 @@ namespace Tango.Integration.Operation try { - var res = await SendRequest<StopDebugLogRequest, StopDebugLogResponse>(req, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(req); + var res = await SendRequest<StopDebugLogRequest, StopDebugLogResponse>(req); + LogResponseReceived(res.Message); + } + catch (Exception ex) + { + LogRequestFailed(req, ex); } - catch { } } } } @@ -816,25 +668,33 @@ namespace Tango.Integration.Operation bool responseLogged = false; _machineStatusSent = true; - SendContinuousRequest<StartMachineStatusUpdateRequest, StartMachineStatusUpdateResponse>(request, new TransportContinuousRequestConfig() { ShouldLog = true }).ObserveOn(new NewThreadScheduler()).Subscribe( + SendContinuousRequest<StartMachineStatusUpdateRequest, StartMachineStatusUpdateResponse>(request).ObserveOn(new NewThreadScheduler()).Subscribe( (response) => { OnMachineStatusChanged(response); if (!responseLogged) { + LogResponseReceived(response.Message); responseLogged = true; } }, (ex) => { _machineStatusSent = false; + + if (!(ex is ContinuousResponseAbortedException)) + { + LogRequestFailed(request, ex); + } }, () => { _machineStatusSent = false; LogManager.Log("Machine status update response completed!?", LogCategory.Warning); }); + + LogRequestSent(request); } else if (_machineStatusSent) { @@ -846,98 +706,14 @@ namespace Tango.Integration.Operation try { - var res = await SendRequest<StopMachineStatusUpdateRequest, StopMachineStatusUpdateResponse>(req, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(req); + var res = await SendRequest<StopMachineStatusUpdateRequest, StopMachineStatusUpdateResponse>(req); + LogResponseReceived(res.Message); } - catch { } - } - } - } - - /// <summary> - /// Called when the enable ink filling status has been changed. - /// </summary> - /// <param name="value">if set to <c>true</c> [value].</param> - protected virtual void OnEnableInkFillingStatus(bool value) - { - if (value && State == TransportComponentState.Connected && !_inkFillingStatusSent) - { - var request = new StartInkFillingStatusRequest(); - - bool responseLogged = false; - _inkFillingStatusSent = true; - - SendContinuousRequest<StartInkFillingStatusRequest, StartInkFillingStatusResponse>(request, new TransportContinuousRequestConfig() { ShouldLog = true }).ObserveOn(new NewThreadScheduler()).Subscribe( - (response) => - { - OnInkFillingStatusChanged(response); - - if (!responseLogged) - { - responseLogged = true; - } - }, - (ex) => - { - _inkFillingStatusSent = false; - }, - () => - { - _inkFillingStatusSent = false; - LogManager.Log("Ink filling status response completed!?", LogCategory.Warning); - }); - } - else if (_inkFillingStatusSent) - { - _inkFillingStatusSent = false; - } - } - - /// <summary> - /// Called when the enable automatic thread loading has been changed - /// </summary> - /// <param name="value">if set to <c>true</c> [value].</param> - protected virtual async void OnEnableAutomaticThreadLoadingChanged(bool value) - { - if (value && State == TransportComponentState.Connected && !_threadLoadingSent) - { - var request = new StartThreadLoadingRequest(); - - bool responseLogged = false; - _threadLoadingSent = true; - - SendContinuousRequest<StartThreadLoadingRequest, StartThreadLoadingResponse>(request, new TransportContinuousRequestConfig() { ShouldLog = true }).ObserveOn(new NewThreadScheduler()).Subscribe( - (response) => - { - OnThreadLoadingStatusChanged(response); - - if (!responseLogged) - { - responseLogged = true; - } - }, - (ex) => - { - _threadLoadingSent = false; - }, - () => - { - _threadLoadingSent = false; - LogManager.Log("Thread loading response completed!?", LogCategory.Warning); - }); - } - else if (_threadLoadingSent) - { - _threadLoadingSent = false; - - if (State == TransportComponentState.Connected) - { - var req = new StopThreadLoadingRequest(); - - try + catch (Exception ex) { - var res = await SendRequest<StopThreadLoadingRequest, StopThreadLoadingResponse>(req, new TransportRequestConfig() { ShouldLog = true }); + LogRequestFailed(req, ex); } - catch { } } } } @@ -959,17 +735,7 @@ namespace Tango.Integration.Operation { if (MachineEventsStateProvider != null) { - var events = response.Events; - - foreach (var emulated in _emulatedEvents) - { - if (!events.Any(x => x.Type == emulated.Type)) - { - events.Add(emulated); - } - } - - MachineEventsStateProvider.ApplyEvents(events); + MachineEventsStateProvider.ApplyEvents(response.Events); } EventsNotification?.Invoke(this, response); @@ -981,16 +747,30 @@ namespace Tango.Integration.Operation /// <param name="data">The sensors data.</param> protected virtual void OnDebugLogAvailable(StartDebugLogResponse data) { - if (LogEmbeddedDebuggingToFile && EmbeddedLogManager != null) + if (_last_embedded_debug_log == null || _last_embedded_debug_log.DebugLogResponse.Message != data.Message) { - EmbeddedLogManager.Log(new EmbeddedLogItem(data)); + _last_embedded_debug_log = new EmbeddedLogItem(data); + + if (LogEmbeddedDebuggingToFile && EmbeddedLogManager != null) + { + EmbeddedLogManager.Log(_last_embedded_debug_log); + } + + DebugLogAvailable?.Invoke(this, data); } + else + { + _last_embedded_debug_log.Repeated++; - DebugLogAvailable?.Invoke(this, data); + if (LogEmbeddedDebuggingToFile && EmbeddedLogManager != null) + { + EmbeddedLogManager.Log(new EmbeddedLogItem(data)); + } + } } /// <summary> - /// Called when the machine status has been updated. + /// Called when the machine status has been update /// </summary> /// <param name="response">The response.</param> protected virtual void OnMachineStatusChanged(StartMachineStatusUpdateResponse response) @@ -1004,188 +784,87 @@ namespace Tango.Integration.Operation if (changed) { - OnMachineStateChanged(MachineStatus.State); - } - } - - /// <summary> - /// Called when ink filling status has been changed. - /// </summary> - /// <param name="response">The response.</param> - protected virtual void OnInkFillingStatusChanged(StartInkFillingStatusResponse response) - { - if (response.Status == null || response.Status.CartridgesStatuses == null || response.Status.CartridgesStatuses.Count == 0) return; + LogManager.Log($"Machine State Changed: {MachineStatus.State}."); - int index = -1; - bool raiseChange = false; - - foreach (var remoteCartridge in response.Status.CartridgesStatuses) - { - index++; - - if (remoteCartridge.Cartridge == null) - { - LogManager.Log($"Remote cartridge arrived with null cartridge at position [{index}] and will be ignored.", LogCategory.Error); - continue; - } - - var localCartridge = InkFillingStatus.CartridgesStatuses.SingleOrDefault(x => x.Cartridge.Index == remoteCartridge.Cartridge.Index && x.Cartridge.Slot == remoteCartridge.Cartridge.Slot); - - if (localCartridge != null) + switch (MachineStatus.State) { - if (localCartridge.State != remoteCartridge.State) - { - localCartridge.State = remoteCartridge.State; - LogManager.Log($"{localCartridge.Cartridge.Slot} Cartridge '{localCartridge.Cartridge.Index}' state changed: '{localCartridge.State}' => '{remoteCartridge.State}'."); - } - - if (remoteCartridge.Cartridge.Tag != null) - { - LogManager.Log($"{localCartridge.Cartridge.Slot} Cartridge '{localCartridge.Cartridge.Index}' Tag arrived:\n{remoteCartridge.Cartridge.Tag.ToJsonString()}"); - } - - localCartridge.Message = remoteCartridge.Message; - localCartridge.ProgressPercentage = remoteCartridge.ProgressPercentage; - - raiseChange = true; - } - else - { - LogManager.Log($"Could not locate local cartridge with slot '{remoteCartridge.Cartridge.Slot}' and index '{remoteCartridge.Cartridge.Index}'.", LogCategory.Error); + case MachineState.Initializing: + Status = MachineStatuses.Service; + break; + //case MachineState.PreparingJob: + // Status = MachineStatuses.GettingReady; + // break; + case MachineState.Ready: + Status = MachineStatuses.ReadyToDye; + break; + //case MachineState.Sleep: + // Status = MachineStatuses.Standby; + // break; + case MachineState.PowerOff: + Status = MachineStatuses.ShuttingDown; + break; + case MachineState.Error: + Status = MachineStatuses.Error; + break; } } - - if (raiseChange) - { - RaisePropertyChanged(nameof(InkFillingStatus)); - InkFillingStatusChanged?.Invoke(this, new InkFillingStatusChangedEventArgs() { Status = InkFillingStatus }); - } } /// <summary> - /// Called when the machine state has been changed. + /// Called when the request has been sent /// </summary> - /// <param name="state">The state.</param> - protected async virtual void OnMachineStateChanged(MachineState state) + /// <param name="response">The request.</param> + protected virtual void OnRequestSent(IMessage request) { - LogManager.Log($"Machine State Changed: {state}."); - - if (IsPrinting) - { - LogManager.Log($"Machine state change will not affect the machine operator status as it is now in a '{Status}' status.", LogCategory.Warning); - return; - } - - switch (state) - { - case MachineState.PowerUp: - Status = MachineStatuses.PowerUp; - break; - //case MachineState.PreparingJob: - // Status = MachineStatuses.GettingReady; - // break; - case MachineState.Ready: - Status = MachineStatuses.ReadyToDye; - break; - case MachineState.Sleep: - Status = MachineStatuses.Standby; - break; - case MachineState.PowerOff: - Status = MachineStatuses.ShuttingDown; - if (!_isPowerDownRequestInProgress) - { - try - { - await PowerDown(); - } - catch { } - } - break; - case MachineState.Error: - //Status = MachineStatuses.Error; - break; - } + RequestSent?.Invoke(this, request); } /// <summary> - /// Called when the thread loading status has been changed. + /// Called when the response has been received /// </summary> /// <param name="response">The response.</param> - protected virtual void OnThreadLoadingStatusChanged(StartThreadLoadingResponse response) + protected virtual void OnResponseReceived(IMessage response) { - bool changed = (ThreadLoadingStatus == null || response.State != ThreadLoadingStatus.State || response.ErrorReason != ThreadLoadingStatus.ErrorReason); - - if (changed) - { - ThreadLoadingStatus = response; - ThreadLoadingStatusChanged?.Invoke(this, response); - - LogManager.Log($"Thread Loading Status Changed: {ThreadLoadingStatus.State}."); - - switch (ThreadLoadingStatus.State) - { - case ThreadLoadingState.ReadyForLoading: - - LogManager.Log("Thread loading is ready for loading. Invoking confirmation event..."); - - ThreadLoadingConfirmationRequired?.Invoke(this, new ThreadLoadingConfirmationRequiredEventArgs((processTable) => - { - //Confirm Action - try - { - var process = processTable.ToProcessParametersPMR(); - LogManager.Log($"Thread loading confirmation received with process parameters:\n{process.ToJsonString()}"); - LogManager.Log("Sending continue thread loading request..."); - var r = SendRequest<ContinueThreadLoadingRequest, ContinueThreadLoadingResponse>(new ContinueThreadLoadingRequest() - { - ProcessParameters = process, - }, new TransportRequestConfig() { ShouldLog = true }).Result; - } - catch (Exception ex) - { - LogManager.Log(ex, "Error confirming thread loading sequence."); - } - }) - { - Status = ThreadLoadingStatus, - }); - break; - case ThreadLoadingState.Completed: - ThreadLoadingCompleted?.Invoke(this, ThreadLoadingStatus); - break; - case ThreadLoadingState.FinalizationError: - case ThreadLoadingState.PreparationError: - ThreadLoadingFailed?.Invoke(this, ThreadLoadingStatus); - break; - } - } + ResponseReceived?.Invoke(this, response); } /// <summary> /// Called when a new request has been received. /// </summary> /// <param name="container">The request.</param> - protected override void OnRequestReceived(RequestReceivedEventArgs e) + protected override void OnRequestReceived(MessageContainer container) { - base.OnRequestReceived(e); - - if (e.Handled) return; - - var container = e.Container; + base.OnRequestReceived(container); if (container.Type == MessageType.CartridgeValidationRequest) { - e.Handled = true; OnCartridgeValidationRequestReceived(container.Token, MessageFactory.ExtractMessageFromContainer<CartridgeValidationRequest>(container)); } else if (container.Type == MessageType.UpdateStatusRequest) { - e.Handled = true; OnUpdateStatusRequestReceived(container.Token, MessageFactory.ExtractMessageFromContainer<UpdateStatusRequest>(container)); } } /// <summary> + /// Called when the response has been sent + /// </summary> + /// <param name="response">The response.</param> + protected virtual void OnResponseSent(IMessage response) + { + ResponseSent?.Invoke(this, response); + } + + /// <summary> + /// Called when the request has been failed + /// </summary> + /// <param name="request">The request.</param> + protected virtual void OnRequestFailed(IMessage request, Exception exception) + { + RequestFailed?.Invoke(this, new RequestFailedEventArgs(request, exception)); + } + + /// <summary> /// Called when the machine status has been changed /// </summary> /// <param name="status">The status.</param> @@ -1241,115 +920,7 @@ namespace Tango.Integration.Operation LogManager.Log(ex); } - try - { - SendResponse<UpdateStatusResponse>(new UpdateStatusResponse(), token); - } - catch (Exception ex) - { - LogManager.Log(ex, "Error sending UpdateStatus response."); - } - } - - /// <summary> - /// Called when the printing has been started. - /// </summary> - /// <param name="handler">The handler.</param> - /// <param name="job">The job.</param> - protected virtual void OnPrintingStarted(JobHandler handler, Job job, bool isResumed = false) - { - PrintingStarted?.Invoke(this, new PrintingEventArgs(handler, job) - { - StartDate = _jobStartDate, - IsResumed = isResumed - }); - } - - /// <summary> - /// Called when the printing has been completed. - /// </summary> - /// <param name="handler">The handler.</param> - /// <param name="job">The job.</param> - protected virtual void OnPrintingCompleted(JobHandler handler, Job job) - { - PrintingCompleted?.Invoke(this, new PrintingEventArgs(handler, job) - { - LiquidQuantities = _lastJobLiquidQuantities.ToList(), - StartDate = _jobStartDate, - UploadingStartTime = _jobUploadingStartDate, - HeatingStartTime = _jobHeatingStartDate, - ActualStartTime = _jobActualStartDate, - }); - - OnPrintingEnded(handler, job); - } - - /// <summary> - /// Called when the printing has been failed. - /// </summary> - /// <param name="handler">The handler.</param> - /// <param name="job">The job.</param> - /// <param name="exception">The exception.</param> - protected virtual void OnPrintingFailed(JobHandler handler, Job job, Exception exception) - { - PrintingFailed?.Invoke(this, new PrintingFailedEventArgs(handler, job, exception) - { - LiquidQuantities = _lastJobLiquidQuantities.ToList(), - StartDate = _jobStartDate, - UploadingStartTime = _jobUploadingStartDate, - HeatingStartTime = _jobHeatingStartDate, - ActualStartTime = _jobActualStartDate, - }); - OnPrintingEnded(handler, job); - } - - /// <summary> - /// Called when the printing has been aborted. - /// </summary> - /// <param name="handler">The handler.</param> - /// <param name="job">The job.</param> - protected virtual void OnPrintingAborted(JobHandler handler, Job job) - { - PrintingAborted?.Invoke(this, new PrintingEventArgs(handler, job) - { - LiquidQuantities = _lastJobLiquidQuantities.ToList(), - StartDate = _jobStartDate, - UploadingStartTime = _jobUploadingStartDate, - HeatingStartTime = _jobHeatingStartDate, - ActualStartTime = _jobActualStartDate, - }); - OnPrintingEnded(handler, job); - } - - /// <summary> - /// Called when the printing has been ended. - /// </summary> - /// <param name="handler">The handler.</param> - /// <param name="job">The job.</param> - protected virtual void OnPrintingEnded(JobHandler handler, Job job) - { - PrintingEnded?.Invoke(this, new PrintingEventArgs(handler, job) - { - LiquidQuantities = _lastJobLiquidQuantities.ToList(), - StartDate = _jobStartDate, - UploadingStartTime = _jobUploadingStartDate, - HeatingStartTime = _jobHeatingStartDate, - ActualStartTime = _jobActualStartDate, - }); - } - - protected virtual void OnHeadCleaningEnded(HeadCleaningHandler handler, JobRunStatus status) - { - SaveLastJobLiquidQuantities(null, null, null, null); - - HeadCleaningEnded?.Invoke(this, new HeadCleaningEndedEventArgs() - { - StartDate = _jobStartDate, - Length = handler.Status.Total, - EndPosition = handler.Status.Progress, - Status = status, - LiquidQuantities = _lastJobLiquidQuantities.ToList(), - }); + SendResponse<UpdateStatusResponse>(new UpdateStatusResponse()); } #endregion @@ -1370,23 +941,7 @@ namespace Tango.Integration.Operation _debugSent = false; _eventsSent = false; _machineStatusSent = false; - - if (Status != MachineStatuses.Disconnected) - { - Status = MachineStatuses.Disconnected; - ResetEvents(); - ResetInkFllingStatus(); - } - } - } - - private void ResetEvents() - { - if (MachineEventsStateProvider != null) - { - LogManager.Log("Resetting active events..."); - _emulatedEvents.Clear(); - MachineEventsStateProvider.Reset(); + Status = MachineStatuses.Disconnected; } } @@ -1398,30 +953,28 @@ namespace Tango.Integration.Operation { if (Status == MachineStatuses.Upgrading) return; - Status = MachineStatuses.Disconnected; - - if (MachineStatus != null) - { - MachineStatus.State = MachineState.Ready; - } - - SessionLogger.EndSession(); - if (State == TransportComponentState.Connected) { DisconnectRequest request = new DisconnectRequest(); + LogRequestSent(request); try { - var response = await SendRequest<DisconnectRequest, DisconnectResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + var response = await SendRequest<DisconnectRequest, DisconnectResponse>(request); + LogResponseReceived(response.Message); Status = MachineStatuses.Disconnected; } - catch { } + catch (Exception ex) + { + LogRequestFailed(request, ex); + } } - ResetEvents(); - ResetInkFllingStatus(); + if (MachineEventsStateProvider != null) + { + MachineEventsStateProvider.Reset(); + } await base.Disconnect(); } @@ -1447,14 +1000,12 @@ namespace Tango.Integration.Operation Password = "1234", UnixTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds() }; + LogRequestSent(request); try { - var response = await SendRequest<ConnectRequest, ConnectResponse>(request, new TransportRequestConfig() { ShouldLog = true }); - - SessionLogger.CreateSession(); - - _isPowerDownRequestInProgress = false; + var response = await SendRequest<ConnectRequest, ConnectResponse>(request); + LogResponseReceived(response.Message); if (Status != MachineStatuses.Upgrading) { @@ -1472,27 +1023,15 @@ namespace Tango.Integration.Operation OnEnableEmbeddedDebuggingChanged(EnableEmbeddedDebugging); OnEnableEventsNotification(EnableEventsNotification); OnEnableMachineStatusUpdatesChanged(EnableMachineStatusUpdates); - OnEnableAutomaticThreadLoadingChanged(EnableAutomaticThreadLoading); - OnEnableInkFillingStatus(EnableInkFillingStatus); - - if (EnablePowerUpSequence) - { - TrackPowerUpSequence(); - } if (EnableJobResume) { ResumeJob(); } - - if (response.Message.IsAfterReset) - { - FirmwareStarted?.Invoke(this, new EventArgs()); - } } catch (Exception ex) { - SessionLogger.EndSession(); + LogRequestFailed(request, ex); await base.Disconnect(); throw ex; } @@ -1507,202 +1046,35 @@ namespace Tango.Integration.Operation #region Private Methods - private void ResetInkFllingStatus() - { - if (InkFillingStatus == null) - { - var status = new InkFillingStatus(); - - for (int i = 0; i < 8; i++) - { - status.CartridgesStatuses.Add(new CartridgeStatus() - { - Cartridge = new Cartridge() - { - Index = i, - Slot = CartridgeSlot.Ink, - }, - State = CartridgeState.Absent - }); - } - - status.CartridgesStatuses.Add(new CartridgeStatus() - { - Cartridge = new Cartridge() { Index = 0, Slot = CartridgeSlot.WasteMiddle }, - State = CartridgeState.Absent - }); - - status.CartridgesStatuses.Add(new CartridgeStatus() - { - Cartridge = new Cartridge() { Index = 1, Slot = CartridgeSlot.WasteLower }, - State = CartridgeState.Absent - }); - - InkFillingStatus = status; - } - else - { - foreach (var cartridge in InkFillingStatus.CartridgesStatuses) - { - cartridge.ProgressPercentage = 0; - cartridge.Message = String.Empty; - cartridge.State = CartridgeState.Absent; - } - } - - InkFillingStatusChanged?.Invoke(this, new InkFillingStatusChangedEventArgs() { Status = InkFillingStatus }); - } - - private void SaveCachedJobOperation(Job job) - { - try - { - LogManager.Log("Caching current job operation..."); - CachedJobOperation cache = new CachedJobOperation(); - cache.JobDTO = JobDTO.FromObservable(job); - cache.MachineStatus = MachineStatus; - cache.ProcessParametersDTO = ProcessParametersTableDTO.FromObservable(CurrentProcessParameters); - cache.MachineConfigurationDTO = ConfigurationDTO.FromObservable(job.Machine.Configuration); - var json = JsonConvert.SerializeObject(cache); - Directory.CreateDirectory(Path.GetDirectoryName(CachedJobOperationFile)); - File.WriteAllText(CachedJobOperationFile, json); - } - catch (Exception ex) - { - LogManager.Log(ex, "Error caching job operation for job resume."); - } - } - - private CachedJobOperation LoadCachedJobOperation() - { - try - { - LogManager.Log("Loading last cached job operation..."); - String json = File.ReadAllText(CachedJobOperationFile); - CachedJobOperation cache = JsonConvert.DeserializeObject<CachedJobOperation>(json); - return cache; - } - catch (Exception ex) - { - LogManager.Log(ex, "Error loading cache of last job operation for job resume."); - return null; - } - } - - private void TrackPowerUpSequence() - { - LogManager.Log("Starting power up sequence tracking..."); - - bool started = false; - bool completed = false; - PowerUpState lastState = PowerUpState.None; - - SendContinuousRequest<StartPowerUpRequest, StartPowerUpResponse>(new StartPowerUpRequest(), new TransportContinuousRequestConfig() - { - ShouldLog = true, - Timeout = TimeSpan.FromSeconds(5) - }).Subscribe((response) => - { - if (!started) - { - started = true; - PowerUpStarted?.Invoke(this, response); - } - - PowerUpProgress?.Invoke(this, response); - - var state = response.Message.State; - - if (state != lastState) - { - LogManager.Log($"Power up sequence state changed to '{state}'..."); - - switch (state) - { - case PowerUpState.Error: - completed = true; - LogManager.Log($"Power up sequence failed with state '{state}'. ({response.Message.Message})"); - PowerUpFailed?.Invoke(this, response); - PowerUpEnded?.Invoke(this, new EventArgs()); - break; - case PowerUpState.Cancelled: - completed = true; - LogManager.Log($"Power up sequence canceled with state '{state}'. ({response.Message.Message})"); - PowerUpEnded?.Invoke(this, new EventArgs()); - break; - case PowerUpState.MachineReadyToDye: - completed = true; - LogManager.Log($"Power up sequence completed successfully with state '{state}'. ({response.Message.Message})"); - PowerUpCompleted?.Invoke(this, response); - PowerUpEnded?.Invoke(this, new EventArgs()); - break; - } - - lastState = state; - } - - }, (ex) => - { - if (!completed) - { - completed = true; - LogManager.Log(ex, "Power up sequence tracking failed."); - PowerUpEnded?.Invoke(this, new EventArgs()); - } - }, () => - { - if (!completed) - { - completed = true; - PowerUpEnded?.Invoke(this, new EventArgs()); - } - }); - } - private async void ResumeJob() { LogManager.Log("Checking if a job is in progress..."); try { - var res = await SendRequest<CurrentJobRequest, CurrentJobResponse>(new CurrentJobRequest(), new TransportRequestConfig() { ShouldLog = true }); + var res = await SendRequest<CurrentJobRequest, CurrentJobResponse>(new CurrentJobRequest()); if (res.Message.IsJobInProgress) { - LogManager.Log("Job is in progress. Trying to resume job..."); - CachedJobOperation cache = LoadCachedJobOperation(); - - if (cache == null) - { - LogManager.Log("Cannot resume current job with no cached operation.", LogCategory.Error); - return; - } + JobTicket jobTicket = res.Message.JobTicket; - Job job = null; - Configuration configuration = null; - ProcessParametersTable processParameters = null; + ProcessParametersTable processParameters = new ProcessParametersTable(); + jobTicket.ProcessParameters.MapPrimitivesTo(processParameters); - try - { - processParameters = cache.ProcessParametersDTO.ToObservable(); - job = cache.JobDTO.ToObservable(); - configuration = cache.MachineConfigurationDTO.ToObservable(); - _machineStatusBeforeJobStart = cache.MachineStatus; - CurrentProcessParameters = processParameters; - } - catch (Exception ex) + ResumingJobEventArgs args = new ResumingJobEventArgs((job) => { - LogManager.Log(ex, "Error deserializing cache job operation. Aborting resume."); - return; - } - - JobTicket jobTicket = res.Message.JobTicket; + if (Status != MachineStatuses.ReadyToDye) + { + throw new InvalidOperationException("Could not print while status = " + Status); + } - ResumingJobEventArgs args = new ResumingJobEventArgs(() => - { RunningJob = null; RunningJobStatus = null; + var originalJob = job; + + CurrentProcessParameters = processParameters; + var request = new ResumeCurrentJobRequest(); JobHandler handler = null; @@ -1711,125 +1083,109 @@ namespace Tango.Integration.Operation { try { - if (handler.CanCancel) - { - handler.CanCancel = false; - handler.IsCanceled = true; - LogManager.Log("Aborting current job..."); - var result = await SendRequest<AbortJobRequest, AbortJobResponse>(new AbortJobRequest(), new TransportRequestConfig() { ShouldLog = true }); - SaveLastJobLiquidQuantities(job, configuration, processParameters, handler); - OnPrintingAborted(handler, job); - handler.RaiseCanceled(); - if (Status != MachineStatuses.Disconnected) - { - Status = MachineStatuses.ReadyToDye; - } - } + var result = await SendRequest<AbortJobRequest, AbortJobResponse>(new AbortJobRequest()); + PrintingAborted?.Invoke(this, new PrintingEventArgs(handler, originalJob)); + PrintingEnded?.Invoke(this, new PrintingEventArgs(handler, originalJob)); + handler.RaiseCanceled(); } catch (Exception ex) { - handler.CanCancel = true; LogManager.Log(ex, "Failed to cancel job."); } - }, job, jobTicket, processParameters, JobHandlingMode); + }, originalJob, jobTicket, processParameters, JobHandlingMode); handler.StatusChanged += (x, s) => { RunningJobStatus = s; }; - - _jobStartDate = DateTime.UtcNow; - _jobUploadingStartDate = _jobStartDate; - _jobHeatingStartDate = _jobStartDate; - _jobActualStartDate = null; + LogRequestSent(request); bool responseLogged = false; - bool completed = false; Thread.Sleep(500); //Just wait maybe Shlomo is getting this message to fast after restart ? + bool completed = false; - SendContinuousRequest<ResumeCurrentJobRequest, ResumeCurrentJobResponse>(request, new TransportContinuousRequestConfig() { ContinuousTimeout = ContinuousRequestTimeout, ShouldLog = true }).Subscribe((response) => - { - if (!completed) - { - handler.RaiseStatusReceived(response.Message.Status); - _last_job_status = handler.Status; - - if (response.Message.Status.Progress > 0) - { - if (_jobActualStartDate == null) - { - _jobActualStartDate = DateTime.UtcNow; - } - } - - if (!responseLogged) - { - Status = MachineStatuses.GettingReady; - responseLogged = true; - RunningJob = job; - OnPrintingStarted(handler, job, true); - } - - if (JobHandlingMode == JobHandlerModes.SettingUp) - { - if (response.Message.Status.Progress > CurrentProcessParameters.DryerBufferLengthMeters) - { - if (!completed) - { - Status = MachineStatuses.Printing; - } - } - } - else - { - if (response.Message.Status.Progress > 0) - { - if (!completed) - { - Status = MachineStatuses.Printing; - } - } - } - } - }, (ex) => - { - if (!completed) - { - completed = true; - - if (Status != MachineStatuses.Disconnected) - { - Status = MachineStatuses.ReadyToDye; - } + SendContinuousRequest<ResumeCurrentJobRequest, ResumeCurrentJobResponse>(request, null, TimeSpan.FromSeconds(2)).Subscribe((response) => + { + if (!completed) + { + if (!responseLogged) + { + if (_last_job_status != null) + { + _last_job_status.IsCanceled = false; + _last_job_status.IsCompleted = false; + _last_job_status.IsFailed = false; + handler.Status = _last_job_status; + } + } - if (!handler.IsCanceled) - { - SaveLastJobLiquidQuantities(job, configuration, processParameters, handler); + handler.RaiseStatusReceived(response.Message.Status); - Exception finalException = ex; + if (!responseLogged) + { + Status = MachineStatuses.GettingReady; + responseLogged = true; + RunningJob = originalJob; + PrintingStarted?.Invoke(this, new PrintingEventArgs(handler, originalJob)); + LogResponseReceived(response.Message); + } - if (ex is ContinuousResponseAbortedException continuousException) - { - finalException = new ContinuousResponseAbortedException($"Job aborted by the embedded device ({continuousException.Container.ErrorMessage})."); - } + if (JobHandlingMode == JobHandlerModes.SettingUp) + { + if (response.Message.Status.Progress > processParameters.DryerBufferLengthMeters) + { + if (!completed) + { + Status = MachineStatuses.Printing; + } + } + } + else + { + if (response.Message.Status.Progress > 0) + { + if (!completed) + { + Status = MachineStatuses.Printing; + } + } + } + } + }, (ex) => + { + if (!completed) + { + completed = true; + if (!(ex is ContinuousResponseAbortedException)) + { + Status = MachineStatuses.ReadyToDye; - OnPrintingFailed(handler, job, finalException); - handler.RaiseFailed(finalException); - } - } - }, () => - { - if (!completed) - { - completed = true; - Status = MachineStatuses.ReadyToDye; - SaveLastJobLiquidQuantities(job, configuration, processParameters, handler); - OnPrintingCompleted(handler, job); - handler.RaiseCompleted(); - } - }); + if (!handler.IsCanceled) + { + PrintingFailed?.Invoke(this, new PrintingFailedEventArgs(handler, originalJob, ex)); + PrintingEnded?.Invoke(this, new PrintingEventArgs(handler, originalJob)); + handler.RaiseFailed(ex); + LogRequestFailed(request, ex); + } + } + else + { + Status = MachineStatuses.ReadyToDye; + } + } + }, () => + { + if (!completed) + { + completed = true; + Status = MachineStatuses.ReadyToDye; + PrintingCompleted?.Invoke(this, new PrintingEventArgs(handler, originalJob)); + PrintingEnded?.Invoke(this, new PrintingEventArgs(handler, originalJob)); + handler.RaiseCompleted(); + } + }); return handler; }); @@ -1845,6 +1201,42 @@ namespace Tango.Integration.Operation } /// <summary> + /// Logs the request sent. + /// </summary> + /// <param name="message">The message.</param> + protected void LogRequestSent(IMessage message) + { + if (!(message is FileChunkUploadRequest) && !(message is FileDownloadRequest)) + { + LogManager.Log(String.Format("Sending request '{0}'...{1}{2}", message.GetType().Name, Environment.NewLine, message.ToJsonString())); + OnRequestSent(message); + } + } + + /// <summary> + /// Logs the request failed. + /// </summary> + /// <param name="message">The message.</param> + protected void LogRequestFailed(IMessage message, Exception ex) + { + LogManager.Log(String.Format("Request failed '{0}'...{1}{2}{1}{3}", message.GetType().Name, Environment.NewLine, message.ToJsonString(), ex.ToString()), LogCategory.Error); + OnRequestFailed(message, ex); + } + + /// <summary> + /// Logs the response received. + /// </summary> + /// <param name="message">The message.</param> + protected void LogResponseReceived(IMessage message) + { + if (!(message is FileChunkUploadResponse) && !(message is FileDownloadResponse)) + { + LogManager.Log(String.Format("Response received '{0}'...{1}{2}", message.GetType().Name, Environment.NewLine, message.ToJsonString())); + OnResponseReceived(message); + } + } + + /// <summary> /// Creates a PMR job segment. /// </summary> /// <param name="segment">The segment.</param> @@ -1862,25 +1254,11 @@ namespace Tango.Integration.Operation if (GradientGenerationConfiguration != null && GradientGenerationConfiguration.IsEnabled && segment.BrushStops.Count > 1) { LogManager.Log($"Generate segment {segment.SegmentIndex} gradient..."); - try - { - stops = GradientGenerationConfiguration.Generate(segment, job, processParameters, (e) => - { - PreparingJobProgress?.Invoke(this, e); - }); - } - catch (Exception ex) - { - throw new InvalidOperationException($"Error occurred while trying to generate a gradient.\n{ex.Message}"); - } - LogManager.Log($"Gradient generated."); - - PreparingJobProgress?.Invoke(this, new PreparingJobProgressEventArgs() + stops = GradientGenerationConfiguration.Generate(segment, job, processParameters, (e) => { - Job = job, - Total = job.Segments.Sum(x => x.Length), - Progress = job.Segments.Sum(x => x.Length), + PreparingJobProgress?.Invoke(this, e); }); + LogManager.Log($"Gradient generated."); } foreach (var stop in stops) @@ -1949,11 +1327,12 @@ namespace Tango.Integration.Operation request.JobTicket = ticket; + LogRequestSent(request); bool responseLogged = false; var previous_segments_length = job.Segments.Where(x => x.SegmentIndex < segment.SegmentIndex).Sum(x => x.Length); - SendContinuousRequest<JobRequest, JobResponse>(request, new TransportContinuousRequestConfig() { ContinuousTimeout = ContinuousRequestTimeout, ShouldLog = true }).Subscribe((response) => + SendContinuousRequest<JobRequest, JobResponse>(request, null, TimeSpan.FromSeconds(2)).Subscribe((response) => { response.Message.Status.Progress += previous_segments_length; @@ -1964,7 +1343,8 @@ namespace Tango.Integration.Operation responseLogged = true; Status = MachineStatuses.Printing; RunningJob = handler.Job; - OnPrintingStarted(handler, handler.Job); + PrintingStarted?.Invoke(this, new PrintingEventArgs(handler, handler.Job)); + LogResponseReceived(response.Message); } }, (ex) => @@ -1975,8 +1355,10 @@ namespace Tango.Integration.Operation if (!handler.IsCanceled) { - OnPrintingFailed(handler, handler.Job, ex); + PrintingFailed?.Invoke(this, new PrintingFailedEventArgs(handler, handler.Job, ex)); + PrintingEnded?.Invoke(this, new PrintingEventArgs(handler, handler.Job)); handler.RaiseFailed(ex); + LogRequestFailed(request, ex); } } else @@ -1988,7 +1370,8 @@ namespace Tango.Integration.Operation if (segment == job.OrderedSegments.Last()) { Status = MachineStatuses.ReadyToDye; - OnPrintingCompleted(handler, handler.Job); + PrintingCompleted?.Invoke(this, new PrintingEventArgs(handler, handler.Job)); + PrintingEnded?.Invoke(this, new PrintingEventArgs(handler, handler.Job)); handler.RaiseCompleted(); } else @@ -1998,7 +1381,8 @@ namespace Tango.Integration.Operation ContinueSingleSpoolJob(segment.GetNextSegment(), job, processParameters, handler); }, () => { - OnPrintingAborted(handler, handler.Job); + PrintingAborted?.Invoke(this, new PrintingEventArgs(handler, handler.Job)); + PrintingEnded?.Invoke(this, new PrintingEventArgs(handler, handler.Job)); Status = MachineStatuses.ReadyToDye; handler.RaiseCanceled(); }); @@ -2008,8 +1392,6 @@ namespace Tango.Integration.Operation private void ValidateJobLiquidQuantity(Job job, ProcessParametersTable processParameters, Configuration configuration) { - LogManager.Log("Validating job liquid quantities..."); - Dictionary<int, double> liquidQuantities = new Dictionary<int, double>(); foreach (var pack in configuration.NoneEmptyIdsPacks.OrderBy(x => x.PackIndex)) @@ -2017,8 +1399,6 @@ namespace Tango.Integration.Operation liquidQuantities.Add(pack.PackIndex, 0); } - int resolution = GradientGenerationConfiguration.ResolutionCM; - for (int i = 0; i < Math.Max(job.NumberOfUnits, 1); i++) { for (int segmentIndex = 0; segmentIndex < job.Segments.Count; segmentIndex++) @@ -2026,177 +1406,6 @@ namespace Tango.Integration.Operation var segment = job.Segments[segmentIndex]; var segment_length_cm = segment.Length * 100d; - List<BrushStop> orderedBrushCollection = segment.BrushStops.OrderBy(x => x.OffsetMeters).ToList(); - - int solid_gradient_oeff = orderedBrushCollection.Count == 1 ? 1 : 2; - double prev_offset_cm = 0; - - for (int brushIndex = 0; brushIndex < orderedBrushCollection.Count; brushIndex++) - { - var brush = orderedBrushCollection[brushIndex]; - double brush_length_centimeters = 0d; - double brush_offset_cm = 0; - - if ((brushIndex + 1) < orderedBrushCollection.Count) - { - brush_offset_cm = (brush.OffsetMeters * 100d); - double next_brush_offset_cm = (orderedBrushCollection[brushIndex + 1].OffsetMeters * 100d); - brush_length_centimeters = ((next_brush_offset_cm - brush_offset_cm) + (brush_offset_cm - prev_offset_cm)); - - if (brushIndex == 0) - { - // add a resolution step for first brush - brush_length_centimeters += resolution; - } - } - else//last brush or solid brush - { - brush_length_centimeters = (segment_length_cm - prev_offset_cm); - if (orderedBrushCollection.Count > 1) - { - // add a resolution for last brush , not solid brush - brush_length_centimeters -= resolution; - } - } - - prev_offset_cm = brush_offset_cm; - - foreach (var liquidVolumes in brush.LiquidVolumes) - { - liquidQuantities[liquidVolumes.IdsPack.PackIndex] += liquidVolumes.NanoliterPerCentimeter * (brush_length_centimeters / solid_gradient_oeff); - } - } - } - } - - if (MachineStatus != null) - { - var exception = new InsufficientLiquidQuantityException($"Insufficient liquids level."); - - bool shouldThrow = false; - - foreach (var liquidQuantity in liquidQuantities) - { - int index = liquidQuantity.Key; - var packLevel = MachineStatus.IDSPacksLevels.SingleOrDefault(x => x.Index == index); - var idsPack = configuration.NoneEmptyIdsPacks.SingleOrDefault(x => x.PackIndex == index); - - if (packLevel != null) - { - var idsLevel = new InsufficientLiquidQuantityException.IDSPackLevel() - { - IdsPack = idsPack, - Current = packLevel.DispenserLevel, - Required = (int)liquidQuantities[index], - Maximum = MAX_DISPENSER_NANOLITER, - }; - - LogManager.Log($"Required {idsLevel.IdsPack.LiquidType.Type}: {idsLevel.Required}, Current: {idsLevel.Current}"); - - if (idsLevel.Required > idsLevel.Current) - { - shouldThrow = true; - string display_value = (((double)(idsLevel.Required - idsLevel.Current) / 1000000)).ToString("N2", CultureInfo.InvariantCulture); - idsLevel.Message = $"Missing {display_value} CC to complete the job."; - - if (idsLevel.Required > idsLevel.Maximum) - { - display_value = (((double)(idsLevel.Required - idsLevel.Maximum)) / 1000000).ToString("N2", CultureInfo.InvariantCulture); - idsLevel.Message = $"Required ink exceeds the maximum capacity of the dispenser by {display_value} CC. Please reduce the segment length."; - } - } - - exception.IdsPackLevels.Add(idsLevel); - } - else - { - LogManager.Log($"Could not validate required liquid quantity for job. Missing IDS Pack level at index {index}.", LogCategory.Warning); - } - } - - if (shouldThrow) - { - LogManager.Log("Liquid quantity validation failed due to insufficient quantity. Throwing exception..."); - - exception.IdsPackLevels = exception.IdsPackLevels.OrderBy(x => x.IdsPack.PackIndex).ToList(); - - throw LogManager.Log(exception, JsonConvert.SerializeObject(exception.IdsPackLevels.Select(x => new - { - Liquid = x.IdsPack.LiquidType.Name, - x.Required, - x.Current - }).ToList())); - } - } - else - { - LogManager.Log("Could not validate required liquid quantity for job. No machine status received", LogCategory.Warning); - } - } - - /// <summary> - /// Assign the liquid quantities spent by the last job using the job and the handler last status. - /// </summary> - /// <param name="job">The job.</param> - /// <param name="configuration">The configuration.</param> - /// <param name="handler">The handler.</param> - private void SaveLastJobLiquidQuantities(Job job, Configuration configuration, ProcessParametersTable processParameters, JobHandler handler) - { - if (configuration == null) - { - configuration = _machineConfiguration; - } - - try - { - _lastJobLiquidQuantities = new List<BL.ValueObjects.JobRunLiquidQuantity>(); - - if (JobLiquidQuantityCalculationMode == JobLiquidQuantityCalculationMode.MachineStatus) - { - foreach (var pack in configuration.NoneEmptyIdsPacks.ToList()) - { - var packLevelAfter = MachineStatus.IDSPacksLevels.SingleOrDefault(x => x.Index == pack.PackIndex); - var packLevelBefore = _machineStatusBeforeJobStart.IDSPacksLevels.SingleOrDefault(x => x.Index == pack.PackIndex); - - if (packLevelAfter != null && packLevelBefore != null) - { - _lastJobLiquidQuantities.Add(new BL.ValueObjects.JobRunLiquidQuantity() - { - LiquidType = pack.LiquidType.Type, - Quantity = packLevelBefore.DispenserLevel - packLevelAfter.DispenserLevel, - }); - } - } - } - else - { - _lastJobLiquidQuantities = CreateJobRunLiquidQuantities(job, configuration, processParameters, handler.Status.Progress, handler.Status.TotalProgress); - } - } - catch (Exception ex) - { - LogManager.Log(ex, LogCategory.Critical, "Error saving last job liquid quantities."); - } - } - - private void ValidateJobLiquidQuantity(JobTicket ticket, ProcessParametersTable processParameters, Configuration configuration) - { - LogManager.Log("Validating job liquid quantity..."); - - Dictionary<int, double> liquidQuantities = new Dictionary<int, double>(); - - foreach (var pack in configuration.NoneEmptyIdsPacks.OrderBy(x => x.PackIndex)) - { - liquidQuantities.Add(pack.PackIndex, 0); - } - - for (int i = 0; i < Math.Max(ticket.NumberOfUnits, 1); i++) - { - for (int segmentIndex = 0; segmentIndex < ticket.Segments.Count; segmentIndex++) - { - var segment = ticket.Segments[segmentIndex]; - var segment_length_cm = segment.Length * 100d; - var stop_count = segment.BrushStops.Count - (segment.BrushStops.Count == 1 ? 0 : 1); var stop_length_centimeters = segment_length_cm / stop_count; @@ -2204,9 +1413,9 @@ namespace Tango.Integration.Operation { var stop = segment.BrushStops[stopIndex]; - foreach (var dispenser in stop.Dispensers) + foreach (var liquidVolumes in stop.LiquidVolumes) { - liquidQuantities[dispenser.Index] += dispenser.NanoliterPerCentimeter * stop_length_centimeters; + liquidQuantities[liquidVolumes.IdsPack.PackIndex] += liquidVolumes.NanoliterPerCentimeter * stop_length_centimeters; } } } @@ -2230,8 +1439,7 @@ namespace Tango.Integration.Operation { IdsPack = idsPack, Current = packLevel.DispenserLevel, - Required = (int)liquidQuantities[index], - Maximum = MAX_DISPENSER_NANOLITER, + Required = (int)liquidQuantities[index] }; if (liquidQuantities[index] > packLevel.DispenserLevel) @@ -2266,139 +1474,6 @@ namespace Tango.Integration.Operation #endregion - #region Public Static Methods - - /// <summary> - /// Creates the job run liquid quantities. - /// </summary> - /// <param name="job">The job.</param> - /// <param name="configuration">The configuration.</param> - /// <param name="processParameters">The process parameters.</param> - /// <param name="position">The position.</param> - /// <param name="length">The length.</param> - /// <param name="gradientResolution">The gradient resolution.</param> - /// <returns></returns> - public static List<BL.ValueObjects.JobRunLiquidQuantity> CreateJobRunLiquidQuantities(Job job, Configuration configuration, ProcessParametersTable processParameters, double position, double length) - { - var units = Math.Max(job.NumberOfUnits, 1); - - var effectiveSegments = new List<Segment>(); - for (int i = 0; i < units; i++) - { - if (i > 0 && job.EnableInterSegment) - { - effectiveSegments.Add(Job.CreateInterSegment(job.InterSegmentLength)); - } - - foreach (var segment in job.EffectiveSegments) - { - effectiveSegments.Add(segment.Clone(job)); - } - } - - effectiveSegments.Add(Job.CreateInterSegment(processParameters.DryerBufferLengthMeters)); - - double total = length; - double position_cm = position * 100d; - double total_length = 0; - - Dictionary<int, double> liquidQuantities = new Dictionary<int, double>(); - - foreach (var pack in configuration.NoneEmptyIdsPacks.OrderBy(x => x.PackIndex)) - { - liquidQuantities.Add(pack.PackIndex, 0); - } - - bool stop_calc = false; - - for (int segmentIndex = 0; segmentIndex < effectiveSegments.Count && !stop_calc; segmentIndex++) - { - var segment = effectiveSegments[segmentIndex]; - var segment_length_cm = segment.Length * 100d; - - List<BrushStop> orderedBrushCollection = segment.BrushStops.OrderBy(x => x.OffsetMeters).ToList(); - - int solid_gradient_oeff = orderedBrushCollection.Count == 1 ? 1 : 2; - double prev_offset_cm = 0; - double delta_brushLenghtToStopPosition = 0d; - - double position_interval_centimeters = 0d;//interval for calculation where the stop occurred - for (int brushIndex = 0; brushIndex < orderedBrushCollection.Count && !stop_calc; brushIndex++) - { - var brush = orderedBrushCollection[brushIndex]; - double brush_length_centimeters = 0d; - double brush_offset_cm = 0; - - if ((brushIndex + 1) < orderedBrushCollection.Count) - { - brush_offset_cm = (brush.OffsetMeters * 100d); - double next_brush_offset_cm = (orderedBrushCollection[brushIndex + 1].OffsetMeters * 100d); - brush_length_centimeters = (next_brush_offset_cm - prev_offset_cm); - double brush_length_centimeters_before_calc = brush_length_centimeters; - - if (delta_brushLenghtToStopPosition > 0)//calculate second brush - { - brush_length_centimeters = ((position_interval_centimeters - delta_brushLenghtToStopPosition) * (position_interval_centimeters - delta_brushLenghtToStopPosition)) / position_interval_centimeters; - stop_calc = true; - } - else if (total_length + prev_offset_cm + brush_length_centimeters > position_cm)//calculate first brush - { - position_interval_centimeters = brush_length_centimeters; - delta_brushLenghtToStopPosition = (total_length + prev_offset_cm + brush_length_centimeters) - position_cm; - brush_length_centimeters = brush_length_centimeters - (delta_brushLenghtToStopPosition * delta_brushLenghtToStopPosition / brush_length_centimeters); - } - } - else//last brush or solid brush - { - brush_length_centimeters = (segment_length_cm - prev_offset_cm); - if (delta_brushLenghtToStopPosition > 0)//second brush - { - brush_length_centimeters = ((position_interval_centimeters - delta_brushLenghtToStopPosition) * (position_interval_centimeters - delta_brushLenghtToStopPosition)) / position_interval_centimeters; - stop_calc = true; - } - else if (orderedBrushCollection.Count == 1 && (total_length + segment_length_cm) > position_cm)// solid brush - { - brush_length_centimeters = position_cm - total_length; - stop_calc = true; - } - } - - prev_offset_cm = brush_offset_cm; - - if (brush.LiquidVolumes != null) - { - foreach (var liquidVolumes in brush.LiquidVolumes) - { - liquidQuantities[liquidVolumes.IdsPack.PackIndex] += liquidVolumes.NanoliterPerCentimeter * (brush_length_centimeters / solid_gradient_oeff); - } - } - } - total_length += segment_length_cm; - } - - List<BL.ValueObjects.JobRunLiquidQuantity> quantities = new List<BL.ValueObjects.JobRunLiquidQuantity>(); - - foreach (var liquidQuantity in liquidQuantities) - { - int index = liquidQuantity.Key; - var idsPack = configuration.NoneEmptyIdsPacks.SingleOrDefault(x => x.PackIndex == index); - - if (idsPack != null) - { - quantities.Add(new BL.ValueObjects.JobRunLiquidQuantity() - { - LiquidType = idsPack.LiquidType.Type, - Quantity = (int)liquidQuantities[index], - }); - } - } - - return quantities; - } - - - #endregion - #region Public Methods /// <summary> @@ -2426,16 +1501,7 @@ namespace Tango.Integration.Operation throw new NullReferenceException("Could not locate an active process parameters tables group for RML " + job.Rml.Name); } - ProcessParametersTable processParameters = null; - - try - { - processParameters = converter.GetRecommendedProcessParameters(job); - } - catch (Exception ex) - { - throw LogManager.Log(new InvalidOperationException($"An error occurred while trying to resolve the recommended process parameters.\n{ex.Message}")); - } + var processParameters = converter.GetRecommendedProcessParameters(job); if (processParameters == null) { @@ -2445,104 +1511,104 @@ namespace Tango.Integration.Operation //Perform color correction foreach (var stop in jobSegments.SelectMany(x => x.BrushStops)) { - //if (stop.LiquidVolumes == null || stop.BrushColorSpace == ColorSpaces.Volume) - //{ - if (stop.BrushColorSpace == ColorSpaces.RGB || stop.BrushColorSpace == ColorSpaces.LAB) + if (stop.LiquidVolumes == null) { - var output = converter.Convert(stop, false); - - //TODO: Restore this when Mirta conversion is working as expected. - //if (suggestions.OutOfGamut) - //{ - // throw new InvalidOperationException("Cannot print a brush stop which is out of gamut."); - //} - - stop.SetLiquidVolumes(job.Machine.Configuration, job.Rml, processParameters); - - foreach (var outputLiquid in output.SingleCoordinates.OutputLiquids) + if (stop.BrushColorSpace == ColorSpaces.RGB || stop.BrushColorSpace == ColorSpaces.LAB) { - var liquidVolume = stop.LiquidVolumes.SingleOrDefault(x => x.IdsPack.LiquidType.Code == outputLiquid.LiquidType.ToInt32()); + var output = converter.Convert(stop, false); - if (liquidVolume == null) - { - throw new NullReferenceException("Liquid volume not found for color conversion output liquid '" + outputLiquid.LiquidType + "'."); - } + //TODO: Restore this when Mirta conversion is working as expected. + //if (suggestions.OutOfGamut) + //{ + // throw new InvalidOperationException("Cannot print a brush stop which is out of gamut."); + //} - liquidVolume.Volume = outputLiquid.Volume; - } - } - else if (stop.BrushColorSpace == ColorSpaces.Catalog) - { - if (stop.ColorCatalogsItem != null) - { stop.SetLiquidVolumes(job.Machine.Configuration, job.Rml, processParameters); + foreach (var outputLiquid in output.SingleCoordinates.OutputLiquids) { - var liquidVolume = stop.LiquidVolumes.SingleOrDefault(x => x.LiquidType == LiquidTypes.Cyan); + var liquidVolume = stop.LiquidVolumes.SingleOrDefault(x => x.IdsPack.LiquidType.Code == outputLiquid.LiquidType.ToInt32()); if (liquidVolume == null) { - throw new NullReferenceException("Liquid volume not found for color conversion output liquid '" + LiquidTypes.Cyan + "'."); + throw new NullReferenceException("Liquid volume not found for color conversion output liquid '" + outputLiquid.LiquidType + "'."); } - liquidVolume.Volume = stop.ColorCatalogsItem.Cyan; + liquidVolume.Volume = outputLiquid.Volume; } - + } + else if (stop.BrushColorSpace == ColorSpaces.Catalog) + { + if (stop.ColorCatalogsItem != null) { - var liquidVolume = stop.LiquidVolumes.SingleOrDefault(x => x.LiquidType == LiquidTypes.Magenta); + stop.SetLiquidVolumes(job.Machine.Configuration, job.Rml, processParameters); - if (liquidVolume == null) + if (stop.ColorCatalogsItem.Cyan > 0) { - throw new NullReferenceException("Liquid volume not found for color conversion output liquid '" + LiquidTypes.Magenta + "'."); - } + var liquidVolume = stop.LiquidVolumes.SingleOrDefault(x => x.IdsPack.LiquidType.Code == LiquidTypes.Cyan.ToInt32()); - liquidVolume.Volume = stop.ColorCatalogsItem.Magenta; - } + if (liquidVolume == null) + { + throw new NullReferenceException("Liquid volume not found for color conversion output liquid '" + LiquidTypes.Cyan + "'."); + } - { - var liquidVolume = stop.LiquidVolumes.SingleOrDefault(x => x.LiquidType == LiquidTypes.Yellow); + liquidVolume.Volume = stop.ColorCatalogsItem.Cyan; + } - if (liquidVolume == null) + if (stop.ColorCatalogsItem.Magenta > 0) { - throw new NullReferenceException("Liquid volume not found for color conversion output liquid '" + LiquidTypes.Yellow + "'."); - } + var liquidVolume = stop.LiquidVolumes.SingleOrDefault(x => x.IdsPack.LiquidType.Code == LiquidTypes.Magenta.ToInt32()); - liquidVolume.Volume = stop.ColorCatalogsItem.Yellow; - } + if (liquidVolume == null) + { + throw new NullReferenceException("Liquid volume not found for color conversion output liquid '" + LiquidTypes.Magenta + "'."); + } - { - var liquidVolume = stop.LiquidVolumes.SingleOrDefault(x => x.LiquidType == LiquidTypes.Black); + liquidVolume.Volume = stop.ColorCatalogsItem.Magenta; + } - if (liquidVolume == null) + if (stop.ColorCatalogsItem.Yellow > 0) { - throw new NullReferenceException("Liquid volume not found for color conversion output liquid '" + LiquidTypes.Black + "'."); + var liquidVolume = stop.LiquidVolumes.SingleOrDefault(x => x.IdsPack.LiquidType.Code == LiquidTypes.Yellow.ToInt32()); + + if (liquidVolume == null) + { + throw new NullReferenceException("Liquid volume not found for color conversion output liquid '" + LiquidTypes.Yellow + "'."); + } + + liquidVolume.Volume = stop.ColorCatalogsItem.Yellow; } - liquidVolume.Volume = stop.ColorCatalogsItem.Black; + if (stop.ColorCatalogsItem.Black > 0) + { + var liquidVolume = stop.LiquidVolumes.SingleOrDefault(x => x.IdsPack.LiquidType.Code == LiquidTypes.Black.ToInt32()); + + if (liquidVolume == null) + { + throw new NullReferenceException("Liquid volume not found for color conversion output liquid '" + LiquidTypes.Black + "'."); + } + + liquidVolume.Volume = stop.ColorCatalogsItem.Black; + } + } + else + { + throw new InvalidOperationException($"No catalog item specified for segment color."); } } - else if (!stop.IsTransparent) + else if (stop.BrushColorSpace == ColorSpaces.Volume) { - throw new InvalidOperationException($"No catalog item specified for segment color."); + stop.SetLiquidVolumes(job.Machine.Configuration, job.Rml, processParameters); } else { - stop.SetLiquidVolumes(job.Machine.Configuration, job.Rml, processParameters); + throw new InvalidOperationException($"Unsupported color space {stop.BrushColorSpace}."); } } - else if (stop.BrushColorSpace == ColorSpaces.Volume) - { - stop.SetLiquidVolumes(job.Machine.Configuration, job.Rml, processParameters); - } - else - { - throw new InvalidOperationException($"Unsupported color space {stop.BrushColorSpace}."); - } - //} if (job.EnableLubrication) { - var lubricantVolume = stop.LiquidVolumes.SingleOrDefault(x => x.IdsPack != null && x.IdsPack.LiquidType != null && x.LiquidType == LiquidTypes.Lubricant); + var lubricantVolume = stop.LiquidVolumes.SingleOrDefault(x => x.IdsPack != null && x.IdsPack.LiquidType != null && x.IdsPack.LiquidType.Code == LiquidTypes.Lubricant.ToInt32()); if (lubricantVolume != null) { @@ -2564,26 +1630,13 @@ namespace Tango.Integration.Operation { return Task.Factory.StartNew(() => { - if (!CanPrint) + if (Status != MachineStatuses.ReadyToDye) { throw new InvalidOperationException("Could not print while status = " + Status); } - _jobStartDate = DateTime.UtcNow; - LogManager.Log($"Executing job '{job.Name}'..."); - if (MachineStatus == null) - { - LogManager.Log("Aborting job execution. No machine status received yet."); - throw new InvalidOperationException("Cannot execute a job before at least one machine status has been received."); - } - - _lastJobLiquidQuantities = new List<BL.ValueObjects.JobRunLiquidQuantity>(); - _jobUploadingStartDate = null; - _jobHeatingStartDate = null; - _jobActualStartDate = null; - RunningJob = null; RunningJobStatus = null; @@ -2592,59 +1645,10 @@ namespace Tango.Integration.Operation job.NumberOfUnits = 1; } - if (job.EnableLubrication) - { - LogManager.Log("Job lubrication is enabled. Settings all brush stops to 100% lubricant."); - - try - { - foreach (var stop in job.Segments.SelectMany(x => x.BrushStops).Where(x => x.BrushColorSpace != ColorSpaces.Volume)) - { - var lubricantVolume = stop.LiquidVolumes.SingleOrDefault(x => x.IdsPack != null && x.IdsPack.LiquidType != null && x.LiquidType == LiquidTypes.Lubricant); - - if (lubricantVolume != null) - { - lubricantVolume.Volume = 100; - } - } - } - catch (Exception ex) - { - System.Diagnostics.Debugger.Break(); - LogManager.Log(ex, "Error in setting automatic lubrication volumes."); - } - } - else - { - LogManager.Log("Job lubrication is disabled."); - } - - //Modify transparent/white brush stops. (Transparent/white stops should be all zeros and 100% TI) - LogManager.Log("Modifying all transparent/white brush stops..."); - foreach (var stop in job.Segments.SelectMany(x => x.BrushStops).Where(x => x.IsTransparent || x.IsWhite).ToList()) - { - foreach (var liquidVolume in stop.LiquidVolumes.Where(x => x.LiquidType != LiquidTypes.TransparentInk && x.LiquidType != LiquidTypes.Lubricant).ToList()) - { - liquidVolume.Volume = 0; - } - - var tiLiquid = stop.LiquidVolumes.SingleOrDefault(x => x.IdsPack != null && x.IdsPack.LiquidType != null && x.LiquidType == LiquidTypes.TransparentInk); - - if (tiLiquid != null) - { - tiLiquid.Volume = 100; - } - } - - //Validate liquid quantities.. if (EnableJobLiquidQuantityValidation) { ValidateJobLiquidQuantity(job, processParameters, job.Machine.Configuration); } - else - { - LogManager.Log("Liquid quantity validation is disabled. Skipping..."); - } var originalJob = job; var clonedJob = job.Clone(); @@ -2683,94 +1687,57 @@ namespace Tango.Integration.Operation if (JobUnitsMethod == JobUnitsMethods.Device) { - ticket.NumberOfUnits = (uint)Math.Max(job.NumberOfUnits, 1); + ticket.NumberOfUnits = (uint)job.NumberOfUnits; } - //Spool parameters ticket.Spool = new JobSpool(); + job.SpoolType.MapPrimitivesTo(ticket.Spool); - ticket.Spool.JobSpoolType = (JobSpoolType)job.SpoolType.Code; - //Override spool parameters from RML Spool calibration - var rmlSpool = job.Rml.RmlsSpools.FirstOrDefault(x => x.SpoolType.Guid == job.SpoolType.Guid); - if (rmlSpool != null) + var spool = job.Machine.Spools.SingleOrDefault(x => x.SpoolType == job.SpoolType); + + if (spool == null) { - ticket.Spool.RotationsPerPassage = rmlSpool.RotationsPerPassage != null ? rmlSpool.RotationsPerPassage.Value : ticket.Spool.RotationsPerPassage; - ticket.Spool.Length = rmlSpool.Length != null ? rmlSpool.Length.Value : ticket.Spool.Length; - ticket.Spool.BackingRate = rmlSpool.BackingRate != null ? rmlSpool.BackingRate.Value : ticket.Spool.BackingRate; - ticket.Spool.BottomBackingRate = rmlSpool.BottomBackingRate != null ? rmlSpool.BottomBackingRate.Value : ticket.Spool.BottomBackingRate; + throw new InvalidOperationException("Job spool type is not registered with this machine."); } - - //Override spool parameters from Machine Spool calibration - var machineSpool = job.Machine.Spools.FirstOrDefault(x => x.SpoolType.Guid == job.SpoolType.Guid); - if (machineSpool != null) + else { - ticket.Spool.LimitSwitchStartPointOffset = machineSpool.LimitSwitchStartPointOffset != null ? machineSpool.LimitSwitchStartPointOffset.Value : ticket.Spool.LimitSwitchStartPointOffset; + spool.MapPrimitivesTo(ticket.Spool); } - //Thread Parameters - ticket.ThreadParameters = new ThreadParameters(); - job.Rml.MapPrimitivesTo(ticket.ThreadParameters); + ticket.Spool.JobSpoolType = (JobSpoolType)job.SpoolType.Code; ProcessParameters process = new ProcessParameters(); processParameters.MapPrimitivesTo(process); ticket.ProcessParameters = process; - //Head Cleaning Parameters - ticket.HeadCleaningParameters = new HeadCleaningParameters(); - ticket.HeadCleaningParameters.CleanerFlow = job.Rml.CleanerFlow; - ticket.HeadCleaningParameters.ArcHeadCleaningMotorSpeed = job.Rml.ArcHeadCleaningMotorSpeed; - JobHandler handler = null; - StorageFileHandler fileUploadHandler = null; + bool canceled = false; bool requestSent = false; handler = new JobHandler(async () => { try { - if (handler.CanCancel) + if (!canceled) { - handler.CanCancel = false; - handler.IsCanceled = true; - LogManager.Log("Aborting current job..."); + canceled = true; LogManager.Log($"Aborting current gradient generation..."); GradientGenerationConfiguration.AbortCurrentGeneration(); - if (fileUploadHandler != null) + if (requestSent) { - LogManager.Log("Job is currently uploading. Aborting file upload..."); - await fileUploadHandler.Cancel(); - fileUploadHandler = null; - LogManager.Log("Job upload canceled."); - OnPrintingAborted(handler, clonedJob); - handler.RaiseCanceled(); - if (Status != MachineStatuses.Disconnected) - { - Status = MachineStatuses.ReadyToDye; - } + var result = await SendRequest<AbortJobRequest, AbortJobResponse>(new AbortJobRequest()); } - else - { - if (requestSent) - { - var result = await SendRequest<AbortJobRequest, AbortJobResponse>(new AbortJobRequest(), new TransportRequestConfig() { ShouldLog = true }); - } - SaveLastJobLiquidQuantities(clonedJob, originalJob.Machine.Configuration, processParameters, handler); - OnPrintingAborted(handler, clonedJob); - handler.RaiseCanceled(); - if (Status != MachineStatuses.Disconnected) - { - Status = MachineStatuses.ReadyToDye; - } - } + PrintingAborted?.Invoke(this, new PrintingEventArgs(handler, clonedJob)); + PrintingEnded?.Invoke(this, new PrintingEventArgs(handler, clonedJob)); + handler.RaiseCanceled(); } } catch (Exception ex) { - handler.CanCancel = true; LogManager.Log(ex, "Failed to cancel job."); } }, clonedJob, ticket, processParameters, JobHandlingMode); @@ -2788,15 +1755,9 @@ namespace Tango.Integration.Operation ThreadFactory.StartNew(async () => { - if (handler.IsCanceled) - { - Status = MachineStatuses.ReadyToDye; - return; - } - Status = MachineStatuses.GettingReady; RunningJob = clonedJob; - OnPrintingStarted(handler, clonedJob); + PrintingStarted?.Invoke(this, new PrintingEventArgs(handler, clonedJob)); Thread.Sleep(100); @@ -2827,28 +1788,6 @@ namespace Tango.Integration.Operation } } - //Log Job Outline (Only first and last brush stops if gradient). - var ticketToLog = ticket.Clone(); - ticketToLog.UploadStrategy = JobUploadStrategy; - ticketToLog.Segments.Clear(); - - foreach (var seg in ticket.Segments) - { - JobSegment segmentToLog = new JobSegment(); - - segmentToLog.Length = seg.Length; - segmentToLog.BrushStops.Add(seg.BrushStops.First()); - - if (seg.BrushStops.Count > 1) - { - segmentToLog.BrushStops.Add(seg.BrushStops.Last()); - } - - ticketToLog.Segments.Add(segmentToLog); - } - - LogManager.Log($"Job outline for '{job.Name}':\n{ticketToLog.ToJsonString()}"); - if (handler.IsCanceled) { Status = MachineStatuses.ReadyToDye; @@ -2886,13 +1825,10 @@ namespace Tango.Integration.Operation request.JobTicket = ticket.Clone(); request.JobTicket.UploadStrategy = JobUploadStrategy; - LogManager.Log($"Job upload method is set to {JobUploadStrategy}..."); + //Use this if you want to log the entire job... + var logRequest = request.Clone(); - if (handler.IsCanceled) - { - Status = MachineStatuses.ReadyToDye; - return; - } + LogManager.Log($"Job upload method is set to {JobUploadStrategy}..."); var oldKeepAlive = UseKeepAlive; @@ -2914,21 +1850,9 @@ namespace Tango.Integration.Operation Message = "Uploading job description file...", }); - if (handler.IsCanceled) - { - Status = MachineStatuses.ReadyToDye; - return; - } - LogManager.Log("Creating storage API manager..."); var storage = CreateStorageManager(); - if (handler.IsCanceled) - { - Status = MachineStatuses.ReadyToDye; - return; - } - //Suppress keep alive while job uploads. //storage.SuppressKeepAliveWhileFileUploads = true; UseKeepAlive = false; //This is a work around for Shlomo not managing to keep alive while parsing the file. @@ -2947,183 +1871,346 @@ namespace Tango.Integration.Operation String job_file_path = Path.Combine(storageInfo.Root, JOB_DESCRIPTION_FILE_NAME); - LogManager.Log($"Uploading job description file '{job_file_path}' of size: {ms.Length} bytes..."); + LogManager.Log($"Uploading job description file '{job_file_path}' of size: {ms.Length}"); + await storage.UploadFileSync(job_file_path, ms); + LogManager.Log("Job upload completed successfully."); - TaskCompletionSource<object> uploadCompletion = new TaskCompletionSource<object>(); - _jobUploadingStartDate = DateTime.UtcNow; - fileUploadHandler = await storage.UploadFile(job_file_path, ms); - bool uploadCanceled = false; - Exception uploadException = null; - fileUploadHandler.Canceled += (_, __) => - { - uploadCanceled = true; - uploadCompletion.SetResult(true); - }; - fileUploadHandler.Completed += (_, __) => - { - uploadCompletion.SetResult(true); - }; - fileUploadHandler.Failed += (_, e) => + ms.Dispose(); + + request.JobTicket.JobDescriptionFile = job_file_path; + } + catch (Exception ex) + { + UseKeepAlive = oldKeepAlive; + Status = MachineStatuses.ReadyToDye; + PrintingFailed?.Invoke(this, new PrintingFailedEventArgs(handler, clonedJob, ex)); + PrintingEnded?.Invoke(this, new PrintingEventArgs(handler, clonedJob)); + handler.RaiseFailed(ex); + LogRequestFailed(request, ex); + return; + } + } + + if (handler.IsCanceled) + { + UseKeepAlive = oldKeepAlive; + Status = MachineStatuses.ReadyToDye; + return; + } + + LogRequestSent(request); + bool responseLogged = false; + bool completed = false; //Use this in case Shlomo is sending progress after completion. + + SendContinuousRequest<JobRequest, JobResponse>(request, null, TimeSpan.FromSeconds(2)).Subscribe((response) => + { + if (!completed) + { + handler.RaiseStatusReceived(response.Message.Status); + _last_job_status = handler.Status; + + if (response.Message.Status.Progress > 0) { - uploadCompletion.SetException(e); - }; + if (oldKeepAlive != UseKeepAlive) + { + UseKeepAlive = oldKeepAlive; + } + } - try + if (!responseLogged) { - await uploadCompletion.Task; + requestSent = true; + responseLogged = true; + LogResponseReceived(response.Message); } - catch (Exception ue) + + if (JobHandlingMode == JobHandlerModes.SettingUp) { - if (uploadException != null) - { - throw uploadException; - } - else + if (response.Message.Status.Progress > processParameters.DryerBufferLengthMeters) { - throw ue; + if (!completed) + { + Status = MachineStatuses.Printing; + } } } - finally + else { - try + if (response.Message.Status.Progress > 0) { - fileUploadHandler = null; - ms.Dispose(); + if (!completed) + { + Status = MachineStatuses.Printing; + } } - catch { } } + } + + }, (ex) => + { + if (!completed) + { + completed = true; - if (uploadCanceled) + UseKeepAlive = oldKeepAlive; + + if (!(ex is ContinuousResponseAbortedException)) { - return; + Status = MachineStatuses.ReadyToDye; + + if (!handler.IsCanceled) + { + PrintingFailed?.Invoke(this, new PrintingFailedEventArgs(handler, clonedJob, ex)); + PrintingEnded?.Invoke(this, new PrintingEventArgs(handler, clonedJob)); + handler.RaiseFailed(ex); + LogRequestFailed(request, ex); + } } else { - LogManager.Log("Job upload completed successfully."); + Status = MachineStatuses.ReadyToDye; } - - request.JobTicket.JobDescriptionFile = job_file_path; } - catch (Exception ex) + }, () => + { + if (!completed) { + completed = true; + UseKeepAlive = oldKeepAlive; + Status = MachineStatuses.ReadyToDye; - OnPrintingFailed(handler, clonedJob, ex); - handler.RaiseFailed(ex); - return; + PrintingCompleted?.Invoke(this, new PrintingEventArgs(handler, clonedJob)); + PrintingEnded?.Invoke(this, new PrintingEventArgs(handler, clonedJob)); + handler.RaiseCompleted(); } + }); + }); + + return handler; + + }); + } + + /// <summary> + /// Executes a print stub for emulating a full job. + /// The process parameters table will be calculated using color conversion gamut region. + /// This method cannot accept brush stops with 'Volume' as color space. + /// </summary> + /// <param name="job">The job.</param> + /// <returns></returns> + /// <exception cref="InvalidOperationException"> + /// Cannot print a brush stop with volume color space when process parameters table has not been specified. + /// or + /// Could not print while status = " + Status + /// </exception> + /// <exception cref="NullReferenceException"> + /// Job RML is null + /// or + /// Could not locate an active process parameters tables group for RML " + job.Rml.Name + /// or + /// Could not locate process parameters table index " + processParametersTableIndex + " in group " + processGroup.Name + " for RML " + job.Rml.Name + /// or + /// Liquid volume not found for color conversion output liquid '" + outputLiquid.LiquidType + "'. + /// </exception> + public Task<JobHandler> PrintStub(Job job) + { + return Task.Factory.StartNew<JobHandler>(() => + { + + //Check not brush stop has color space 'Volume'. + if (job.Segments.SelectMany(x => x.BrushStops).ToList().Exists(x => x.ColorSpace.Code == ColorSpaces.Volume.ToInt32())) + { + throw new InvalidOperationException("Cannot print a brush stop with volume color space when process parameters table has not been specified."); + } + + //Get least common process parameters table index. + int processParametersTableIndex = 0; + + if (job.Rml == null) + { + throw new NullReferenceException("Job RML is null"); + } + + var processGroup = job.Rml.ProcessParametersTablesGroups.FirstOrDefault(x => x.Active); + + if (processGroup == null) + { + throw new NullReferenceException("Could not locate an active process parameters tables group for RML " + job.Rml.Name); + } + + var processParameters = processGroup.ProcessParametersTables.FirstOrDefault(x => x.TableIndex == processParametersTableIndex); + + if (processParameters == null) + { + throw new NullReferenceException("Could not locate process parameters table index " + processParametersTableIndex + " in group " + processGroup.Name + " for RML " + job.Rml.Name); + } + + //Perform color correction + foreach (var stop in job.Segments.SelectMany(x => x.BrushStops)) + { + if (stop.LiquidVolumes == null) + { + stop.SetLiquidVolumes(job.Machine.Configuration, job.Rml, processParameters); } - else + + foreach (var liquidVolume in stop.LiquidVolumes) { - _jobUploadingStartDate = DateTime.UtcNow; + liquidVolume.Volume = 10; } + } - if (handler.IsCanceled) + if (Status != MachineStatuses.ReadyToDye) + { + throw new InvalidOperationException("Could not print while status = " + Status); + } + + RunningJob = null; + RunningJobStatus = null; + + var originalJob = job; + + CurrentProcessParameters = processParameters; + + StubJobRequest request = new StubJobRequest(); + + if (job.NumberOfUnits < 1) + { + job.NumberOfUnits = 1; + } + + job = job.Clone(); + + var segments = job.OrderedSegments.ToList(); + + for (int i = 0; i < job.NumberOfUnits - 1; i++) + { + foreach (var s in segments) { - UseKeepAlive = oldKeepAlive; - Status = MachineStatuses.ReadyToDye; - return; + job.Segments.Add(s); } + } - _machineStatusBeforeJobStart = MachineStatus.Clone(); + JobTicket ticket = new JobTicket(); + ticket.Guid = originalJob.Guid; + ticket.EnableInterSegment = job.EnableInterSegment; + ticket.InterSegmentLength = job.InterSegmentLength; + ticket.Length = job.Length; + ticket.WindingMethod = (JobWindingMethod)job.WindingMethod.Code; + ticket.Spool = new JobSpool(); - SaveCachedJobOperation(clonedJob); //Cache job and machine status for job resume! + job.SpoolType.MapPrimitivesTo(ticket.Spool); + ticket.Spool.JobSpoolType = (JobSpoolType)job.SpoolType.Code; - bool responseLogged = false; - bool completed = false; //Use this in case Shlomo is sending progress after completion. + ProcessParameters process = new ProcessParameters(); + processParameters.MapPrimitivesTo(process); + ticket.ProcessParameters = process; - _jobHeatingStartDate = DateTime.UtcNow; + foreach (var segment in job.OrderedSegments) + { + JobSegment jobSegment = new JobSegment(); + jobSegment.Length = segment.LengthWithFactor; + jobSegment.Name = segment.Name; - SendContinuousRequest<JobRequest, JobResponse>(request, new TransportContinuousRequestConfig() { ContinuousTimeout = ContinuousRequestTimeout.Add(TimeSpan.FromSeconds(3)), ShouldLog = true }).Subscribe((response) => - { - if (!completed) - { - handler.RaiseStatusReceived(response.Message.Status); - _last_job_status = handler.Status; + foreach (var stop in segment.BrushStops) + { + JobBrushStop jobStop = new JobBrushStop(); + jobStop.Index = stop.StopIndex; + jobStop.OffsetPercent = stop.OffsetPercent; + jobStop.OffsetMeters = stop.OffsetMeters; - if (response.Message.Status.Progress > 0) - { - if (oldKeepAlive != UseKeepAlive) - { - UseKeepAlive = oldKeepAlive; - } + if (stop.LiquidVolumes == null) + { + stop.SetLiquidVolumes(job.Machine.Configuration, job.Rml, processParameters); + } - if (_jobActualStartDate == null) - { - _jobActualStartDate = DateTime.UtcNow; - } - } + foreach (var liquidVolume in stop.LiquidVolumes) + { + JobDispenser dispenser = new JobDispenser(); + dispenser.Index = liquidVolume.IdsPack.PackIndex; + dispenser.Volume = liquidVolume.Volume; + dispenser.DispenserLiquidType = (DispenserLiquidType)liquidVolume.IdsPack.LiquidType.Code; + dispenser.DispenserStepDivision = (DispenserStepDivision)liquidVolume.DispenserStepDivision; - if (!responseLogged) - { - requestSent = true; - responseLogged = true; - } + dispenser.NanoliterPerPulse = liquidVolume.IdsPack.Dispenser.NlPerPulse; - if (JobHandlingMode == JobHandlerModes.SettingUp) - { - if (response.Message.Status.Progress > processParameters.DryerBufferLengthMeters) - { - if (!completed) - { - Status = MachineStatuses.Printing; - } - } - } - else - { - if (response.Message.Status.Progress > 0) - { - if (!completed) - { - Status = MachineStatuses.Printing; - } - } - } - } + dispenser.LiquidMaxNanoliterPerCentimeter = liquidVolume.LiquidMaxNanoliterPerCentimeter; + dispenser.NanoliterPerCentimeter = liquidVolume.NanoliterPerCentimeter; + dispenser.NanolitterPerSecond = liquidVolume.NanoliterPerSecond; + dispenser.PulsePerSecond = liquidVolume.PulsePerSecond; - }, (ex) => - { - if (!completed) - { - completed = true; + jobStop.Dispensers.Add(dispenser); + } - UseKeepAlive = oldKeepAlive; + jobSegment.BrushStops.Add(jobStop); + } - if (Status != MachineStatuses.Disconnected) - { - Status = MachineStatuses.ReadyToDye; - } + ticket.Segments.Add(jobSegment); + } - if (!handler.IsCanceled) - { - SaveLastJobLiquidQuantities(originalJob, originalJob.Machine.Configuration, processParameters, handler); + request.JobTicket = ticket; - Exception finalException = ex; + JobHandler handler = null; - if (ex is ContinuousResponseAbortedException continuousException) - { - finalException = new ContinuousResponseAbortedException($"Job aborted by the embedded device ({continuousException.Container.ErrorMessage})."); - } + handler = new JobHandler(async () => + { + try + { + var result = await SendRequest<StubAbortJobRequest, StubAbortJobResponse>(new StubAbortJobRequest()); + PrintingAborted?.Invoke(this, new PrintingEventArgs(handler, originalJob)); + PrintingEnded?.Invoke(this, new PrintingEventArgs(handler, originalJob)); + handler.RaiseCanceled(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Failed to cancel job."); + } + }, originalJob, ticket, processParameters, JobHandlingMode); - OnPrintingFailed(handler, originalJob, finalException); - handler.RaiseFailed(finalException); - } - } - }, () => - { - if (!completed) - { - completed = true; + handler.StatusChanged += (x, s) => + { + RunningJobStatus = s; + }; + + LogRequestSent(request); + bool responseLogged = false; - UseKeepAlive = oldKeepAlive; + SendContinuousRequest<StubJobRequest, StubJobResponse>(request, null, TimeSpan.FromSeconds(2)).Subscribe((response) => + { + handler.RaiseStatusReceived(response.Message.Status); + + if (!responseLogged) + { + responseLogged = true; + Status = MachineStatuses.Printing; + RunningJob = originalJob; + PrintingStarted?.Invoke(this, new PrintingEventArgs(handler, originalJob)); + LogResponseReceived(response.Message); + } + }, (ex) => + { + if (!(ex is ContinuousResponseAbortedException)) + { + Status = MachineStatuses.ReadyToDye; - Status = MachineStatuses.ReadyToDye; - SaveLastJobLiquidQuantities(clonedJob, originalJob.Machine.Configuration, processParameters, handler); - OnPrintingCompleted(handler, clonedJob); - handler.RaiseCompleted(); - } - }); + if (!handler.IsCanceled) + { + PrintingFailed?.Invoke(this, new PrintingFailedEventArgs(handler, originalJob, ex)); + PrintingEnded?.Invoke(this, new PrintingEventArgs(handler, originalJob)); + handler.RaiseFailed(ex); + LogRequestFailed(request, ex); + } + } + else + { + Status = MachineStatuses.ReadyToDye; + } + }, () => + { + Status = MachineStatuses.ReadyToDye; + PrintingCompleted?.Invoke(this, new PrintingEventArgs(handler, originalJob)); + PrintingEnded?.Invoke(this, new PrintingEventArgs(handler, originalJob)); + handler.RaiseCompleted(); }); return handler; @@ -3147,10 +2234,13 @@ namespace Tango.Integration.Operation try { CurrentProcessParameters = processParameters; - response = await SendRequest<UploadProcessParametersRequest, UploadProcessParametersResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(request); + response = await SendRequest<UploadProcessParametersRequest, UploadProcessParametersResponse>(request); + LogResponseReceived(response); } catch (Exception ex) { + LogRequestFailed(request, ex); throw ex; } @@ -3165,8 +2255,6 @@ namespace Tango.Integration.Operation /// <returns></returns> public async Task<UploadHardwareConfigurationResponse> UploadHardwareConfiguration(HardwareVersion hardwareVersion, Configuration configuration) { - _machineConfiguration = configuration; - try { hardwareVersion = configuration.GetHardwareConfiguration().Merge(hardwareVersion); @@ -3251,14 +2339,14 @@ namespace Tango.Integration.Operation try { - LogManager.Log($"Sending '{nameof(UploadHardwareConfigurationRequest)}'..."); - LogManager.Log($"{nameof(UploadHardwareConfigurationRequest)} request:\n{request.HardwareConfiguration.ToJsonString()}", LogCategory.Debug); - CurrentHardwareConfiguration = hardwareConfiguration; - response = await SendRequest<UploadHardwareConfigurationRequest, UploadHardwareConfigurationResponse>(request, new TransportRequestConfig() { ShouldLog = false }); + LogRequestSent(request); + response = await SendRequest<UploadHardwareConfigurationRequest, UploadHardwareConfigurationResponse>(request); + LogResponseReceived(response); } catch (Exception ex) { + LogRequestFailed(request, ex); throw ex; } @@ -3276,10 +2364,13 @@ namespace Tango.Integration.Operation try { - response = await SendRequest<MotorJoggingRequest, MotorJoggingResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(request); + response = await SendRequest<MotorJoggingRequest, MotorJoggingResponse>(request); + LogResponseReceived(response); } catch (Exception ex) { + LogRequestFailed(request, ex); throw ex; } @@ -3293,7 +2384,8 @@ namespace Tango.Integration.Operation /// <returns></returns> public async Task<MotorAbortJoggingResponse> StopMotorJogging(MotorAbortJoggingRequest request) { - return await SendRequest<MotorAbortJoggingRequest, MotorAbortJoggingResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(request); + return await SendRequest<MotorAbortJoggingRequest, MotorAbortJoggingResponse>(request); } /// <summary> @@ -3303,7 +2395,8 @@ namespace Tango.Integration.Operation /// <returns></returns> public IObservable<MotorHomingResponse> StartMotorHoming(MotorHomingRequest request) { - return SendContinuousRequest<MotorHomingRequest, MotorHomingResponse>(request, new TransportContinuousRequestConfig() { ContinuousTimeout = ContinuousRequestTimeout, ShouldLog = true }).Select(x => x.Message); + LogRequestSent(request); + return SendContinuousRequest<MotorHomingRequest, MotorHomingResponse>(request, null, TimeSpan.FromSeconds(5)).Select(x => x.Message); } /// <summary> @@ -3313,7 +2406,8 @@ namespace Tango.Integration.Operation /// <returns></returns> public async Task<MotorAbortHomingResponse> StopMotorHoming(MotorAbortHomingRequest request) { - return await SendRequest<MotorAbortHomingRequest, MotorAbortHomingResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(request); + return await SendRequest<MotorAbortHomingRequest, MotorAbortHomingResponse>(request); } /// <summary> @@ -3323,7 +2417,8 @@ namespace Tango.Integration.Operation /// <returns></returns> public async Task<DispenserJoggingResponse> StartDispenserJogging(DispenserJoggingRequest request) { - return await SendRequest<DispenserJoggingRequest, DispenserJoggingResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(request); + return await SendRequest<DispenserJoggingRequest, DispenserJoggingResponse>(request); } /// <summary> @@ -3333,7 +2428,8 @@ namespace Tango.Integration.Operation /// <returns></returns> public async Task<DispenserAbortJoggingResponse> StopDispenserJogging(DispenserAbortJoggingRequest request) { - return await SendRequest<DispenserAbortJoggingRequest, DispenserAbortJoggingResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(request); + return await SendRequest<DispenserAbortJoggingRequest, DispenserAbortJoggingResponse>(request); } /// <summary> @@ -3343,7 +2439,8 @@ namespace Tango.Integration.Operation /// <returns></returns> public IObservable<DispenserHomingResponse> StartDispenserHoming(DispenserHomingRequest request) { - return SendContinuousRequest<DispenserHomingRequest, DispenserHomingResponse>(request, new TransportContinuousRequestConfig() { ContinuousTimeout = ContinuousRequestTimeout, ShouldLog = true }).Select(x => x.Message); + LogRequestSent(request); + return SendContinuousRequest<DispenserHomingRequest, DispenserHomingResponse>(request, null, TimeSpan.FromSeconds(5)).Select(x => x.Message); } /// <summary> @@ -3353,7 +2450,8 @@ namespace Tango.Integration.Operation /// <returns></returns> public async Task<DispenserAbortHomingResponse> StopDispenserHoming(DispenserAbortHomingRequest request) { - return await SendRequest<DispenserAbortHomingRequest, DispenserAbortHomingResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(request); + return await SendRequest<DispenserAbortHomingRequest, DispenserAbortHomingResponse>(request); } /// <summary> @@ -3363,7 +2461,8 @@ namespace Tango.Integration.Operation /// <returns></returns> public async Task<SetDigitalOutResponse> SetDigitalOut(SetDigitalOutRequest request) { - return await SendRequest<SetDigitalOutRequest, SetDigitalOutResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(request); + return await SendRequest<SetDigitalOutRequest, SetDigitalOutResponse>(request); } /// <summary> @@ -3373,7 +2472,8 @@ namespace Tango.Integration.Operation /// <returns></returns> public async Task<ThreadJoggingResponse> StartThreadJogging(ThreadJoggingRequest request) { - return await SendRequest<ThreadJoggingRequest, ThreadJoggingResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(request); + return await SendRequest<ThreadJoggingRequest, ThreadJoggingResponse>(request); } /// <summary> @@ -3383,7 +2483,8 @@ namespace Tango.Integration.Operation /// <returns></returns> public async Task<ThreadAbortJoggingResponse> StopThreadJogging(ThreadAbortJoggingRequest request) { - return await SendRequest<ThreadAbortJoggingRequest, ThreadAbortJoggingResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(request); + return await SendRequest<ThreadAbortJoggingRequest, ThreadAbortJoggingResponse>(request); } /// <summary> @@ -3393,7 +2494,8 @@ namespace Tango.Integration.Operation /// <returns></returns> public async Task<SetComponentValueResponse> SetComponentValue(SetComponentValueRequest request) { - return await SendRequest<SetComponentValueRequest, SetComponentValueResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(request); + return await SendRequest<SetComponentValueRequest, SetComponentValueResponse>(request); } /// <summary> @@ -3414,10 +2516,13 @@ namespace Tango.Integration.Operation try { - response = await SendRequest<SetHeaterStateRequest, SetHeaterStateResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(request); + response = await SendRequest<SetHeaterStateRequest, SetHeaterStateResponse>(request); + LogResponseReceived(response); } catch (Exception ex) { + LogRequestFailed(request, ex); throw ex; } @@ -3443,10 +2548,13 @@ namespace Tango.Integration.Operation try { - response = await SendRequest<SetBlowerStateRequest, SetBlowerStateResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(request); + response = await SendRequest<SetBlowerStateRequest, SetBlowerStateResponse>(request); + LogResponseReceived(response); } catch (Exception ex) { + LogRequestFailed(request, ex); throw ex; } @@ -3470,10 +2578,13 @@ namespace Tango.Integration.Operation try { - response = await SendRequest<SetValveStateRequest, SetValveStateResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(request); + response = await SendRequest<SetValveStateRequest, SetValveStateResponse>(request); + LogResponseReceived(response); } catch (Exception ex) { + LogRequestFailed(request, ex); throw ex; } @@ -3488,7 +2599,8 @@ namespace Tango.Integration.Operation public async Task<ResolveEventResponse> ResolveEvent(PMR.Diagnostics.EventType eventType) { ResolveEventRequest request = new ResolveEventRequest() { Type = eventType }; - return await SendRequest<ResolveEventRequest, ResolveEventResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(request); + return await SendRequest<ResolveEventRequest, ResolveEventResponse>(request); } /// <summary> @@ -3508,10 +2620,13 @@ namespace Tango.Integration.Operation Value = 0x0 }; - response = await SendRequest<StubFpgaWriteRegRequest, StubFpgaWriteRegResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(request); + response = await SendRequest<StubFpgaWriteRegRequest, StubFpgaWriteRegResponse>(request); + LogResponseReceived(response); } catch (Exception ex) { + LogRequestFailed(request, ex); throw ex; } @@ -3525,10 +2640,13 @@ namespace Tango.Integration.Operation Value = 0x1 }; - response = await SendRequest<StubFpgaWriteRegRequest, StubFpgaWriteRegResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(request); + response = await SendRequest<StubFpgaWriteRegRequest, StubFpgaWriteRegResponse>(request); + LogResponseReceived(response); } catch (Exception ex) { + LogRequestFailed(request, ex); throw ex; } @@ -3536,16 +2654,6 @@ namespace Tango.Integration.Operation } /// <summary> - /// Directs the embedded device to switch to stand-by mode. - /// </summary> - /// <returns></returns> - public async Task StandBy() - { - LogManager.Log("Switching to stand-by mode..."); - await SendRequest<StandByRequest, StandByResponse>(new StandByRequest(), new TransportRequestConfig() { ShouldLog = true }); - } - - /// <summary> /// Resets the device through the DFU channel. /// </summary> /// <returns></returns> @@ -3608,10 +2716,8 @@ namespace Tango.Integration.Operation /// Upgrades the firmware. /// </summary> /// <param name="tfpStream">The TFP stream (Tango Firmware Package File).</param> - /// <param name="isEmulated">Specify whether the connected machine is emulated and to skip the actual DFU interface.</param> /// <returns></returns> - /// <exception cref="InvalidOperationException"></exception> - public virtual async Task<FirmwareUpgradeHandler> UpgradeFirmware(Stream tfpStream, bool isEmulated = false) + public async Task<FirmwareUpgradeHandler> UpgradeFirmware(Stream tfpStream) { bool cancel = false; ZipFile zip = null; @@ -3626,60 +2732,33 @@ namespace Tango.Integration.Operation try { - LogManager.Log("Starting firmware upgrade..."); - LogManager.Log($"Firmware upgrade flags: {String.Join(", ", FirmwareUpgradeMode.GetFlags<FirmwareUpgradeModes>().Select(x => x.ToString()))}"); - - if (!CanPrint) + if (Status != MachineStatuses.ReadyToDye) { throw LogManager.Log(new InvalidOperationException($"Could not perform firmware upgrade while operator status is '{Status}'.")); } - LogManager.Log("Extracting tfp package..."); var package_info = await GetFirmwarePackageInfo(tfpStream); tfpStream.Position = 0; - LogManager.Log("Validating TFP package..."); - package_info.Validate(); - - LogManager.Log("Reading zip stream..."); zip = ZipFile.Read(tfpStream); - double packageUploadTotal = 0; - - try - { - packageUploadTotal = zip.Entries.Sum(x => x.UncompressedSize); - } - catch (Exception ex) - { - LogManager.Log(ex, "Error calculating total package upload bytes."); - } - - LogManager.Log("Creating storage manager..."); var storage = CreateStorageManager(); - LogManager.Log("Getting storage drive information..."); var drive = await storage.GetStorageDrive(); - LogManager.Log($"Storage drive info:\n{drive.ToJsonString()}"); - LogManager.Log("Getting root folder..."); var root = await storage.GetRootFolder(); - LogManager.Log($"Root folder: '{root.Path}'"); var existing_folder = root.Items.SingleOrDefault(x => x.Name == FIRMWARE_UPGRADE_FOLDER_NAME); if (existing_folder != null) { - LogManager.Log("Root folder exists. Deleting..."); await storage.DeleteItem(existing_folder); } String package_folder = Path.Combine(drive.Root, FIRMWARE_UPGRADE_FOLDER_NAME); - LogManager.Log($"Creating new folder: '{package_folder}'."); await storage.CreateFolder(package_folder); List<StorageFileHandler> handlers = new List<StorageFileHandler>(); List<ZipEntry> entries = zip.Entries.ToList(); List<Stream> streams = new List<Stream>(); - LogManager.Log("Disabling keep alive..."); var keepAlive = UseKeepAlive; UseKeepAlive = false; @@ -3702,102 +2781,49 @@ namespace Tango.Integration.Operation { if (FirmwareUpgradeMode.HasFlag(FirmwareUpgradeModes.DFU)) { - if (package_info.ContainsMcu()) - { - LogManager.Log("DFU enabled. Starting upgrade via DFU..."); - LogManager.Log("Extracting MCU file..."); - ZipEntry mcuEntry = null; - try - { - mcuEntry = entries.Single(x => x.FileName == package_info.FileDescriptors.Single(y => y.Destination == VersionFileDestination.Mcu).FileName); - entries.Remove(mcuEntry); - } - catch (Exception ex) - { - LogManager.Log(ex, "Error extracting MCU file from package."); - upgradeHandler.RaiseFailed(new IOException("Error retrieving MCU file from package.", ex)); - return; - } - - MemoryStream ms = new MemoryStream(); - mcuEntry.Extract(ms); - ms.Position = 0; - byte[] data = ms.ToArray(); - ms.Dispose(); + var mcuEntry = zip.Entries.Single(x => x.FileName == package_info.FileDescriptors.Single(y => y.Destination == VersionFileDestination.Mcu).FileName); + MemoryStream ms = new MemoryStream(); + mcuEntry.Extract(ms); + ms.Position = 0; + byte[] data = ms.ToArray(); + ms.Dispose(); - FirmwareUpgradeManager upgradeManager = new FirmwareUpgradeManager(); - upgradeManager.UpgradeProgress += (sender, e) => - { - upgradeHandler.RaiseProgress(FirmwareUpgradeStatus.Upgrading, e.State.ToDescription(), false, e.Total, e.Progress); - }; - - LogManager.Log("Disconnecting adapter..."); - Adapter.Disconnect().Wait(); + FirmwareUpgradeManager upgradeManager = new FirmwareUpgradeManager(); + upgradeManager.UpgradeProgress += (sender, e) => + { + upgradeHandler.Total = (long)e.Total; + upgradeHandler.RaiseProgress((long)e.Progress, FirmwareUpgradeStatus.Upgrading, e.State.ToDescription()); + }; - ResetEvents(); - ResetInkFllingStatus(); + Adapter.Disconnect().Wait(); - try - { - if (!isEmulated) - { - LogManager.Log("Upgrading..."); - upgradeManager.PerformUpgrade(data).Wait(); - } - else - { - LogManager.Log("Upgrading (emulated)..."); - Thread.Sleep(3000); - } - } - catch (Exception ex) - { - LogManager.Log("Firmware upgrade failed while doing DFU upload. We need to destroy the whole transport layer.", LogCategory.Error); - Status = MachineStatuses.Disconnected; - upgradeHandler.RaiseFailed(ex); - OnFailed(ex); - return; - } + if (MachineEventsStateProvider != null) + { + MachineEventsStateProvider.Reset(); + } - LogManager.Log("Waiting for the device..."); - upgradeHandler.RaiseProgress(FirmwareUpgradeStatus.Upgrading, "Waiting for the device..."); - Thread.Sleep(5000); + upgradeManager.PerformUpgrade(data).Wait(); - LogManager.Log("Reconnecting adapter..."); - upgradeHandler.RaiseProgress(FirmwareUpgradeStatus.Upgrading, "Connecting..."); - Adapter.Connect().Wait(); + upgradeHandler.RaiseProgress(100, FirmwareUpgradeStatus.Upgrading, "Waiting for the device..."); + Thread.Sleep(5000); - Connect().Wait(); + upgradeHandler.RaiseProgress(100, FirmwareUpgradeStatus.Upgrading, "Connecting..."); + Adapter.Connect().Wait(); + Connect().Wait(); - LogManager.Log("Connected..."); - upgradeHandler.RaiseProgress(FirmwareUpgradeStatus.Upgrading, "Connected."); - Thread.Sleep(2000); + upgradeHandler.RaiseProgress(100, FirmwareUpgradeStatus.Upgrading, "Connected."); + Thread.Sleep(2000); - LogManager.Log("Waiting..."); - upgradeHandler.RaiseProgress(FirmwareUpgradeStatus.Upgrading, "Waiting..."); - Thread.Sleep(2000); + upgradeHandler.RaiseProgress(100, FirmwareUpgradeStatus.Upgrading, "Waiting..."); + Thread.Sleep(2000); - Status = MachineStatuses.Upgrading; - } - else - { - LogManager.Log("DFU is enabled but no MCU file was found on the package. Skipping..."); - } + Status = MachineStatuses.Upgrading; } - //Upload tfp package only if specified in flag && package info contains more files other than the mcu bin file. if (FirmwareUpgradeMode.HasFlag(FirmwareUpgradeModes.TFP_PACKAGE)) { - if (package_info.ContainsNoneMcu()) - { - LogManager.Log("TFP package is enabled. Starting upload..."); - uploadNext(); - } - else - { - LogManager.Log("TFP package is enabled but no other files other than the MCU file were found on the package. Skipping..."); - postActivation(); - } + upgradeHandler.Total = zip.Entries.Sum(x => x.UncompressedSize); + uploadNext(); } else { @@ -3821,8 +2847,6 @@ namespace Tango.Integration.Operation var entry = entries.First(); entries.Remove(entry); - LogManager.Log($"Uploading file '{entry.FileName}'..."); - var reader = entry.OpenReader(); streams.Add(reader); @@ -3839,7 +2863,7 @@ namespace Tango.Integration.Operation return; } - upgradeHandler.RaiseProgress(FirmwareUpgradeStatus.Uploading, $"Uploading '{entry.FileName}'...", false, packageUploadTotal, upgradeHandler.Current + e.Delta); + upgradeHandler.RaiseProgress(upgradeHandler.Current + e.Delta, FirmwareUpgradeStatus.Uploading, $"Uploading '{entry.FileName}'..."); }; } catch (Exception ex) @@ -3858,12 +2882,11 @@ namespace Tango.Integration.Operation { try { - LogManager.Log("Validating version..."); streams.ForEach(x => x.Dispose()); - upgradeHandler.RaiseProgress(FirmwareUpgradeStatus.Validating, "Validating version..."); + upgradeHandler.RaiseProgress(upgradeHandler.Total, FirmwareUpgradeStatus.Validating, "Validating version..."); var validateRequest = new ValidateVersionRequest(); validateRequest.Path = package_folder; - var validateResponse = SendRequest<ValidateVersionRequest, ValidateVersionResponse>(validateRequest, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(10), ShouldLog = true }).Result; + var validateResponse = SendRequest<ValidateVersionRequest, ValidateVersionResponse>(validateRequest, TimeSpan.FromSeconds(10)).Result; activate(); } catch (Exception ex) @@ -3876,42 +2899,10 @@ namespace Tango.Integration.Operation { try { - TaskCompletionSource<object> activationCompletion = new TaskCompletionSource<object>(); - - bool completed = false; - - LogManager.Log("Activating version..."); - - upgradeHandler.RaiseProgress(FirmwareUpgradeStatus.Activating, "Activating version..."); - + upgradeHandler.RaiseProgress(upgradeHandler.Total, FirmwareUpgradeStatus.Activating, "Activating version..."); var activateRequest = new ActivateVersionRequest(); activateRequest.Path = package_folder; - - SendContinuousRequest<ActivateVersionRequest, ActivateVersionResponse>(activateRequest, new TransportContinuousRequestConfig() { Timeout = TimeSpan.FromSeconds(10), ContinuousTimeout = TimeSpan.FromSeconds(10), ShouldLog = true }) - .Subscribe((response) => - { - if (!completed && response.Message.Progress > 0) - { - upgradeHandler.RaiseProgress(FirmwareUpgradeStatus.Activating, "Activating version...", false, response.Message.Total, response.Message.Progress); - } - }, (ex) => - { - if (!completed) - { - completed = true; - activationCompletion.SetException(ex); - } - }, () => - { - if (!completed) - { - completed = true; - activationCompletion.SetResult(true); - } - }); - - var result = activationCompletion.Task.GetAwaiter().GetResult(); - + var activateResponse = SendRequest<ActivateVersionRequest, ActivateVersionResponse>(activateRequest, TimeSpan.FromSeconds(10)).Result; postActivation(); } catch (Exception ex) @@ -3922,10 +2913,8 @@ namespace Tango.Integration.Operation postActivation = new Action(() => { - LogManager.Log("Firmware upgrade completed."); upgradeHandler.RaiseCompleted(); Status = MachineStatuses.ReadyToDye; - LogManager.Log("Enabling keep alive..."); UseKeepAlive = keepAlive; }); @@ -3975,7 +2964,7 @@ namespace Tango.Integration.Operation { var validateRequest = new ValidateVersionRequest(); validateRequest.Path = path; - await SendRequest<ValidateVersionRequest, ValidateVersionResponse>(validateRequest, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(10), ShouldLog = true }); + await SendRequest<ValidateVersionRequest, ValidateVersionResponse>(validateRequest, TimeSpan.FromSeconds(10)); } /// <summary> @@ -3986,200 +2975,7 @@ namespace Tango.Integration.Operation { var activateRequest = new ActivateVersionRequest(); activateRequest.Path = path; - await SendRequest<ActivateVersionRequest, ActivateVersionResponse>(activateRequest, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(10), ShouldLog = true }); - } - - /// <summary> - /// Turns off the machine. - /// </summary> - /// <returns></returns> - public Task<PowerDownHandler> PowerDown() - { - if (_isPowerDownRequestInProgress) - { - throw new InvalidOperationException("Machine power down is already in progress."); - } - - _isPowerDownRequestInProgress = true; - - PowerDownHandler handler = new PowerDownHandler(new Task(() => - { - _isPowerDownRequestInProgress = false; - Thread.Sleep(2000); - var r = SendRequest<AbortPowerDownRequest, AbortPowerDownResponse>(new AbortPowerDownRequest(), new TransportRequestConfig() { ShouldLog = true }).Result; - })); - - Task.Factory.StartNew(() => - { - Thread.Sleep(100); - - bool firstResponse = true; - - SendContinuousRequest<StartPowerDownRequest, StartPowerDownResponse>(new StartPowerDownRequest(), new TransportContinuousRequestConfig() { ContinuousTimeout = TimeSpan.FromSeconds(2), ShouldLog = true }).ObserveOn(new NewThreadScheduler()).Subscribe((response) => - { - if (firstResponse) - { - firstResponse = false; - Status = MachineStatuses.ShuttingDown; - } - - handler.RaiseStatusChanged(response); - }, (ex) => - { - if (_isPowerDownRequestInProgress) - { - _isPowerDownRequestInProgress = false; - LogManager.Log(ex, "Power down error."); - handler.RaiseFailed(ex); - } - }, () => - { - if (_isPowerDownRequestInProgress) - { - _isPowerDownRequestInProgress = false; - handler.RaiseCompleted(); - } - }); - }); - - PowerDownStarted?.Invoke(this, new PowerDownStartedEventArgs() - { - Handler = handler, - }); - - return Task.FromResult(handler); - } - - /// <summary> - /// Turns off the machine. - /// </summary> - /// <returns></returns> - public Task<HeadCleaningHandler> PerformHeadCleaning() - { - if (_isHeadCleaningInProgress) - { - throw new InvalidOperationException("Head cleaning is already in progress."); - } - - if (!CanPrint) - { - throw new InvalidOperationException($"Cannot perform head cleaning while machine status is '{Status}'."); - } - - _isHeadCleaningInProgress = true; - bool _completed = false; - - HeadCleaningHandler handler = null; - handler = new HeadCleaningHandler(() => - { - _isHeadCleaningInProgress = false; - Thread.Sleep(1000); - - if (!_completed) - { - _completed = true; - OnHeadCleaningEnded(handler, JobRunStatus.Aborted); - } - - var r = SendRequest<AbortHeadCleaningRequest, AbortHeadCleaningResponse>(new AbortHeadCleaningRequest(), new TransportRequestConfig() { ShouldLog = true }).Result; - }); - - Task.Factory.StartNew(() => - { - Thread.Sleep(100); - - _lastJobLiquidQuantities = new List<BL.ValueObjects.JobRunLiquidQuantity>(); - _machineStatusBeforeJobStart = MachineStatus.Clone(); - - bool firstResponse = true; - _jobStartDate = DateTime.UtcNow; - - SendContinuousRequest<StartHeadCleaningRequest, StartHeadCleaningResponse>(new StartHeadCleaningRequest(), new TransportContinuousRequestConfig() { ContinuousTimeout = TimeSpan.FromSeconds(5), ShouldLog = true }).ObserveOn(new NewThreadScheduler()).Subscribe((response) => - { - if (firstResponse) - { - firstResponse = false; - } - - handler.RaiseStatusChanged(response); - }, (ex) => - { - if (!(ex is ContinuousResponseAbortedException)) - { - _isHeadCleaningInProgress = false; - LogManager.Log(ex, "Head cleaning error."); - handler.RaiseFailed(ex); - } - - if (!_completed) - { - _completed = true; - OnHeadCleaningEnded(handler, JobRunStatus.Failed); - } - }, () => - { - _isHeadCleaningInProgress = false; - handler.RaiseCompleted(); - - if (!_completed) - { - _completed = true; - OnHeadCleaningEnded(handler, JobRunStatus.Completed); - } - }); - }); - - return Task.FromResult(handler); - } - - /// <summary> - /// Starts the automatic thread loading process. - /// </summary> - /// <returns></returns> - public async Task StartThreadLoading() - { - var response = await SendRequest<TryThreadLoadingRequest, TryThreadLoadingResponse>(new TryThreadLoadingRequest()); - } - - /// <summary> - /// Continues the current thread loading. - /// </summary> - /// <param name="processParameters">The process parameters.</param> - /// <returns></returns> - public async Task ContinueThreadLoading(ProcessParametersTable processParameters) - { - var process = processParameters.ToProcessParametersPMR(); - var r = await SendRequest<ContinueThreadLoadingRequest, ContinueThreadLoadingResponse>(new ContinueThreadLoadingRequest() - { - ProcessParameters = process, - }, new TransportRequestConfig() { ShouldLog = true }); - } - - /// <summary> - /// Attempts to jog the thread in order to check whether there are no thread breaking issues. - /// </summary> - /// <returns></returns> - public async Task AttemptThreadJogging() - { - var r = await SendRequest<AttemptThreadJoggingRequest, AttemptThreadJoggingResponse>(new AttemptThreadJoggingRequest() - { - - }, new TransportRequestConfig() { ShouldLog = true, Timeout = TimeSpan.FromSeconds(20) }); - } - - /// <summary> - /// Emulates a hardware event that will last for the specified timeout. - /// </summary> - /// <param name="ev">Type of the event.</param> - /// <param name="timeout">The timeout.</param> - public async void PushEmulatedEvent(Event ev, TimeSpan timeout) - { - if (!_emulatedEvents.Exists(x => x.Type == ev.Type)) - { - _emulatedEvents.Add(ev); - await Task.Delay(timeout); - _emulatedEvents.Remove(ev); - } + await SendRequest<ActivateVersionRequest, ActivateVersionResponse>(activateRequest, TimeSpan.FromSeconds(10)); } #endregion diff --git a/Software/Visual_Studio/Tango.Integration/Operation/MachineStatuses.cs b/Software/Visual_Studio/Tango.Integration/Operation/MachineStatuses.cs index fb21b27fa..14774f73a 100644 --- a/Software/Visual_Studio/Tango.Integration/Operation/MachineStatuses.cs +++ b/Software/Visual_Studio/Tango.Integration/Operation/MachineStatuses.cs @@ -10,24 +10,22 @@ namespace Tango.Integration.Operation public enum MachineStatuses { [Description("Disconnected")] - Disconnected = 0, - [Description("Getting Ready")] - PowerUp = 1, + Disconnected, [Description("Standby")] - Standby = 2, + Standby, [Description("Ready To Dye")] - ReadyToDye = 3, + ReadyToDye, [Description("Getting Ready")] - GettingReady = 4, + GettingReady, [Description("Dyeing")] - Printing = 5, + Printing, [Description("Service")] - Service = 6, + Service, [Description("Upgrading")] - Upgrading = 7, + Upgrading, [Description("Shutting Down")] - ShuttingDown = 8, + ShuttingDown, [Description("Error")] - Error = 9, + Error, } } diff --git a/Software/Visual_Studio/Tango.Integration/Operation/PowerDownHandler.cs b/Software/Visual_Studio/Tango.Integration/Operation/PowerDownHandler.cs deleted file mode 100644 index 03593d6c6..000000000 --- a/Software/Visual_Studio/Tango.Integration/Operation/PowerDownHandler.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tango.Core; -using Tango.PMR.Power; - -namespace Tango.Integration.Operation -{ - public class PowerDownHandler : ExtendedObject - { - private Task _abortTask; - - public event EventHandler<PowerDownStatusChangedEventArgs> StatusChanged; - public event EventHandler<Exception> Failed; - public event EventHandler Completed; - - private StartPowerDownResponse _status; - public StartPowerDownResponse Status - { - get { return _status; } - set { _status = value; RaisePropertyChangedAuto(); } - } - - internal PowerDownHandler(Task abortTask) - { - _abortTask = abortTask; - - Status = new StartPowerDownResponse() - { - Message = "Powering down...", - State = PowerDownState.None, - }; - } - - internal void RaiseStatusChanged(StartPowerDownResponse status) - { - OnStatusChanged(status); - } - - internal void RaiseFailed(Exception ex) - { - OnFailed(ex); - } - - internal void RaiseCompleted() - { - OnCompleted(); - } - - private void OnStatusChanged(StartPowerDownResponse status) - { - Status = status; - StatusChanged?.Invoke(this, new PowerDownStatusChangedEventArgs() - { - Status = status - }); - } - - private void OnCompleted() - { - Completed?.Invoke(this, new EventArgs()); - } - - private void OnFailed(Exception ex) - { - Failed?.Invoke(this, ex); - } - - public async Task Abort() - { - _abortTask.Start(); - await _abortTask; - } - } -} diff --git a/Software/Visual_Studio/Tango.Integration/Operation/PowerDownStartedEventArgs.cs b/Software/Visual_Studio/Tango.Integration/Operation/PowerDownStartedEventArgs.cs deleted file mode 100644 index 7dcd4fb39..000000000 --- a/Software/Visual_Studio/Tango.Integration/Operation/PowerDownStartedEventArgs.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Tango.Integration.Operation -{ - public class PowerDownStartedEventArgs : EventArgs - { - public PowerDownHandler Handler { get; set; } - } -} diff --git a/Software/Visual_Studio/Tango.Integration/Operation/PowerDownStatusChangedEventArgs.cs b/Software/Visual_Studio/Tango.Integration/Operation/PowerDownStatusChangedEventArgs.cs deleted file mode 100644 index 5c64b41a2..000000000 --- a/Software/Visual_Studio/Tango.Integration/Operation/PowerDownStatusChangedEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tango.PMR.Power; - -namespace Tango.Integration.Operation -{ - public class PowerDownStatusChangedEventArgs : EventArgs - { - public StartPowerDownResponse Status { get; set; } - } -} diff --git a/Software/Visual_Studio/Tango.Integration/Operation/PrintingEventArgs.cs b/Software/Visual_Studio/Tango.Integration/Operation/PrintingEventArgs.cs index ff2fc4623..fe8a573a5 100644 --- a/Software/Visual_Studio/Tango.Integration/Operation/PrintingEventArgs.cs +++ b/Software/Visual_Studio/Tango.Integration/Operation/PrintingEventArgs.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Tango.BL.Entities; -using Tango.BL.ValueObjects; namespace Tango.Integration.Operation { @@ -12,16 +11,9 @@ namespace Tango.Integration.Operation { public JobHandler JobHandler { get; private set; } public Job Job { get; private set; } - public List<JobRunLiquidQuantity> LiquidQuantities { get; set; } - public DateTime StartDate { get; set; } - public DateTime? UploadingStartTime { get; set; } - public DateTime? HeatingStartTime { get; set; } - public DateTime? ActualStartTime { get; set; } - public bool IsResumed { get; set; } public PrintingEventArgs(JobHandler jobHandler, Job job) { - LiquidQuantities = new List<JobRunLiquidQuantity>(); JobHandler = jobHandler; Job = job; } diff --git a/Software/Visual_Studio/Tango.Integration/Operation/RequestFailedEventArgs.cs b/Software/Visual_Studio/Tango.Integration/Operation/RequestFailedEventArgs.cs new file mode 100644 index 000000000..e946dd0c1 --- /dev/null +++ b/Software/Visual_Studio/Tango.Integration/Operation/RequestFailedEventArgs.cs @@ -0,0 +1,22 @@ +using Google.Protobuf; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Integration.Operation +{ + public class RequestFailedEventArgs : EventArgs + { + public IMessage Message { get; set; } + + public Exception Exception { get; set; } + + public RequestFailedEventArgs(IMessage message, Exception exception) + { + Message = message; + Exception = exception; + } + } +} diff --git a/Software/Visual_Studio/Tango.Integration/Operation/ResumingJobEventArgs.cs b/Software/Visual_Studio/Tango.Integration/Operation/ResumingJobEventArgs.cs index 55728f799..6a8546350 100644 --- a/Software/Visual_Studio/Tango.Integration/Operation/ResumingJobEventArgs.cs +++ b/Software/Visual_Studio/Tango.Integration/Operation/ResumingJobEventArgs.cs @@ -9,18 +9,18 @@ namespace Tango.Integration.Operation { public class ResumingJobEventArgs : EventArgs { - private Func<JobHandler> _approveAction; + private Func<Job,JobHandler> _approveAction; public String JobGuid { get; set; } - public ResumingJobEventArgs(Func<JobHandler> approveAction) + public ResumingJobEventArgs(Func<Job, JobHandler> approveAction) { _approveAction = approveAction; } - public JobHandler Approve() + public JobHandler Approve(Job job) { - return _approveAction(); + return _approveAction(job); } } } diff --git a/Software/Visual_Studio/Tango.Integration/Operation/ThreadLoadingConfirmationRequiredEventArgs.cs b/Software/Visual_Studio/Tango.Integration/Operation/ThreadLoadingConfirmationRequiredEventArgs.cs deleted file mode 100644 index e5594dd01..000000000 --- a/Software/Visual_Studio/Tango.Integration/Operation/ThreadLoadingConfirmationRequiredEventArgs.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tango.BL.Entities; -using Tango.PMR.ThreadLoading; - -namespace Tango.Integration.Operation -{ - public class ThreadLoadingConfirmationRequiredEventArgs : EventArgs - { - private Action<ProcessParametersTable> _confirm; - - public StartThreadLoadingResponse Status { get; set; } - - internal ThreadLoadingConfirmationRequiredEventArgs(Action<ProcessParametersTable> confirm) - { - _confirm = confirm; - } - - public void Confirm(ProcessParametersTable processTable) - { - _confirm.Invoke(processTable); - } - } -} diff --git a/Software/Visual_Studio/Tango.Integration/Storage/StorageDrive.cs b/Software/Visual_Studio/Tango.Integration/Storage/StorageDrive.cs index 91dce12f5..28f390bc9 100644 --- a/Software/Visual_Studio/Tango.Integration/Storage/StorageDrive.cs +++ b/Software/Visual_Studio/Tango.Integration/Storage/StorageDrive.cs @@ -7,7 +7,7 @@ using Tango.Core; namespace Tango.Integration.Storage { - public class StorageDrive : StorageItem + public class StorageDrive : ExtendedObject { public long Capacity { get; set; } public long FreeSpace { get; set; } diff --git a/Software/Visual_Studio/Tango.Integration/Storage/StorageFileHandler.cs b/Software/Visual_Studio/Tango.Integration/Storage/StorageFileHandler.cs index 54bc7232b..eaa209e65 100644 --- a/Software/Visual_Studio/Tango.Integration/Storage/StorageFileHandler.cs +++ b/Software/Visual_Studio/Tango.Integration/Storage/StorageFileHandler.cs @@ -65,8 +65,6 @@ namespace Tango.Integration.Storage internal set { _total = value; RaisePropertyChangedAuto(); } } - public bool IsPaused { get; set; } - public Task Cancel() { return Task.Factory.StartNew(() => diff --git a/Software/Visual_Studio/Tango.Integration/Storage/StorageItem.cs b/Software/Visual_Studio/Tango.Integration/Storage/StorageItem.cs index 6894f7111..eb7e56adb 100644 --- a/Software/Visual_Studio/Tango.Integration/Storage/StorageItem.cs +++ b/Software/Visual_Studio/Tango.Integration/Storage/StorageItem.cs @@ -22,12 +22,11 @@ namespace Tango.Integration.Storage { get { return System.IO.Path.GetFileName(Path); } } - public String Parent { get { - if (Path == "/" || Path == null) return null; + if (Path == "/") return null; String root = System.IO.Path.GetPathRoot(Path); var parent = Directory.GetParent(Path); diff --git a/Software/Visual_Studio/Tango.Integration/Storage/StorageManager.cs b/Software/Visual_Studio/Tango.Integration/Storage/StorageManager.cs index 5dd975463..7db7433fa 100644 --- a/Software/Visual_Studio/Tango.Integration/Storage/StorageManager.cs +++ b/Software/Visual_Studio/Tango.Integration/Storage/StorageManager.cs @@ -5,7 +5,6 @@ using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Text; -using System.Threading; using System.Threading.Tasks; using Tango.Core; using Tango.Core.Commands; @@ -89,6 +88,37 @@ namespace Tango.Integration.Storage #endregion + #region Protected Methods + + /// <summary> + /// Logs the request sent. + /// </summary> + /// <param name="message">The message.</param> + protected void LogRequestSent(IMessage message) + { + LogManager.Log(String.Format("Sending request '{0}'...{1}{2}", message.GetType().Name, Environment.NewLine, message.ToJsonString()), LogCategory.Debug); + } + + /// <summary> + /// Logs the request failed. + /// </summary> + /// <param name="message">The message.</param> + protected void LogRequestFailed(IMessage message, Exception ex) + { + LogManager.Log(String.Format("Request failed '{0}'...{1}{2}{1}{3}", message.GetType().Name, Environment.NewLine, message.ToJsonString(), ex.ToString()), LogCategory.Error); + } + + /// <summary> + /// Logs the response received. + /// </summary> + /// <param name="message">The message.</param> + protected void LogResponseReceived(IMessage message) + { + LogManager.Log(String.Format("Response received '{0}'...{1}{2}", message.GetType().Name, Environment.NewLine, message.ToJsonString()), LogCategory.Debug); + } + + #endregion + #region Public Methods /// <summary> @@ -104,10 +134,11 @@ namespace Tango.Integration.Storage try { - response = await _transporter.SendRequest<GetStorageInfoRequest, GetStorageInfoResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + response = await _transporter.SendRequest<GetStorageInfoRequest, GetStorageInfoResponse>(request); } catch (Exception ex) { + LogRequestFailed(request, ex); throw ex; } @@ -158,10 +189,11 @@ namespace Tango.Integration.Storage try { - response = await _transporter.SendRequest<GetFilesRequest, GetFilesResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + response = await _transporter.SendRequest<GetFilesRequest, GetFilesResponse>(request); } catch (Exception ex) { + LogRequestFailed(request, ex); throw ex; } @@ -214,7 +246,7 @@ namespace Tango.Integration.Storage request.Path = path; request.Length = stream.Length; - var fileUploadResponse = await _transporter.SendRequest<FileUploadRequest, FileUploadResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + var fileUploadResponse = await _transporter.SendRequest<FileUploadRequest, FileUploadResponse>(request); String uploadId = fileUploadResponse.Message.UploadID; long max_length = fileUploadResponse.Message.MaxChunkLength; @@ -246,31 +278,24 @@ namespace Tango.Integration.Storage { if (!canceled) { - if (!handler.IsPaused) - { - byte[] buffer = new byte[Math.Min(max_length, stream.Length - stream.Position)]; - stream.Read(buffer, 0, buffer.Length); + byte[] buffer = new byte[Math.Min(max_length, stream.Length - stream.Position)]; + stream.Read(buffer, 0, buffer.Length); - FileChunkUploadRequest chunk = new FileChunkUploadRequest(); - chunk.UploadID = uploadId; - chunk.Path = path; - chunk.Buffer = ByteString.CopyFrom(buffer); + FileChunkUploadRequest chunk = new FileChunkUploadRequest(); + chunk.UploadID = uploadId; + chunk.Path = path; + chunk.Buffer = ByteString.CopyFrom(buffer); - var chunk_response = _transporter.SendRequest<FileChunkUploadRequest, FileChunkUploadResponse>(chunk, new TransportRequestConfig() { Priority = QueuePriority.Low }).Result; + var chunk_response = _transporter.SendRequest<FileChunkUploadRequest, FileChunkUploadResponse>(chunk).Result; - if (chunk_response.Message.IsCanceled) - { - canceled = true; - handler.RaiseFailed(new IOException("The storage device controller has canceled the current upload.")); - return; - } - - handler.Current = stream.Position; - } - else + if (chunk_response.Message.IsCanceled) { - Thread.Sleep(100); + canceled = true; + handler.RaiseFailed(new IOException("The storage device controller has canceled the current upload.")); + return; } + + handler.Current = stream.Position; } else { @@ -337,7 +362,7 @@ namespace Tango.Integration.Storage FileDownloadRequest request = new FileDownloadRequest(); request.FileName = file.Path; - var fileDownloadResponse = await _transporter.SendRequest<FileDownloadRequest, FileDownloadResponse>(request, new TransportRequestConfig() { ShouldLog = true }); + var fileDownloadResponse = await _transporter.SendRequest<FileDownloadRequest, FileDownloadResponse>(request); String download_id = fileDownloadResponse.Message.DownloadID; long max_length = fileDownloadResponse.Message.MaxChunkLength; @@ -358,32 +383,25 @@ namespace Tango.Integration.Storage { if (!canceled) { - if (!handler.IsPaused) - { - FileChunkDownloadRequest chunk = new FileChunkDownloadRequest(); - chunk.DownloadID = download_id; - chunk.FileName = file.Path; - chunk.Position = stream.Length; + FileChunkDownloadRequest chunk = new FileChunkDownloadRequest(); + chunk.DownloadID = download_id; + chunk.FileName = file.Path; + chunk.Position = stream.Length; - var chunk_response = _transporter.SendRequest<FileChunkDownloadRequest, FileChunkDownloadResponse>(chunk, new TransportRequestConfig() { Priority = QueuePriority.Low }).Result; + var chunk_response = _transporter.SendRequest<FileChunkDownloadRequest, FileChunkDownloadResponse>(chunk).Result; - if (chunk_response.Message.IsCanceled) - { - canceled = true; - handler.RaiseFailed(new IOException("The storage device controller has canceled the current download.")); - return; - } + if (chunk_response.Message.IsCanceled) + { + canceled = true; + handler.RaiseFailed(new IOException("The storage device controller has canceled the current download.")); + return; + } - byte[] buffer = chunk_response.Message.Buffer.ToByteArray(); - stream.Write(buffer, 0, buffer.Length); + byte[] buffer = chunk_response.Message.Buffer.ToByteArray(); + stream.Write(buffer, 0, buffer.Length); - handler.Current = stream.Length; - } - else - { - Thread.Sleep(100); - } + handler.Current = stream.Length; } else { @@ -418,7 +436,7 @@ namespace Tango.Integration.Storage { Path = item.Path, Attribute = item.Attribute, - }, new TransportRequestConfig() { ShouldLog = true }); + }); } /// <summary> @@ -432,7 +450,7 @@ namespace Tango.Integration.Storage { Path = path, Attribute = FileAttribute.Directory, - }, new TransportRequestConfig() { ShouldLog = true }); + }); } #endregion diff --git a/Software/Visual_Studio/Tango.Integration/Tango.Integration.csproj b/Software/Visual_Studio/Tango.Integration/Tango.Integration.csproj index 591cd282a..6b8d4ee8d 100644 --- a/Software/Visual_Studio/Tango.Integration/Tango.Integration.csproj +++ b/Software/Visual_Studio/Tango.Integration/Tango.Integration.csproj @@ -42,9 +42,6 @@ <Reference Include="Ionic.Zip, Version=1.9.1.8, Culture=neutral, PublicKeyToken=edbe51ad942a3f5c, processorArchitecture=MSIL"> <HintPath>..\packages\Ionic.Zip.1.9.1.8\lib\Ionic.Zip.dll</HintPath> </Reference> - <Reference Include="Microsoft.AspNet.SignalR.Client, Version=2.4.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> - <HintPath>..\packages\Microsoft.AspNet.SignalR.Client.2.4.1\lib\net45\Microsoft.AspNet.SignalR.Client.dll</HintPath> - </Reference> <Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> <HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath> </Reference> @@ -54,7 +51,6 @@ <Reference Include="System.ComponentModel.DataAnnotations" /> <Reference Include="System.Core" /> <Reference Include="System.Management" /> - <Reference Include="System.Net.Http.WebRequest" /> <Reference Include="System.Reactive.Core, Version=3.0.3000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL"> <HintPath>..\packages\System.Reactive.Core.3.1.1\lib\net46\System.Reactive.Core.dll</HintPath> </Reference> @@ -99,39 +95,20 @@ <Compile Include="ExtensionMethods\IExternalBridgeClientExtensions.cs" /> <Compile Include="ExternalBridge\ColorProfileRequestEventArgs.cs" /> <Compile Include="ExternalBridge\ExternalBridgeClientConnectedEventArgs.cs" /> - <Compile Include="ExternalBridge\ExternalBridgeReceiver.cs" /> - <Compile Include="ExternalBridge\ExternalBridgeReceiverLoginRequestEventArgs.cs" /> - <Compile Include="ExternalBridge\ExternalBridgeReceiverRequestReceivedEventArgs.cs" /> - <Compile Include="ExternalBridge\ExternalBridgeRequestHandlerMethodAttribute.cs" /> - <Compile Include="ExternalBridge\IExternalBridgeRequestHandler.cs" /> - <Compile Include="ExternalBridge\ExternalBridgeSignalRConfiguration.cs" /> - <Compile Include="ExternalBridge\ExternalBridgeSignalRClient.cs" /> - <Compile Include="ExternalBridge\RequestHandlerLoggingMode.cs" /> - <Compile Include="ExternalBridge\Web\MachineInfo.cs" /> <Compile Include="IntegrationSettings.cs" /> <Compile Include="JobRuns\BasicJobRunsLogger.cs" /> <Compile Include="JobRuns\IJobRunsLogger.cs" /> <Compile Include="Logging\EmbeddedLogFileParser.cs" /> - <Compile Include="Operation\CachedJobOperation.cs" /> <Compile Include="Operation\CartridgeValidationEventArgs.cs" /> <Compile Include="Operation\DefaultMachineEventsStateProvider.cs" /> <Compile Include="Logging\EmbeddedLogItem.cs" /> <Compile Include="Operation\DefaultGradientGenerationConfiguration.cs" /> - <Compile Include="Operation\HeadCleaningEndedEventArgs.cs" /> - <Compile Include="Operation\HeadCleaningHandler.cs" /> - <Compile Include="Operation\HeadCleaningStatusChangedEventArgs.cs" /> <Compile Include="Operation\IGradientGenerationConfiguration.cs" /> - <Compile Include="Operation\InkFillingStatusChangedEventArgs.cs" /> <Compile Include="Operation\InsufficientLiquidQuantityException.cs" /> <Compile Include="Operation\JobDescriptionFile.cs" /> - <Compile Include="Operation\JobLiquidQuantityCalculationMode.cs" /> <Compile Include="Operation\JobUnitsMethods.cs" /> - <Compile Include="Operation\PowerDownHandler.cs" /> - <Compile Include="Operation\PowerDownStartedEventArgs.cs" /> - <Compile Include="Operation\PowerDownStatusChangedEventArgs.cs" /> <Compile Include="Operation\PreparingJobProgressEventArgs.cs" /> <Compile Include="Operation\SpoolChangeRequiredEventArgs.cs" /> - <Compile Include="Operation\ThreadLoadingConfirmationRequiredEventArgs.cs" /> <Compile Include="Upgrade\FirmwareUpgradeHandler.cs" /> <Compile Include="Upgrade\FirmwareUpgradeModes.cs" /> <Compile Include="Upgrade\FirmwareUpgradeProgressEventArgs.cs" /> @@ -144,6 +121,7 @@ <Compile Include="Operation\JobHandler.cs" /> <Compile Include="Operation\MachineStatuses.cs" /> <Compile Include="Operation\PrintingEventArgs.cs" /> + <Compile Include="Operation\RequestFailedEventArgs.cs" /> <Compile Include="Operation\ResumingJobEventArgs.cs" /> <Compile Include="Operation\RunningJobStatus.cs" /> <Compile Include="ExternalBridge\ExternalBridgeScanner.cs" /> @@ -204,10 +182,6 @@ <Project>{d8f1ad85-526a-4f50-b6dc-d437af63d8d8}</Project> <Name>Tango.Settings</Name> </ProjectReference> - <ProjectReference Include="..\Tango.SystemInfo\Tango.SystemInfo.csproj"> - <Project>{997a961c-beda-4b56-aa0f-c39e532f7ffa}</Project> - <Name>Tango.SystemInfo</Name> - </ProjectReference> <ProjectReference Include="..\Tango.Transport\Tango.Transport.csproj"> <Project>{74e700b0-1156-4126-be40-ee450d3c3026}</Project> <Name>Tango.Transport</Name> diff --git a/Software/Visual_Studio/Tango.Integration/Upgrade/FirmwareUpgradeHandler.cs b/Software/Visual_Studio/Tango.Integration/Upgrade/FirmwareUpgradeHandler.cs index dd42693c4..774824b49 100644 --- a/Software/Visual_Studio/Tango.Integration/Upgrade/FirmwareUpgradeHandler.cs +++ b/Software/Visual_Studio/Tango.Integration/Upgrade/FirmwareUpgradeHandler.cs @@ -19,8 +19,6 @@ namespace Tango.Integration.Upgrade internal FirmwareUpgradeHandler() { - IsIndeterminate = true; - Total = 100; Message = "Initializing..."; } @@ -43,8 +41,8 @@ namespace Tango.Integration.Upgrade private set { _status = value; RaisePropertyChangedAuto(); } } - private double _current; - public double Current + private long _current; + public long Current { get { return _current; } internal set @@ -53,20 +51,13 @@ namespace Tango.Integration.Upgrade } } - private double _total; - public double Total + private long _total; + public long Total { get { return _total; } internal set { _total = value; RaisePropertyChangedAuto(); } } - private bool _isIndeterminate; - public bool IsIndeterminate - { - get { return _isIndeterminate; } - set { _isIndeterminate = value; RaisePropertyChangedAuto(); } - } - public Task Cancel() { return Task.Factory.StartNew(() => @@ -80,27 +71,28 @@ namespace Tango.Integration.Upgrade internal void RaiseCompleted() { - RaiseProgress(FirmwareUpgradeStatus.Completed, "Firmware upgrade completed.", false, 100, 100); + Status = FirmwareUpgradeStatus.Completed; + Message = "Completed."; Completed?.Invoke(this, new EventArgs()); } internal void RaiseCanceled() { - RaiseProgress(FirmwareUpgradeStatus.Canceled, "Firmware upgrade canceled by user.", false, 100, 0); + Status = FirmwareUpgradeStatus.Canceled; + Message = "Canceled."; Canceled?.Invoke(this, new EventArgs()); } internal void RaiseFailed(Exception ex) { - RaiseProgress(FirmwareUpgradeStatus.Failed, "Firmware upgrade failed.", false, 100, 0); + Status = FirmwareUpgradeStatus.Failed; + Message = "Failed."; Failed?.Invoke(this, ex); } - internal void RaiseProgress(FirmwareUpgradeStatus status, String message, bool isIndeterminate = true, double total = 100, double current = 0) + internal void RaiseProgress(long current, FirmwareUpgradeStatus status, String message) { - Total = total; Current = current; - IsIndeterminate = isIndeterminate; Status = status; Message = message; @@ -110,7 +102,6 @@ namespace Tango.Integration.Upgrade Status = Status, Total = Total, Message = Message, - IsIndeterminate = IsIndeterminate }); } } diff --git a/Software/Visual_Studio/Tango.Integration/Upgrade/FirmwareUpgradeProgressEventArgs.cs b/Software/Visual_Studio/Tango.Integration/Upgrade/FirmwareUpgradeProgressEventArgs.cs index 8315f4026..fa4f4cc96 100644 --- a/Software/Visual_Studio/Tango.Integration/Upgrade/FirmwareUpgradeProgressEventArgs.cs +++ b/Software/Visual_Studio/Tango.Integration/Upgrade/FirmwareUpgradeProgressEventArgs.cs @@ -8,9 +8,8 @@ namespace Tango.Integration.Upgrade { public class FirmwareUpgradeProgressEventArgs : EventArgs { - public double Current { get; set; } - public double Total { get; set; } - public bool IsIndeterminate { get; set; } + public long Current { get; set; } + public long Total { get; set; } public FirmwareUpgradeStatus Status { get; set; } public String Message { get; set; } } diff --git a/Software/Visual_Studio/Tango.Integration/packages.config b/Software/Visual_Studio/Tango.Integration/packages.config index 542b7a059..56f5092b2 100644 --- a/Software/Visual_Studio/Tango.Integration/packages.config +++ b/Software/Visual_Studio/Tango.Integration/packages.config @@ -3,7 +3,6 @@ <package id="EntityFramework" version="6.2.0" targetFramework="net461" /> <package id="Google.Protobuf" version="3.4.1" targetFramework="net46" /> <package id="Ionic.Zip" version="1.9.1.8" targetFramework="net461" /> - <package id="Microsoft.AspNet.SignalR.Client" version="2.4.1" targetFramework="net461" /> <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" /> <package id="System.Reactive" version="3.1.1" targetFramework="net46" /> <package id="System.Reactive.Core" version="3.1.1" targetFramework="net46" /> |
