aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.PMR/Printing/JobSegment.cs
blob: 86f95bd31b37b354c591fbc5678be61bbe29f836 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// Generated by the protocol buffer compiler.  DO NOT EDIT!
// source: JobSegment.proto
#pragma warning disable 1591, 0612, 3021
#region Designer generated code

using pb = global::Google.Protobuf;
using pbc = global::Google.Protobuf.Collections;
using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
namespace Tango.PMR.Printing {

  /// <summary>Holder for reflection information generated from JobSegment.proto</summary>
  public static partial class JobSegmentReflection {

    #region Descriptor
    /// <summary>File descriptor for JobSegment.proto</summary>
    public static pbr::FileDescriptor Descriptor {
      get { return descriptor; }
    }
    private static pbr::FileDescriptor descriptor;

    static JobSegmentReflection() {
      byte[] descriptorData = global::System.Convert.FromBase64String(
          string.Concat(
            "ChBKb2JTZWdtZW50LnByb3RvEhJUYW5nby5QTVIuUHJpbnRpbmcaEkpvYkJy",
            "dXNoU3RvcC5wcm90byJgCgpKb2JTZWdtZW50EgwKBE5hbWUYASABKAkSDgoG",
            "TGVuZ3RoGAIgASgBEjQKCkJydXNoU3RvcHMYAyADKAsyIC5UYW5nby5QTVIu",
            "UHJpbnRpbmcuSm9iQnJ1c2hTdG9wQh4KHGNvbS50d2luZS50YW5nby5wbXIu",
            "cHJpbnRpbmdiBnByb3RvMw=="));
      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
          new pbr::FileDescriptor[] { global::Tango.PMR.Printing.JobBrushStopReflection.Descriptor, },
          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
            new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Printing.JobSegment), global::Tango.PMR.Printing.JobSegment.Parser, new[]{ "Name", "Length", "BrushStops" }, null, null, null)
          }));
    }
    #endregion

  }
  #region Messages
  public sealed partial class JobSegment : pb::IMessage<JobSegment> {
    private static readonly pb::MessageParser<JobSegment> _parser = new pb::MessageParser<JobSegment>(() => new JobSegment());
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public static pb::MessageParser<JobSegment> Parser { get { return _parser; } }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public static pbr::MessageDescriptor Descriptor {
      get { return global::Tango.PMR.Printing.JobSegmentReflection.Descriptor.MessageTypes[0]; }
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    pbr::MessageDescriptor pb::IMessage.Descriptor {
      get { return Descriptor; }
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public JobSegment() {
      OnConstruction();
    }

    partial void OnConstruction();

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public JobSegment(JobSegment other) : this() {
      name_ = other.name_;
      length_ = other.length_;
      brushStops_ = other.brushStops_.Clone();
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public JobSegment Clone() {
      return new JobSegment(this);
    }

    /// <summary>Field number for the "Name" field.</summary>
    public const int NameFieldNumber = 1;
    private string name_ = "";
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public string Name {
      get { return name_; }
      set {
        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
      }
    }

    /// <summary>Field number for the "Length" field.</summary>
    public const int LengthFieldNumber = 2;
    private double length_;
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public double Length {
      get { return length_; }
      set {
        length_ = value;
      }
    }

    /// <summary>Field number for the "BrushStops" field.</summary>
    public const int BrushStopsFieldNumber = 3;
    private static readonly pb::FieldCodec<global::Tango.PMR.Printing.JobBrushStop> _repeated_brushStops_codec
        = pb::FieldCodec.ForMessage(26, global::Tango.PMR.Printing.JobBrushStop.Parser);
    private readonly pbc::RepeatedField<global::Tango.PMR.Printing.JobBrushStop> brushStops_ = new pbc::RepeatedField<global::Tango.PMR.Printing.JobBrushStop>();
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public pbc::RepeatedField<global::Tango.PMR.Printing.JobBrushStop> BrushStops {
      get { return brushStops_; }
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public override bool Equals(object other) {
      return Equals(other as JobSegment);
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public bool Equals(JobSegment other) {
      if (ReferenceEquals(other, null)) {
        return false;
      }
      if (ReferenceEquals(other, this)) {
        return true;
      }
      if (Name != other.Name) return false;
      if (Length != other.Length) return false;
      if(!brushStops_.Equals(other.brushStops_)) return false;
      return true;
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public override int GetHashCode() {
      int hash = 1;
      if (Name.Length != 0) hash ^= Name.GetHashCode();
      if (Length != 0D) hash ^= Length.GetHashCode();
      hash ^= brushStops_.GetHashCode();
      return hash;
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public override string ToString() {
      return pb::JsonFormatter.ToDiagnosticString(this);
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public void WriteTo(pb::CodedOutputStream output) {
      if (Name.Length != 0) {
        output.WriteRawTag(10);
        output.WriteString(Name);
      }
      if (Length != 0D) {
        output.WriteRawTag(17);
        output.WriteDouble(Length);
      }
      brushStops_.WriteTo(output, _repeated_brushStops_codec);
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public int CalculateSize() {
      int size = 0;
      if (Name.Length != 0) {
        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
      }
      if (Length != 0D) {
        size += 1 + 8;
      }
      size += brushStops_.CalculateSize(_repeated_brushStops_codec);
      return size;
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public void MergeFrom(JobSegment other) {
      if (other == null) {
        return;
      }
      if (other.Name.Length != 0) {
        Name = other.Name;
      }
      if (other.Length != 0D) {
        Length = other.Length;
      }
      brushStops_.Add(other.brushStops_);
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public void MergeFrom(pb::CodedInputStream input) {
      uint tag;
      while ((tag = input.ReadTag()) != 0) {
        switch(tag) {
          default:
            input.SkipLastField();
            break;
          case 10: {
            Name = input.ReadString();
            break;
          }
          case 17: {
            Length = input.ReadDouble();
            break;
          }
          case 26: {
            brushStops_.AddEntriesFrom(input, _repeated_brushStops_codec);
            break;
          }
        }
      }
    }

  }

  #endregion

}

#endregion Designer generated code
using Google.Protobuf;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tango.Transport.Servers;
using Tango.Logging;
using Tango.PMR;
using Tango.PMR.Common;
using Tango.PMR.Stubs;
using Tango.Core.Commands;
using Tango.Transport;
using Tango.PMR.Integration;
using Tango.PMR.Diagnostics;
using System.Windows.Forms;
using Google.Protobuf.Collections;
using Tango.PMR.Printing;
using Tango.BL.Entities;
using Tango.PMR.Debugging;
using Tango.BL.Enumerations;
using Tango.BL;
using Tango.PMR.Connection;
using Tango.PMR.Hardware;
using System.Runtime.InteropServices;
using Tango.PMR.IO;
using System.IO;
using Tango.Integration.Operation;
using Tango.PMR.FirmwareUpgrade;
using System.Diagnostics;
using Tango.Core.ExtensionMethods;
using Tango.PMR.MachineStatus;
using Tango.PMR.Power;
using Tango.PMR.ThreadLoading;
using Tango.PMR.IFS;
using Tango.PMR.DataStore;

namespace Tango.Emulations.Emulators
{
    /// <summary>
    /// Represents a Tango machine emulator.
    /// </summary>
    /// <seealso cref="Tango.Emulations.EmulatorBase" />
    public class MachineEmulator : EmulatorBase
    {
        [DllImport("Tango.Emulations.Native.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "ProcessMessage")]
        public static extern int ProcessMessageNative(IntPtr data, int size, ref IntPtr output);

        private class ContinousResponseToken
        {
            public bool Canceled { get; set; }
        }

        private const int MAX_CHUNK_LENGTH = 4000;
        private const int DIAGNOSTICS_INTERVAL = 300;
        private static Random _rnd = new Random();
        private StartDiagnosticsRequest _diagnosticsRequest;
        private bool _cancelJob;
        private List<PMR.Hardware.HardwareMotorType> _motorJoggingRequestTypes;
        private List<PMR.Hardware.HardwareMotorType> _motorHomingRequestCodes;
        private List<int> _dispenserJoggingRequestCodes;
        private List<int> _dispenserHomingRequestCodes;
        private double _graphAmplitude;
        private double _graphFrequency;
        private List<DigitalInterfaceState> _digitalOutputPinsStates;
        private List<DigitalInterfaceState> _digitalInputPinsStates;
        private List<ValueComponentState> _componentsStates;
        private List<HeaterState> _heater_states;
        private List<ContinousResponseToken> _continousResponseTokens;
        public List<MachineEventState> EventsStates { get; set; }
        private bool _diagnostics_enabled;
        private bool _debug_logs_enabled;
        private bool _events_enabled;
        private bool _machine_updates_enabled;
        private List<SetBlowerStateRequest> _blower_states;
        private List<ValveState> _valveStates;
        private JobTicket _current_job_ticket;
        private String _current_job_resume_token;
        private FileUploadRequest _lastFileUploadRequest;
        private bool _isAfterReset;
        private bool _abortPowerDown;
        private bool _isThreadLoadingStarted;
        private String _threadLoadingToken;
        private DateTime _connectionTime;
        private int _jobAbortCounter;
        private bool _abortHeadCleaning;
        private String _machineStatusRequestToken;

        #region Properties

        private bool _performNativeRoundTrip;
        /// <summary>
        /// Gets or sets a value indicating whether [perform native round trip].
        /// </summary>
        public bool PerformNativeRoundTrip
        {
            get { return _performNativeRoundTrip; }
            set { _performNativeRoundTrip = value; RaisePropertyChangedAuto(); }
        }

        private bool _emulateCorruption;
        /// <summary>
        /// Gets or sets a value indicating whether emulate corruption in keep alive and job response.
        /// </summary>
        public bool EmulateCorruption
        {
            get { return _emulateCorruption; }
            set
            {
                _emulateCorruption = value;
                RaisePropertyChangedAuto();
                Transporter.EnableKeepAliveAutoResponse = !_emulateCorruption;
            }
        }

        public MachineStatus MachineStatus { get; set; }

        public InkFillingStatus InkFillingStatus { get; set; }

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="MachineEmulator"/> class.
        /// </summary>
        public MachineEmulator() : base()
        {
            Init();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="MachineEmulator"/> class.
        /// </summary>
        /// <param name="transporter">The transporter.</param>
        public MachineEmulator(ITransporter transporter) : base(transporter)
        {
            transporter.ComponentName = $"Machine Emulator";
            LogManager.Log("Machine emulator initialized using transporter " + transporter.ToString());
            Init();
        }

        #endregion

        #region Private Methods

        private ContinousResponseToken CreateCancelToken()
        {
            ContinousResponseToken t = new ContinousResponseToken();
            _continousResponseTokens.Add(t);
            return t;
        }

        private void Init()
        {
            _isAfterReset = true;
            MachineStatus = new MachineStatus();
            MachineStatus.SpoolState = SpoolState.Present;
            MachineStatus.State = MachineState.Ready;

            for (int i = 0; i < 10; i++)
            {
                MachineStatus.IDSPacksLevels.Add(new IDSPackLevel()
                {
                    Index = i,
                    DispenserLevel = 130000000,
                    MidTankLevel = 2500,
                });
            }

            EventsStates = MachineEventState.GetAllEventsStates();

            _valveStates = new List<ValveState>();
            _blower_states = new List<SetBlowerStateRequest>();
            _heater_states = new List<HeaterState>();
            _continousResponseTokens = new List<ContinousResponseToken>();
            _motorJoggingRequestTypes = new List<PMR.Hardware.HardwareMotorType>();
            _motorHomingRequestCodes = new List<PMR.Hardware.HardwareMotorType>();
            _dispenserJoggingRequestCodes = new List<int>();
            _dispenserHomingRequestCodes = new List<int>();
            _digitalOutputPinsStates = new List<DigitalInterfaceState>();
            _componentsStates = new List<ValueComponentState>();

            ObservablesStaticCollections adapter = ObservablesStaticCollections.Instance;
            adapter.Initialize();

            _digitalOutputPinsStates = adapter.TechIos.Where(x => x.Type == IOType.DigitalOutput.ToInt32()).Select(x => new DigitalInterfaceState()
            {
                InterfaceIO = (InterfaceIOs)x.Code,
            }).ToList();

            _digitalInputPinsStates = adapter.TechIos.Where(x => x.Type == IOType.DigitalInput.ToInt32()).Select(x => new DigitalInterfaceState()
            {
                InterfaceIO = (InterfaceIOs)x.Code,
            }).ToList();

            foreach (var item in adapter.TechControllers)
            {
                _componentsStates.Add(new ValueComponentState()
                {
                    Component = (ValueComponent)item.Code,
                    Value = item.Min
                });
            }

            foreach (var item in adapter.TechHeaters)
            {
                _heater_states.Add(new HeaterState()
                {
                    HeaterType = (HeaterType)item.Code,
                });
            }

            foreach (var item in adapter.HardwareBlowerTypes)
            {
                _blower_states.Add(new SetBlowerStateRequest()
                {
                    BlowerType = (PMR.Hardware.HardwareBlowerType)item.Code,
                });
            }

            foreach (var item in adapter.TechValves)
            {
                _valveStates.Add(new ValveState()
                {
                    ValveType = (ValveType)item.Code,
                    State = (ValveStateCode)Enum.Parse(typeof(ValveStateCode), item.State1.Replace(" ", ""), true),
                });
            }

            ResetGraphFactors();

            InkFillingStatus = new InkFillingStatus();

            for (int i = 0; i < 8; i++)
            {
                InkFillingStatus.CartridgesStatuses.Add(new CartridgeStatus()
                {
                    Cartridge = new Cartridge()
                    {
                        Index = i,
                        Slot = CartridgeSlot.Ink,
                    },
                    State = CartridgeState.Present,
                    Message = "This is an emulated ink filling message"
                });
            }

            InkFillingStatus.CartridgesStatuses.Add(new CartridgeStatus()
            {
                Cartridge = new Cartridge() { Index = 0, Slot = CartridgeSlot.WasteMiddle },
                State = CartridgeState.Present,
                Message = "This is an emulated waste emptying message"
            });

            InkFillingStatus.CartridgesStatuses.Add(new CartridgeStatus()
            {
                Cartridge = new Cartridge() { Index = 1, Slot = CartridgeSlot.WasteLower },
                State = CartridgeState.Present,
                Message = "This is an emulated waste emptying message"
            });
        }

        private void ResetGraphFactors()
        {
            _graphAmplitude = 75;
            _graphFrequency = 1;
        }

        #endregion

        #region Override Methods

        public override Task Start()
        {
            _isAfterReset = true;
            return base.Start();
        }

        /// <summary>
        /// Called on new request message.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="container">The container.</param>
        protected override void OnTransporterRequestReceived(object sender, RequestReceivedEventArgs e)
        {
            var container = e.Container;

            if (container.Type != MessageType.FileChunkUploadRequest && container.Type != MessageType.FileChunkDownloadRequest)
            {
                LogManager.Log(container.Type.ToString().ToWords() + " received." + Environment.NewLine + MessageFactory.ExtractMessageFromContainer(container).ToJsonString());
            }

            if (PerformNativeRoundTrip)
            {
                NativePMR<MessageContainer, MessageContainer> nativePMR = new NativePMR<MessageContainer, MessageContainer>(ProcessMessageNative);
                var response = nativePMR.Invoke(container);

                if (response != null)
                {
                    container = response;
                }
                else
                {
                    LogManager.Log("Native RoundTrip is not available for " + container.Type.ToString() + ".");
                }
            }

            switch (container.Type)
            {
                case MessageType.CalculateRequest:
                    HandleCalculateRequest(MessageFactory.ParseTangoMessageFromContainer<CalculateRequest>(container));
                    break;
                case MessageType.ProgressRequest:
                    HandleProgressRequest(MessageFactory.ParseTangoMessageFromContainer<ProgressRequest>(container));
                    break;
                case MessageType.StartDiagnosticsRequest:
                    HandleStartDiagnosticsRequest(MessageFactory.ParseTangoMessageFromContainer<StartDiagnosticsRequest>(container));
                    break;
                case MessageType.StopDiagnosticsRequest:
                    HandleStopDiagnosticsRequest(MessageFactory.ParseTangoMessageFromContainer<StopDiagnosticsRequest>(container));
                    break;
                case MessageType.StartEventsNotificationRequest:
                    HandleStartEventsNotificationRequest(MessageFactory.ParseTangoMessageFromContainer<StartEventsNotificationRequest>(container));
                    break;
                case MessageType.StopEventsNotificationRequest:
                    HandleStopEventsNotificationRequest(MessageFactory.ParseTangoMessageFromContainer<StopEventsNotificationRequest>(container));
                    break;
                case MessageType.StartMachineStatusUpdateRequest:
                    HandleStartMachineStatusUpdateRequest(MessageFactory.ParseTangoMessageFromContainer<StartMachineStatusUpdateRequest>(container));
                    break;
                case MessageType.StopMachineStatusUpdateRequest:
                    HandleStopMachineStatusUpdateRequest(MessageFactory.ParseTangoMessageFromContainer<StopMachineStatusUpdateRequest>(container));
                    break;
                case MessageType.JobRequest:
                    HandleJobRequest(MessageFactory.ParseTangoMessageFromContainer<JobRequest>(container));
                    break;
                case MessageType.AbortJobRequest:
                    HandleAbortJobRequest(MessageFactory.ParseTangoMessageFromContainer<AbortJobRequest>(container));
                    break;
                case MessageType.MotorJoggingRequest:
                    HandleMotorJoggingRequest(MessageFactory.ParseTangoMessageFromContainer<MotorJoggingRequest>(container));
                    break;
                case MessageType.MotorAbortJoggingRequest:
                    HandleAbortMotorJoggingRequest(MessageFactory.ParseTangoMessageFromContainer<MotorAbortJoggingRequest>(container));
                    break;
                case MessageType.MotorHomingRequest:
                    HandleMotorHomingRequest(MessageFactory.ParseTangoMessageFromContainer<MotorHomingRequest>(container));
                    break;
                case MessageType.MotorAbortHomingRequest:
                    HandleAbortMotorHomingRequest(MessageFactory.ParseTangoMessageFromContainer<MotorAbortHomingRequest>(container));
                    break;
                case MessageType.DispenserJoggingRequest:
                    HandleDispenserJoggingRequest(MessageFactory.ParseTangoMessageFromContainer<DispenserJoggingRequest>(container));
                    break;
                case MessageType.DispenserAbortJoggingRequest:
                    HandleAbortDispenserJoggingRequest(MessageFactory.ParseTangoMessageFromContainer<DispenserAbortJoggingRequest>(container));
                    break;
                case MessageType.DispenserHomingRequest:
                    HandleDispenserHomingRequest(MessageFactory.ParseTangoMessageFromContainer<DispenserHomingRequest>(container));
                    break;
                case MessageType.DispenserAbortHomingRequest:
                    HandleAbortDispenserHomingRequest(MessageFactory.ParseTangoMessageFromContainer<DispenserAbortHomingRequest>(container));
                    break;
                case MessageType.SetDigitalOutRequest:
                    HandleSetDigitalOutRequest(MessageFactory.ParseTangoMessageFromContainer<SetDigitalOutRequest>(container));
                    break;
                case MessageType.ThreadJoggingRequest:
                    HandleThreadJoggingRequest(MessageFactory.ParseTangoMessageFromContainer<ThreadJoggingRequest>(container));
                    break;
                case MessageType.ThreadAbortJoggingRequest:
                    HandleThreadAbortJoggingRequest(MessageFactory.ParseTangoMessageFromContainer<ThreadAbortJoggingRequest>(container));
                    break;
                case MessageType.StartDebugLogRequest:
                    HandleStartDebugLogRequest(MessageFactory.ParseTangoMessageFromContainer<StartDebugLogRequest>(container));
                    break;
                case MessageType.StopDebugLogRequest:
                    HandleStopDebugLogRequest(MessageFactory.ParseTangoMessageFromContainer<StopDebugLogRequest>(container));
                    break;
                case MessageType.UploadProcessParametersRequest:
                    HandleUploadProcessParametersRequest(MessageFactory.ParseTangoMessageFromContainer<UploadProcessParametersRequest>(container));
                    break;
                case MessageType.SetComponentValueRequest:
                    HandleSetComponentValueRequest(MessageFactory.ParseTangoMessageFromContainer<SetComponentValueRequest>(container));
                    break;
                case MessageType.ResolveEventRequest:
                    HandleResolveEventRequest(MessageFactory.ParseTangoMessageFromContainer<ResolveEventRequest>(container));
                    break;
                case MessageType.DisconnectRequest:
                    HandleDisconnectRequest(MessageFactory.ParseTangoMessageFromContainer<DisconnectRequest>(container));
                    break;
                case MessageType.ConnectRequest:
                    HandleConnectRequest(MessageFactory.ParseTangoMessageFromContainer<ConnectRequest>(container));
                    break;
                case MessageType.UploadHardwareConfigurationRequest:
                    HandleUploadHardwareConfigurationRequest(MessageFactory.ParseTangoMessageFromContainer<UploadHardwareConfigurationRequest>(container));
                    break;
                case MessageType.StubFpgaWriteRegRequest:
                    HandleResetRequest(MessageFactory.ParseTangoMessageFromContainer<StubFpgaWriteRegRequest>(container));
                    break;
                case MessageType.SetHeaterStateRequest:
                    HandleSetHeaterStateRequest(MessageFactory.ParseTangoMessageFromContainer<SetHeaterStateRequest>(container));
                    break;
                case MessageType.SetBlowerStateRequest:
                    HandleSetBlowerStateRequest(MessageFactory.ParseTangoMessageFromContainer<SetBlowerStateRequest>(container));
                    break;
                case MessageType.SetValveStateRequest:
                    HandleSetValveStateRequest(MessageFactory.ParseTangoMessageFromContainer<SetValveStateRequest>(container));
                    break;
                case MessageType.CurrentJobRequest:
                    HandleCurrentJobRequest(MessageFactory.ParseTangoMessageFromContainer<CurrentJobRequest>(container));
                    break;
                case MessageType.ResumeCurrentJobRequest:
                    HandleResumeCurrentJobRequest(MessageFactory.ParseTangoMessageFromContainer<ResumeCurrentJobRequest>(container));
                    break;
                case MessageType.GetStorageInfoRequest:
                    HandleGetStorageInfoRequest(MessageFactory.ParseTangoMessageFromContainer<GetStorageInfoRequest>(container));
                    break;
                case MessageType.GetFilesRequest:
                    HandleGetFilesRequest(MessageFactory.ParseTangoMessageFromContainer<GetFilesRequest>(container));
                    break;
                case MessageType.FileDownloadRequest:
                    HandleFileDownloadRequest(MessageFactory.ParseTangoMessageFromContainer<FileDownloadRequest>(container));
                    break;
                case MessageType.FileChunkDownloadRequest:
                    HandleFileChunkDownloadRequest(MessageFactory.ParseTangoMessageFromContainer<FileChunkDownloadRequest>(container));
                    break;
                case MessageType.CreateRequest:
                    HandleCreateRequest(MessageFactory.ParseTangoMessageFromContainer<CreateRequest>(container));
                    break;
                case MessageType.DeleteRequest:
                    HandleDeleteRequest(MessageFactory.ParseTangoMessageFromContainer<DeleteRequest>(container));
                    break;
                case MessageType.FileUploadRequest:
                    HandleFileUploadRequest(MessageFactory.ParseTangoMessageFromContainer<FileUploadRequest>(container));
                    break;
                case MessageType.FileChunkUploadRequest:
                    HandleFileChunkUploadRequest(MessageFactory.ParseTangoMessageFromContainer<FileChunkUploadRequest>(container));
                    break;
                case MessageType.ValidateVersionRequest:
                    HandleValidateVersionRequest(MessageFactory.ParseTangoMessageFromContainer<ValidateVersionRequest>(container));
                    break;
                case MessageType.ActivateVersionRequest:
                    HandleActivateVersionRequest(MessageFactory.ParseTangoMessageFromContainer<ActivateVersionRequest>(container));
                    break;
                case MessageType.StartPowerDownRequest:
                    HandleStartPowerDownRequest(MessageFactory.ParseTangoMessageFromContainer<StartPowerDownRequest>(container));
                    break;
                case MessageType.AbortPowerDownRequest:
                    HandleAbortPowerDownRequest(MessageFactory.ParseTangoMessageFromContainer<AbortPowerDownRequest>(container));
                    break;
                case MessageType.StartThreadLoadingRequest:
                    HandleStartThreadLoadingRequest(MessageFactory.ParseTangoMessageFromContainer<StartThreadLoadingRequest>(container));
                    break;
                case MessageType.TryThreadLoadingRequest:
                    HandleTryThreadLoadingRequest(MessageFactory.ParseTangoMessageFromContainer<TryThreadLoadingRequest>(container));
                    break;
                case MessageType.ContinueThreadLoadingRequest:
                    HandleContinueThreadLoadingRequest(MessageFactory.ParseTangoMessageFromContainer<ContinueThreadLoadingRequest>(container));
                    break;
                case MessageType.StartHeadCleaningRequest:
                    HandleStartHeadCleaningRequest(MessageFactory.ParseTangoMessageFromContainer<StartHeadCleaningRequest>(container));
                    break;
                case MessageType.AbortHeadCleaningRequest:
                    HandleAbortHeadCleaningRequest(MessageFactory.ParseTangoMessageFromContainer<AbortHeadCleaningRequest>(container));
                    break;
                case MessageType.StartPowerUpRequest:
                    HandleStartPowerUpRequest(MessageFactory.ParseTangoMessageFromContainer<StartPowerUpRequest>(container));
                    break;
                case MessageType.StartInkFillingStatusRequest:
                    HandleStartInkFillingStatusRequest(MessageFactory.ParseTangoMessageFromContainer<StartInkFillingStatusRequest>(container));
                    break;
                case MessageType.StandByRequest:
                    HandleStandByRequest(MessageFactory.ParseTangoMessageFromContainer<StandByRequest>(container));
                    break;
                case MessageType.AttemptThreadJoggingRequest:
                    HandleAttemptThreadJoggingRequest(MessageFactory.ParseTangoMessageFromContainer<AttemptThreadJoggingRequest>(container));
                    break;
                case MessageType.DataStoreItemModifiedRequest:
                    HandleDataStoreItemModifiedRequest(MessageFactory.ParseTangoMessageFromContainer<DataStoreItemModifiedRequest>(container));
                    break;
                case MessageType.JobPrepareRequest:
                    HandleJobPrepareRequest(MessageFactory.ParseTangoMessageFromContainer<JobPrepareRequest>(container));
                    break;
                case MessageType.SetInkAutoFillingModeRequest:
                    HandleSetInkAutoFillingModeRequest(MessageFactory.ParseTangoMessageFromContainer<SetInkAutoFillingModeRequest>(container));
                    break;
                case MessageType.BitResultsRequest:
                    HandleBitResultsRequest(MessageFactory.ParseTangoMessageFromContainer<BitResultsRequest>(container));
                    break;
                case MessageType.SpoolTypeChangedRequest:
                    HandleSpoolTypeChangedRequest(MessageFactory.ParseTangoMessageFromContainer<SpoolTypeChangedRequest>(container));
                    break;
            }
        }

        #endregion

        #region Request Handlers

        private void HandleCalculateRequest(TangoMessage<CalculateRequest> request)
        {
            Task.Factory.StartNew(() =>
            {
                var response = MessageFactory.CreateTangoMessage<CalculateResponse>(request.Container.Token);
                response.Message.Sum = request.Message.A + request.Message.B;
                Transporter.SendResponse(response);
            });
        }

        private void HandleProgressRequest(TangoMessage<ProgressRequest> request)
        {
            Task.Factory.StartNew(() =>
            {
                for (int i = 0; i < request.Message.Amount; i++)
                {
                    Thread.Sleep(request.Message.Delay);
                    var res = MessageFactory.CreateTangoMessage<ProgressResponse>(request.Container.Token);
                    res.Message.Progress = i;

                    if (i == request.Message.Amount - 1) res.Container.Completed = true;

                    Transporter.SendResponse(res);
                }

                Transporter.SendResponse(new ProgressResponse(), request.Container.Token, new TransportResponseConfig() { Completed = true });
            });
        }

        private void HandleStartDiagnosticsRequest(TangoMessage<StartDiagnosticsRequest> request)
        {
            _diagnostics_enabled = true;

            _diagnosticsRequest = request.Message;

            int value = 0;
            Random rnd = new Random();

            var cancelToken = CreateCancelToken();

            Stopwatch watch = new Stopwatch();

            Task.Factory.StartNew(() =>
            {
                watch.Start();

                while (_diagnostics_enabled && Transporter.State == TransportComponentState.Connected && !cancelToken.Canceled)
                {
                    StartDiagnosticsResponse res = new StartDiagnosticsResponse();
                    DiagnosticsMonitors monitors = new DiagnosticsMonitors();
                    res.Monitors = monitors;

                    for (int i = 0; i < 10; i++)
                    {
                        value++;
                        monitors.Dancer1Angle.Add((int)(150 + _graphAmplitude * Math.Sin(2 * 3.14 * ((int)_graphFrequency) * value)));
                    }

                    var blower_state = _blower_states.FirstOrDefault();

                    if (blower_state != null)
                    {
                        monitors.BlowerVoltage.Add(blower_state.IsActive ? blower_state.Voltage : 0);
                    }

                    int y = Cursor.Position.Y;

                    for (int i = 0; i < 1; i++)
                    {
                        monitors.Dancer2Angle.Add(y);
                        monitors.GasSensor.Add(y);
                        monitors.FilterDeltaPressure.Add(y);
                    }

                    for (int i = 0; i < 30; i++)
                    {
                        monitors.Dancer3Angle.Add(y);
                    }

                    for (int i = 0; i < MachineStatus.IDSPacksLevels.Count; i++)
                    {
                        var dispensers = new DoubleArray();
                        dispensers.Data.Add(MachineStatus.IDSPacksLevels[i].DispenserLevel);
                        monitors.DispensersInkLevel.Add(dispensers);

                        var midTanks = new DoubleArray();
                        midTanks.Data.Add(MachineStatus.IDSPacksLevels[i].MidTankLevel);
                        monitors.MidTanksInkLevel.Add(midTanks);
                    }

                    var dispenserFrequencies = new RepeatedField<DoubleArray>();

                    double cPosition = Cursor.Position.Y;

                    for (int i = 0; i < 8; i++)
                    {
                        DoubleArray singleDispenser = new DoubleArray();

                        for (int j = 0; j < 10; j++)
                        {
                            singleDispenser.Data.Add(cPosition + (i * 50));
                        }

                        dispenserFrequencies.Add(singleDispenser);
                    }

                    monitors.DispensersMotorsFrequency.AddRange(dispenserFrequencies);

                    monitors.Dispenser1MotorFrequency.AddRange(dispenserFrequencies[0].Data);
                    monitors.Dispenser2MotorFrequency.AddRange(dispenserFrequencies[1].Data);
                    monitors.Dispenser3MotorFrequency.AddRange(dispenserFrequencies[2].Data);
                    monitors.Dispenser4MotorFrequency.AddRange(dispenserFrequencies[3].Data);
                    monitors.Dispenser5MotorFrequency.AddRange(dispenserFrequencies[4].Data);
                    monitors.Dispenser6MotorFrequency.AddRange(dispenserFrequencies[5].Data);
                    monitors.Dispenser7MotorFrequency.AddRange(dispenserFrequencies[6].Data);
                    monitors.Dispenser8MotorFrequency.AddRange(dispenserFrequencies[7].Data);

                    res.DigitalInterfaceStates.AddRange(_digitalOutputPinsStates.Concat(_digitalInputPinsStates));
                    res.ComponentsStates.AddRange(_componentsStates);
                    res.HeatersStates.AddRange(_heater_states);
                    res.ValvesStates.AddRange(_valveStates);
                    res.ElapsedMilli = (uint)watch.ElapsedMilliseconds;

                    watch.Restart();

                    if (!EmulateCorruption)
                    {
                        Transporter.SendResponse<StartDiagnosticsResponse>(res, request.Container.Token);
                    }

                    Thread.Sleep(DIAGNOSTICS_INTERVAL);
                }
            });

        }

        private void HandleStopDiagnosticsRequest(TangoMessage<StopDiagnosticsRequest> request)
        {
            _diagnostics_enabled = false;
            Transporter.SendResponse<StopDiagnosticsResponse>(new StopDiagnosticsResponse(), request.Container.Token);
        }

        private void HandleStartEventsNotificationRequest(TangoMessage<StartEventsNotificationRequest> request)
        {
            _events_enabled = true;

            var cancelToken = CreateCancelToken();

            Task.Factory.StartNew(() =>
            {
                while (_events_enabled && Transporter.State == TransportComponentState.Connected && !cancelToken.Canceled)
                {
                    var res = new StartEventsNotificationResponse();
                    res.Events.AddRange(EventsStates.Where(x => x.IsActive).Select(x => new Event() { Type = x.EventType, Message = "Generated by Tango Embedded Emulator" }));

                    if (!EmulateCorruption)
                    {
                        Transporter.SendResponse<StartEventsNotificationResponse>(res, request.Container.Token);
                    }

                    Thread.Sleep(1000);
                }
            });
        }

        private void HandleStopEventsNotificationRequest(TangoMessage<StopEventsNotificationRequest> request)
        {
            _events_enabled = false;
            Transporter.SendResponse<StopEventsNotificationResponse>(new StopEventsNotificationResponse(), request.Container.Token);
        }

        private void HandleStartMachineStatusUpdateRequest(TangoMessage<StartMachineStatusUpdateRequest> request)
        {
            _machine_updates_enabled = true;

            var cancelToken = CreateCancelToken();

            _machineStatusRequestToken = request.Container.Token;

            Task.Factory.StartNew(() =>
            {
                while (_machine_updates_enabled && Transporter.State == TransportComponentState.Connected && !cancelToken.Canceled)
                {
                    var res = new StartMachineStatusUpdateResponse();
                    res.Status = MachineStatus;

                    if (!EmulateCorruption)
                    {
                        Transporter.SendResponse<StartMachineStatusUpdateResponse>(res, request.Container.Token);
                    }

                    Thread.Sleep(1000);
                }
            });
        }

        private void HandleStopMachineStatusUpdateRequest(TangoMessage<StopMachineStatusUpdateRequest> request)
        {
            _machine_updates_enabled = false;
            Transporter.SendResponse<StopMachineStatusUpdateResponse>(new StopMachineStatusUpdateResponse(), request.Container.Token);
        }

        private void HandleStartDebugLogRequest(TangoMessage<StartDebugLogRequest> request)
        {
            _debug_logs_enabled = true;

            int counter = 1;
            int counter_message = 0;

            var cancelToken = CreateCancelToken();

            Task.Factory.StartNew(() =>
            {
                while (_debug_logs_enabled && Transporter.State == TransportComponentState.Connected && !cancelToken.Canceled)
                {
                    StartDebugLogResponse res = new StartDebugLogResponse();

                    res.FileName = "C:\\demoFile.c";
                    res.LineNumber = 100;
                    res.Filter = 1;
                    res.Message = "This is a false message " + counter;
                    res.Category = DebugLogCategory.Info;

                    if (!EmulateCorruption)
                    {
                        Transporter.SendResponse<StartDebugLogResponse>(res, request.Container.Token);
                    }

                    Thread.Sleep(1000);

                    counter_message++;

                    if (counter_message > 10)
                    {
                        counter_message = 0;
                        counter++;
                    }
                }
            });
        }

        private void HandleJobRequest(TangoMessage<JobRequest> request)
        {
            MachineStatus.State = MachineState.PreparingJob;

            JobTicket job = request.Message.JobTicket;
            var jobTicket = job;
            _current_job_ticket = jobTicket.Clone();
            _current_job_resume_token = null;

            if (jobTicket.UploadStrategy == JobUploadStrategy.JobDescriptionFile)
            {
                using (FileStream fs = new FileStream(jobTicket.JobDescriptionFile, FileMode.Open))
                {
                    var segments = JobDescriptionFile.ReadJobDescriptionFile(fs);
                    jobTicket.Segments.AddRange(segments);
                }

                var logedTicket = jobTicket.Clone();
                foreach (var segment in logedTicket.Segments)
                {
                    if (segment.BrushStops.Count > 2)
                    {
                        var first = segment.BrushStops.First();
                        var last = segment.BrushStops.Last();
                        segment.BrushStops.Clear();
                        segment.BrushStops.Add(first);
                        segment.BrushStops.Add(last);
                    }
                }

                LogManager.Log("Parsed Job Upload File (Showing first and last brush stop for segment):\n" + logedTicket.ToJsonString());
            }

            double centimeter_per_second = request.Message.JobTicket.ProcessParameters.DyeingSpeed;

            _cancelJob = false;
            bool message_sent = false;
            int units = (int)Math.Max(job.NumberOfUnits, 1);
            double unit_length = job.Length;/// units;

            Task.Factory.StartNew(() =>
            {
                MachineStatus.State = MachineState.RunningJob;

                List<int> calculatedStopIndexes = new List<int>();
                double progress = 0;
                double lastProgress = 0;
                Stopwatch watch = new Stopwatch();
                Dictionary<int, IDSPackLevel> dispenserindexToPacklevel = new Dictionary<int, IDSPackLevel>();

                for (int i = 0; i < units; i++)
                {

                    while (progress < unit_length + (i == units - 1 ? (job.ProcessParameters.DryerBufferLength * ProcessParametersTable.DRYER_METERS_PER_CYCLE + ProcessParametersTable.DRYER_TO_SPOOL_LENGTH_METERS) : 0) && !_cancelJob)
                    {
                        var status = new PMR.Printing.JobStatus();
                        status.Progress = progress;

                        if (!message_sent)
                        {
                            message_sent = true;
                            status.Message = "Demo Message From Emulator...";
                        }

                        if (!EmulateCorruption)
                        {
                            if (_current_job_resume_token == null)
                            {
                                Transporter.SendResponse<JobResponse>(new JobResponse()
                                {
                                    Status = status,

                                }, request.Container.Token);
                            }
                            else
                            {
                                Transporter.SendResponse<ResumeCurrentJobResponse>(new ResumeCurrentJobResponse()
                                {
                                    Status = status,

                                }, _current_job_resume_token);
                            }
                        }

                        progress += Math.Min((centimeter_per_second / 1000d), (unit_length + (i == units - 1 ? (job.ProcessParameters.DryerBufferLength * ProcessParametersTable.DRYER_METERS_PER_CYCLE + ProcessParametersTable.DRYER_TO_SPOOL_LENGTH_METERS) : 0)) - progress);

                        double currentPosition = 0;
                        double nextStopPosition = unit_length;

                        watch.Restart();
                        for (int seg_index = 0; seg_index < jobTicket.Segments.Count(); seg_index++)
                        {
                            var segment = jobTicket.Segments[seg_index];
                            if ((seg_index + 1) < jobTicket.Segments.Count())
                            {
                                nextStopPosition = jobTicket.Segments[seg_index + 1].Length;
                            }

                            calculatedStopIndexes = new List<int>();

                            for (int index = 0; index < segment.BrushStops.Count(); index++)
                            {
                                var stop = segment.BrushStops[index];
                                if ((index + 1) < segment.BrushStops.Count())
                                {
                                    var nextStop = segment.BrushStops[index + 1];
                                    nextStopPosition = nextStop.OffsetMeters;
                                }

                                if (!calculatedStopIndexes.Contains(stop.Index))
                                {
                                    var brushStopPosition = currentPosition + stop.OffsetMeters;
                                    if (brushStopPosition >= lastProgress && brushStopPosition <= progress)
                                    {
                                        foreach (var dispenser in stop.Dispensers)
                                        {
                                            var quantity = dispenser.NanoliterPerCentimeter * (nextStopPosition - stop.OffsetMeters) * 100d;
                                            IDSPackLevel packLevel;
                                            if (!dispenserindexToPacklevel.TryGetValue(dispenser.Index, out packLevel))
                                            {
                                                packLevel = MachineStatus.IDSPacksLevels.SingleOrDefault(x => x.Index == dispenser.Index);
                                                dispenserindexToPacklevel.Add(dispenser.Index, packLevel);
                                            }
                                            if (packLevel != null)
                                            {
                                                packLevel.DispenserLevel -= (int)quantity;
                                            }
                                        }
                                        calculatedStopIndexes.Add(stop.Index);
                                    }
                                }
                            }
                            currentPosition += segment.Length;
                        }
                        watch.Stop();
                        lastProgress = progress;
                        int delay = (100 - (int)watch.ElapsedMilliseconds) > 0 ? (100 - (int)watch.ElapsedMilliseconds) : 5;
                        Thread.Sleep(delay);

                        if (_cancelJob)
                        {
                            break;
                        }
                    }

                    if (_cancelJob)
                    {
                        break;
                    }
                }

                foreach (var packLevel in MachineStatus.IDSPacksLevels)
                {
                    Debug.WriteLine($"Emulator: Pack Index = {packLevel.Index}");
                    Debug.WriteLine($"Emulator: Quantity = {MachineOperator.MAX_DISPENSER_NANOLITER - packLevel.DispenserLevel}");
                }

                jobTicket = null;

                if (_cancelJob)
                {
                    if (_current_job_resume_token == null)
                    {
                        Transporter.SendResponse<JobResponse>(new JobResponse()
                        {

                        }, request.Container.Token, new TransportResponseConfig() { ErrorCode = ErrorCode.ContinuousResponseAborted });
                    }
                    else
                    {
                        Transporter.SendResponse<ResumeCurrentJobResponse>(new ResumeCurrentJobResponse()
                        {

                        }, _current_job_resume_token, new TransportResponseConfig() { ErrorCode = ErrorCode.ContinuousResponseAborted });
                    }
                }
                else
                {
                    if (_current_job_resume_token == null)
                    {
                        Transporter.SendResponse<JobResponse>(new JobResponse()
                        {
                            Status = new PMR.Printing.JobStatus()
                            {
                                Progress = unit_length + job.ProcessParameters.DryerBufferLength * ProcessParametersTable.DRYER_METERS_PER_CYCLE + ProcessParametersTable.DRYER_TO_SPOOL_LENGTH_METERS,
                            }

                        }, request.Container.Token, new TransportResponseConfig() { Completed = !_cancelJob });

                        if (_rnd.Next(0, 100) > 50)
                        {
                            Task.Factory.StartNew(() =>
                            {
                                Thread.Sleep(5000);
                                MachineStatus.SpoolState = SpoolState.Absent;
                                Transporter.SendResponse<StartMachineStatusUpdateResponse>(new StartMachineStatusUpdateResponse() { Status = MachineStatus }, _machineStatusRequestToken);

                                Thread.Sleep(2000);

                                MachineStatus.SpoolState = SpoolState.Present;
                                Transporter.SendResponse<StartMachineStatusUpdateResponse>(new StartMachineStatusUpdateResponse() { Status = MachineStatus }, _machineStatusRequestToken);
                            });
                        }
                    }
                    else
                    {
                        Transporter.SendResponse<ResumeCurrentJobResponse>(new ResumeCurrentJobResponse()
                        {
                            Status = new PMR.Printing.JobStatus()
                            {
                                Progress = unit_length + job.ProcessParameters.DryerBufferLength * ProcessParametersTable.DRYER_METERS_PER_CYCLE + ProcessParametersTable.DRYER_TO_SPOOL_LENGTH_METERS,
                            }

                        }, _current_job_resume_token, new TransportResponseConfig() { Completed = !_cancelJob });
                    }
                }

                MachineStatus.State = MachineState.Ready;
            });
        }

        private void HandleAbortJobRequest(TangoMessage<AbortJobRequest> request)
        {
            //if (_jobAbortCounter == 1)
            //{
            _cancelJob = true;
            Transporter.SendResponse<AbortJobResponse>(new AbortJobResponse(), request.Container.Token);
            //    _jobAbortCounter = 0;
            //}
            //else
            //{
            //    _jobAbortCounter++;
            //}
        }

        private void HandleMotorJoggingRequest(TangoMessage<MotorJoggingRequest> request)
        {
            var jogRequest = request.Message;

            _motorJoggingRequestTypes.Add(jogRequest.MotorType);


            Task.Factory.StartNew(() =>
            {
                while (_motorJoggingRequestTypes.Contains(jogRequest.MotorType))
                {
                    if (jogRequest.Direction == MotorDirection.Forward)
                    {
                        _graphFrequency = 10;
                    }
                    else
                    {
                        _graphFrequency = 18;
                    }

                    Thread.Sleep(30);
                }

                ResetGraphFactors();
            });

            Transporter.SendResponse<MotorJoggingResponse>(new MotorJoggingResponse(), request.Container.Token);
        }

        private void HandleAbortMotorJoggingRequest(TangoMessage<MotorAbortJoggingRequest> request)
        {
            _motorJoggingRequestTypes.RemoveAll(x => x == request.Message.MotorType);
            ResetGraphFactors();
            Transporter.SendResponse<MotorAbortJoggingResponse>(new MotorAbortJoggingResponse(), request.Container.Token);
        }

        private void HandleMotorHomingRequest(TangoMessage<MotorHomingRequest> request)
        {
            var homeRequest = request.Message;

            _motorHomingRequestCodes.Add(homeRequest.MotorType);

            Task.Factory.StartNew(() =>
            {
                _graphFrequency = 10;

                var inputPin = _digitalInputPinsStates.FirstOrDefault();

                for (int i = 0; i < 100; i++)
                {
                    if (inputPin != null)
                    {
                        inputPin.Value = !inputPin.Value;
                    }

                    Transporter.SendResponse<MotorHomingResponse>(new MotorHomingResponse() { MaxProgress = 100, Progress = i }, request.Container.Token);

                    if (!_motorHomingRequestCodes.Contains(homeRequest.MotorType))
                    {
                        ResetGraphFactors();
                        return;
                    }

                    Thread.Sleep(30);
                }

                Transporter.SendResponse<MotorHomingResponse>(new MotorHomingResponse() { MaxProgress = 100, Progress = 100 }, request.Container.Token, new TransportResponseConfig() { Completed = true });
                _motorHomingRequestCodes.Remove(homeRequest.MotorType);
                ResetGraphFactors();

                if (request.Message.MotorType == PMR.Hardware.HardwareMotorType.MotoDhLid)
                {
                    if (request.Message.Direction == MotorDirection.Backward)
                    {
                        var eventState1 = EventsStates.FirstOrDefault(x => x.EventType == PMR.Diagnostics.EventType.DyeingHeadArcLidIsOpen);
                        var eventState2 = EventsStates.FirstOrDefault(x => x.EventType == PMR.Diagnostics.EventType.DyeingHeadCoverIsOpen);
                        eventState1.IsActive = true;
                        eventState2.IsActive = true;
                    }
                    else
                    {
                        var eventState1 = EventsStates.FirstOrDefault(x => x.EventType == PMR.Diagnostics.EventType.DyeingHeadArcLidIsOpen);
                        var eventState2 = EventsStates.FirstOrDefault(x => x.EventType == PMR.Diagnostics.EventType.DyeingHeadCoverIsOpen);
                        eventState1.IsActive = false;
                        eventState2.IsActive = false;
                    }
                }
            });
        }

        private void HandleAbortMotorHomingRequest(TangoMessage<MotorAbortHomingRequest> request)
        {
            _motorHomingRequestCodes.RemoveAll(x => x == request.Message.MotorType);
            ResetGraphFactors();
            Transporter.SendResponse<MotorAbortHomingResponse>(new MotorAbortHomingResponse(), request.Container.Token);
        }

        private void HandleDispenserJoggingRequest(TangoMessage<DispenserJoggingRequest> request)
        {
            var jogRequest = request.Message;

            _dispenserJoggingRequestCodes.Add(jogRequest.Index);

            Task.Factory.StartNew(() =>
            {
                while (_dispenserJoggingRequestCodes.Contains(jogRequest.Index))
                {
                    if (jogRequest.Direction == MotorDirection.Forward)
                    {
                        _graphFrequency = 10;
                    }
                    else
                    {
                        _graphFrequency = 18;
                    }

                    Thread.Sleep(30);
                }

                ResetGraphFactors();
            });

            Transporter.SendResponse<DispenserJoggingResponse>(new DispenserJoggingResponse(), request.Container.Token);
        }

        private void HandleAbortDispenserJoggingRequest(TangoMessage<DispenserAbortJoggingRequest> request)
        {
            _dispenserJoggingRequestCodes.RemoveAll(x => x == request.Message.Index);
            ResetGraphFactors();
            Transporter.SendResponse<DispenserAbortJoggingResponse>(new DispenserAbortJoggingResponse(), request.Container.Token);
        }

        private void HandleDispenserHomingRequest(TangoMessage<DispenserHomingRequest> request)
        {
            var homeRequest = request.Message;

            _dispenserHomingRequestCodes.Add(homeRequest.Index);

            Task.Factory.StartNew(() =>
            {
                _graphFrequency = 10;

                for (int i = 0; i < 100; i++)
                {
                    Transporter.SendResponse<DispenserHomingResponse>(new DispenserHomingResponse() { MaxProgress = 100, Progress = i }, request.Container.Token);

                    if (!_dispenserHomingRequestCodes.Contains(homeRequest.Index))
                    {
                        ResetGraphFactors();
                        return;
                    }

                    Thread.Sleep(30);
                }

                Transporter.SendResponse<DispenserHomingResponse>(new DispenserHomingResponse() { MaxProgress = 100, Progress = 100 }, request.Container.Token, new TransportResponseConfig() { Completed = true });
                _dispenserHomingRequestCodes.Remove(homeRequest.Index);
                ResetGraphFactors();
            });
        }

        private void HandleAbortDispenserHomingRequest(TangoMessage<DispenserAbortHomingRequest> request)
        {
            _dispenserHomingRequestCodes.RemoveAll(x => x == request.Message.Index);
            ResetGraphFactors();
            Transporter.SendResponse<DispenserAbortHomingResponse>(new DispenserAbortHomingResponse(), request.Container.Token);
        }

        private void HandleSetDigitalOutRequest(TangoMessage<SetDigitalOutRequest> request)
        {
            var pinState = _digitalOutputPinsStates.SingleOrDefault(x => x.InterfaceIO == request.Message.InterfaceIO);
            if (pinState != null)
            {
                pinState.Value = request.Message.Value;
                Transporter.SendResponse<SetDigitalOutResponse>(new SetDigitalOutResponse(), request.Container.Token);
            }
            else
            {
                Transporter.SendResponse<SetDigitalOutResponse>(new SetDigitalOutResponse(), request.Container.Token, new TransportResponseConfig() { ErrorCode = ErrorCode.InvalidDigitalPinNumber });
            }
        }

        private void HandleThreadJoggingRequest(TangoMessage<ThreadJoggingRequest> request)
        {
            Transporter.SendResponse<ThreadJoggingResponse>(new ThreadJoggingResponse(), request.Container.Token);
        }

        private void HandleThreadAbortJoggingRequest(TangoMessage<ThreadAbortJoggingRequest> request)
        {
            Transporter.SendResponse<ThreadAbortJoggingResponse>(new ThreadAbortJoggingResponse(), request.Container.Token);
        }

        private void HandleUploadProcessParametersRequest(TangoMessage<UploadProcessParametersRequest> request)
        {
            Task.Factory.StartNew(() =>
            {

                Thread.Sleep(1000);
                Transporter.SendResponse<UploadProcessParametersResponse>(new UploadProcessParametersResponse(), request.Container.Token);

            });
        }

        private void HandleSetComponentValueRequest(TangoMessage<SetComponentValueRequest> request)
        {
            var componentState = _componentsStates.SingleOrDefault(x => x.Component == request.Message.Component);

            double startValue = componentState.Value;
            double targetValue = request.Message.Value;

            Transporter.SendResponse<SetComponentValueResponse>(new SetComponentValueResponse(), request.Container.Token);

            Task.Factory.StartNew(() =>
            {
                if (targetValue > startValue)
                {
                    while (componentState.Value < targetValue)
                    {
                        componentState.Value++;
                        Thread.Sleep(30);
                    }
                }
                else
                {
                    while (componentState.Value > targetValue)
                    {
                        componentState.Value--;
                        Thread.Sleep(30);
                    }
                }
            });
        }

        private void HandleResolveEventRequest(TangoMessage<ResolveEventRequest> request)
        {
            EventsStates.Where(x => x.EventType == request.Message.Type).ToList().ForEach(x => x.IsActive = false);
            Transporter.SendResponse<ResolveEventResponse>(new ResolveEventResponse(), request.Container.Token);
        }

        private void HandleDisconnectRequest(TangoMessage<DisconnectRequest> request)
        {
            foreach (var cancelToken in _continousResponseTokens)
            {
                cancelToken.Canceled = true;
            }

            _continousResponseTokens.Clear();
            try
            {
                Transporter.SendResponse<DisconnectResponse>(new DisconnectResponse(), request.Container.Token);
            }
            catch { }
        }

        private void HandleConnectRequest(TangoMessage<ConnectRequest> request)
        {
            if (!EmulateCorruption)
            {
                foreach (var cancelToken in _continousResponseTokens)
                {
                    cancelToken.Canceled = true;
                }

                _continousResponseTokens.Clear();

                Transporter.SendResponse<ConnectResponse>(new ConnectResponse()
                {
                    DeviceInformation = new DeviceInformation()
                    {
                        Version = "1.0.0.0",
                        BuildDate = DateTime.Now.ToString(),
                        Name = "Machine Emulator",
                        FPGA1Version = "1.1",
                        FPGA2Version = "2.2",
                        FPGA3Version = "3.3",
                        DiagnosticsInterval = (uint)DIAGNOSTICS_INTERVAL,
                        HeadType = HeadType.Arc,
                    },
                    IsAfterReset = _isAfterReset,
                }, request.Container.Token, new TransportResponseConfig() { ErrorCode = request.Message.Password == "1234" ? ErrorCode.None : ErrorCode.UnauthorizedConnection });


                _connectionTime = DateTime.Now;

                _isAfterReset = false;
            }
        }

        private void HandleStopDebugLogRequest(TangoMessage<StopDebugLogRequest> request)
        {
            _debug_logs_enabled = false;
            Transporter.SendResponse<StopDebugLogResponse>(new StopDebugLogResponse(), request.Container.Token);

        }

        private void HandleUploadHardwareConfigurationRequest(TangoMessage<UploadHardwareConfigurationRequest> request)
        {
            Transporter.SendResponse<UploadHardwareConfigurationResponse>(new UploadHardwareConfigurationResponse(), request.Container.Token);
        }

        private void HandleResetRequest(TangoMessage<StubFpgaWriteRegRequest> request)
        {
            Transporter.SendResponse<StubFpgaWriteRegResponse>(new StubFpgaWriteRegResponse(), request.Container.Token);
        }

        private void HandleSetHeaterStateRequest(TangoMessage<SetHeaterStateRequest> request)
        {
            var heater = _heater_states.SingleOrDefault(x => x.HeaterType == request.Message.HeaterType);

            if (heater != null)
            {
                double startValue = heater.CurrentValue;
                double targetValue = request.Message.SetPoint;

                Task.Factory.StartNew(() =>
                {
                    heater.IsRampingUp = true;
                    heater.IsActive = true;
                    heater.IsInSetPoint = false;
                    heater.SetPoint = targetValue;

                    if (targetValue > startValue)
                    {
                        while (heater.CurrentValue < targetValue)
                        {
                            heater.CurrentValue++;
                            Thread.Sleep(30);
                        }
                    }
                    else
                    {
                        while (heater.CurrentValue > targetValue)
                        {
                            heater.CurrentValue--;
                            Thread.Sleep(30);
                        }
                    }

                    heater.IsRampingUp = false;
                    heater.IsActive = false;
                    heater.IsInSetPoint = true;
                });
            }

            Transporter.SendResponse<SetHeaterStateResponse>(new SetHeaterStateResponse(), request.Container.Token);
        }

        private void HandleSetBlowerStateRequest(TangoMessage<SetBlowerStateRequest> request)
        {
            var blower_state = _blower_states.FirstOrDefault();

            if (blower_state != null)
            {
                blower_state.Voltage = request.Message.Voltage;
                blower_state.IsActive = request.Message.IsActive;
            }

            Transporter.SendResponse<SetBlowerStateResponse>(new SetBlowerStateResponse(), request.Container.Token);
        }

        private void HandleSetValveStateRequest(TangoMessage<SetValveStateRequest> request)
        {
            var valve_state = _valveStates.SingleOrDefault(x => x.ValveType == request.Message.ValveType);

            if (valve_state != null)
            {
                valve_state.State = request.Message.State;
            }

            Transporter.SendResponse<SetValveStateResponse>(new SetValveStateResponse(), request.Container.Token);
        }

        private void HandleCurrentJobRequest(TangoMessage<CurrentJobRequest> request)
        {
            Transporter.SendResponse<CurrentJobResponse>(new CurrentJobResponse()
            {
                IsJobInProgress = _current_job_ticket != null,
                JobTicket = _current_job_ticket,
            }, request.Container.Token);
        }

        private void HandleResumeCurrentJobRequest(TangoMessage<ResumeCurrentJobRequest> request)
        {
            if (_current_job_ticket != null)
            {
                _current_job_resume_token = request.Container.Token;
            }
            else
            {
                Transporter.SendResponse<ResumeCurrentJobResponse>(new ResumeCurrentJobResponse(), request.Container.Token, new TransportResponseConfig() { Completed = true, ErrorCode = ErrorCode.NoJobInProgress });
            }
        }

        private void HandleGetStorageInfoRequest(TangoMessage<GetStorageInfoRequest> request)
        {
            var d = new DriveInfo("C");

            Directory.CreateDirectory("C:\\EmulatorStorage");

            Transporter.SendResponse<GetStorageInfoResponse>(new GetStorageInfoResponse()
            {
                Capacity = d.TotalSize,
                FreeSpace = d.TotalFreeSpace,
                Root = "C:\\EmulatorStorage"
            }, request.Container.Token);
        }

        private void HandleGetFilesRequest(TangoMessage<GetFilesRequest> request)
        {
            GetFilesResponse response = new GetFilesResponse();

            bool failed = false;
            String msg = null;

            try
            {
                String path = request.Message.Path;

                bool replaceSlash = path.Contains("/");

                foreach (var dir in Directory.GetDirectories(path))
                {
                    DirectoryInfo dirInfo = new DirectoryInfo(dir);

                    response.Items.Add(new PMR.IO.FileInfo()
                    {
                        Attribute = FileAttribute.Directory,
                        FullPath = replaceSlash ? dir.Replace("\\", "/") : dir,
                        LastModifiedDate = dirInfo.LastWriteTime.DayOfYear,
                        LastModifiedTime = dirInfo.LastWriteTime.Hour,
                        Name = Path.GetFileName(dir),
                    });
                }

                foreach (var file in Directory.GetFiles(path))
                {
                    System.IO.FileInfo fileInfo = new System.IO.FileInfo(file);

                    response.Items.Add(new PMR.IO.FileInfo()
                    {
                        Attribute = FileAttribute.Unspecified,
                        FullPath = replaceSlash ? file.Replace("\\", "/") : file,
                        LastModifiedDate = fileInfo.LastWriteTime.DayOfYear,
                        LastModifiedTime = fileInfo.LastWriteTime.Hour,
                        Name = Path.GetFileName(file),
                        Length = (int)fileInfo.Length,
                    });
                }
            }
            catch (Exception ex)
            {
                failed = true;
                msg = ex.Message;
            }

            Transporter.SendResponse<GetFilesResponse>(response, request.Container.Token, new TransportResponseConfig() { ErrorCode = failed ? ErrorCode.GeneralError : ErrorCode.None, ErrorMessage = msg });
        }

        private void HandleFileDownloadRequest(TangoMessage<FileDownloadRequest> request)
        {
            long length = File.Exists(request.Message.FileName) ? new System.IO.FileInfo(request.Message.FileName).Length : 0;

            Transporter.SendResponse<FileDownloadResponse>(new FileDownloadResponse()
            {
                DownloadID = Guid.NewGuid().ToString(),
                MaxChunkLength = Math.Min(MAX_CHUNK_LENGTH, length),
            }, request.Container.Token, new TransportResponseConfig() { ErrorCode = File.Exists(request.Message.FileName) ? ErrorCode.None : ErrorCode.FileNotFound });
        }

        private void HandleFileChunkDownloadRequest(TangoMessage<FileChunkDownloadRequest> request)
        {
            var message = request.Message;

            try
            {
                using (FileStream fs = new FileStream(message.FileName, FileMode.Open))
                {
                    fs.Position = message.Position;
                    byte[] buffer = new byte[Math.Min(MAX_CHUNK_LENGTH, fs.Length - fs.Position)];
                    fs.Read(buffer, 0, buffer.Length);
                    Transporter.SendResponse<FileChunkDownloadResponse>(new FileChunkDownloadResponse()
                    {
                        Buffer = ByteString.CopyFrom(buffer),
                    }, request.Container.Token);
                }
            }
            catch (Exception ex)
            {
                Transporter.SendResponse<FileChunkDownloadResponse>(new FileChunkDownloadResponse()
                {

                }, request.Container.Token, new TransportResponseConfig() { ErrorCode = ErrorCode.FileRequestDenied, ErrorMessage = ex.Message });
            }
        }

        private void HandleCreateRequest(TangoMessage<CreateRequest> request)
        {
            try
            {
                Directory.CreateDirectory(request.Message.Path);
                Transporter.SendResponse<CreateResponse>(new CreateResponse(), request.Container.Token);
            }
            catch (Exception ex)
            {
                Transporter.SendResponse<CreateResponse>(new CreateResponse(), request.Container.Token, new TransportResponseConfig() { ErrorCode = ErrorCode.FileRequestInvalidParameter, ErrorMessage = ex.Message });
            }
        }

        private void HandleDeleteRequest(TangoMessage<DeleteRequest> request)
        {
            try
            {
                if (request.Message.Attribute == FileAttribute.Directory)
                {
                    Directory.Delete(request.Message.Path, true);
                }
                else
                {
                    File.Delete(request.Message.Path);
                }

                Transporter.SendResponse<DeleteResponse>(new DeleteResponse(), request.Container.Token);
            }
            catch (Exception ex)
            {
                Transporter.SendResponse<DeleteResponse>(new DeleteResponse(), request.Container.Token, new TransportResponseConfig() { ErrorCode = ErrorCode.FileRequestInvalidParameter, ErrorMessage = ex.Message });
            }
        }

        private void HandleFileUploadRequest(TangoMessage<FileUploadRequest> request)
        {
            var message = request.Message;
            _lastFileUploadRequest = message;
            Transporter.SendResponse<FileUploadResponse>(new FileUploadResponse()
            {
                MaxChunkLength = MAX_CHUNK_LENGTH,
                UploadID = Guid.NewGuid().ToString(),
            }, request.Container.Token);
        }

        private void HandleFileChunkUploadRequest(TangoMessage<FileChunkUploadRequest> request)
        {
            var message = request.Message;

            try
            {
                using (FileStream fs = new FileStream(message.Path, FileMode.Append))
                {
                    byte[] buffer = message.Buffer.ToByteArray();
                    fs.Write(buffer, 0, buffer.Length);

                    Debug.WriteLine($"Emulator file upload '{_lastFileUploadRequest.Path}' {fs.Length}/{_lastFileUploadRequest.Length} ...");
                }

                Transporter.SendResponse<FileChunkUploadResponse>(new FileChunkUploadResponse(), request.Container.Token);
            }
            catch (Exception ex)
            {
                Transporter.SendResponse<FileChunkUploadResponse>(new FileChunkUploadResponse(), request.Container.Token, new TransportResponseConfig() { ErrorCode = ErrorCode.GeneralError, ErrorMessage = ex.Message });
            }
        }

        private void HandleValidateVersionRequest(TangoMessage<ValidateVersionRequest> request)
        {
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(3000);

                try
                {
                    using (FileStream fs = new FileStream(Path.Combine(request.Message.Path, MachineOperator.FIRMWARE_UPGRADE_CONFIG_FILE_NAME), FileMode.Open))
                    {
                        VersionPackageDescriptor package = VersionPackageDescriptor.Parser.ParseFrom(fs);
                    }

                    Transporter.SendResponse<ValidateVersionResponse>(new ValidateVersionResponse(), request.Container.Token);
                }
                catch (Exception ex)
                {
                    Transporter.SendResponse<ValidateVersionResponse>(new ValidateVersionResponse(), request.Container.Token, new TransportResponseConfig() { ErrorCode = ErrorCode.GeneralError, ErrorMessage = ex.Message });
                }
            });
        }

        private void HandleActivateVersionRequest(TangoMessage<ActivateVersionRequest> request)
        {
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(3000);

                try
                {
                    using (FileStream fs = new FileStream(Path.Combine(request.Message.Path, MachineOperator.FIRMWARE_UPGRADE_CONFIG_FILE_NAME), FileMode.Open))
                    {
                        VersionPackageDescriptor package = VersionPackageDescriptor.Parser.ParseFrom(fs);
                    }

                    for (int i = 0; i < 100; i++)
                    {
                        Transporter.SendResponse<ActivateVersionResponse>(new ActivateVersionResponse()
                        {
                            Progress = i + 1,
                            Total = 100
                        }, request.Container.Token);

                        Thread.Sleep(10);
                    }

                    Transporter.SendResponse<ActivateVersionResponse>(new ActivateVersionResponse()
                    {
                        Progress = 100,
                        Total = 100
                    }, request.Container.Token, new TransportResponseConfig() { Completed = true });
                }
                catch (Exception ex)
                {
                    Transporter.SendResponse<ActivateVersionResponse>(new ActivateVersionResponse(), request.Container.Token, new TransportResponseConfig() { ErrorCode = ErrorCode.GeneralError, ErrorMessage = ex.Message });
                }
            });
        }

        private void HandleStartPowerDownRequest(TangoMessage<StartPowerDownRequest> request)
        {
            _abortPowerDown = false;

            Task.Factory.StartNew(async () =>
            {
                MachineStatus.State = MachineState.PowerOff;

                for (int i = 0; i < 100; i++)
                {
                    if (_abortPowerDown) return;

                    await Task.Delay(200);
                    await Transporter.SendResponse<StartPowerDownResponse>(new StartPowerDownResponse()
                    {
                        ProgressPercentage = i++,
                        Message = $"Powering down {i}%..."
                    }, request.Container.Token);
                }

                await Task.Delay(500);

                await Transporter.SendResponse<StartPowerDownResponse>(new StartPowerDownResponse()
                {
                    ProgressPercentage = 100,
                    Message = "Machine is turned off",
                    State = PowerDownState.PowerOffCompleted
                }, request.Container.Token, new TransportResponseConfig() { Completed = true });
            });
        }

        private async void HandleAbortPowerDownRequest(TangoMessage<AbortPowerDownRequest> request)
        {
            _abortPowerDown = true;
            await Task.Delay(1000);
            await Transporter.SendResponse<AbortPowerDownResponse>(new AbortPowerDownResponse(), request.Container.Token);
        }

        private async void HandleStartThreadLoadingRequest(TangoMessage<StartThreadLoadingRequest> request)
        {
            _isThreadLoadingStarted = true;
            _threadLoadingToken = request.Container.Token;
            await Transporter.SendResponse<StartThreadLoadingResponse>(new StartThreadLoadingResponse(), request.Container.Token);
        }

        private async void HandleTryThreadLoadingRequest(TangoMessage<TryThreadLoadingRequest> request)
        {
            await Transporter.SendResponse<TryThreadLoadingResponse>(new TryThreadLoadingResponse(), request.Container.Token);
            StartThreadLoading();
        }

        private async void HandleContinueThreadLoadingRequest(TangoMessage<ContinueThreadLoadingRequest> request)
        {
            if (_threadLoadingToken != null)
            {
                await Transporter.SendResponse<ContinueThreadLoadingResponse>(new ContinueThreadLoadingResponse(), request.Container.Token);

                await Task.Delay(1000);
                await Transporter.SendResponse<StartThreadLoadingResponse>(new StartThreadLoadingResponse() { State = ThreadLoadingState.Finalizing }, _threadLoadingToken);
                await Task.Delay(8000);

                //if (_rnd.Next(0, 100) > 50)
                //{
                await Transporter.SendResponse<StartThreadLoadingResponse>(new StartThreadLoadingResponse() { State = ThreadLoadingState.Completed }, _threadLoadingToken);
                //}
                //else
                //{
                //    await Transporter.SendResponse<StartThreadLoadingResponse>(new StartThreadLoadingResponse() { State = ThreadLoadingState.FinalizationError, ErrorReason = "Emulator random error." }, _threadLoadingToken);
                //}
            }
            else
            {
                await Transporter.SendResponse<ContinueThreadLoadingResponse>(new ContinueThreadLoadingResponse(), request.Container.Token, new TransportResponseConfig() { ErrorCode = ErrorCode.GeneralError, ErrorMessage = "StartThreadLoadingRequest was never sent." });
            }
        }

        private async void HandleStartHeadCleaningRequest(TangoMessage<StartHeadCleaningRequest> request)
        {
            _abortHeadCleaning = false;

            for (int i = 0; i < 100; i++)
            {
                if (_abortHeadCleaning)
                {
                    await Transporter.SendResponse<StartHeadCleaningResponse>(new StartHeadCleaningResponse()
                    {

                    }, request.Container.Token, new TransportResponseConfig()
                    {
                        Completed = true,
                        ErrorCode = ErrorCode.ContinuousResponseAborted
                    });

                    return;
                }

                await Task.Delay(200);
                await Transporter.SendResponse<StartHeadCleaningResponse>(new StartHeadCleaningResponse()
                {
                    Progress = i++,
                    Total = 100,
                    Status = $"Performing head cleaning..."
                }, request.Container.Token);
            }

            await Task.Delay(500);

            await Transporter.SendResponse<StartHeadCleaningResponse>(new StartHeadCleaningResponse()
            {
                Progress = 100,
                Total = 100,
                Status = "Completed",
            }, request.Container.Token, new TransportResponseConfig() { Completed = true });
        }

        private async void HandleAbortHeadCleaningRequest(TangoMessage<AbortHeadCleaningRequest> request)
        {
            if (_rnd.Next(0, 100) > 60)
            {
                _abortHeadCleaning = true;
                await Task.Delay(1000);
                await Transporter.SendResponse<AbortHeadCleaningResponse>(new AbortHeadCleaningResponse(), request.Container.Token);
            }
        }

        private async void HandleStartPowerUpRequest(TangoMessage<StartPowerUpRequest> request)
        {
            await Transporter.SendResponse(new StartPowerUpResponse() { Message = "Power up started...", ProgressPercentage = 10, State = PowerUpState.BuiltInTest }, request.Container.Token);
            Thread.Sleep(1000);

            await Transporter.SendResponse(new StartPowerUpResponse() { Message = "Testing dispensers...", ProgressPercentage = 20, State = PowerUpState.DispenserPressureBuildupTest }, request.Container.Token);
            Thread.Sleep(1000);

            await Transporter.SendResponse(new StartPowerUpResponse() { Message = "Heating started...", ProgressPercentage = 30, State = PowerUpState.HeatingStarted }, request.Container.Token);
            Thread.Sleep(1000);

            await Transporter.SendResponse(new StartPowerUpResponse() { Message = "Heating started...", ProgressPercentage = 40, State = PowerUpState.HwConfig }, request.Container.Token);
            Thread.Sleep(1000);

            await Transporter.SendResponse(new StartPowerUpResponse() { Message = "Hardware configuration...", ProgressPercentage = 50, State = PowerUpState.HwConfig }, request.Container.Token);
            Thread.Sleep(1000);

            await Transporter.SendResponse(new StartPowerUpResponse() { Message = "Initializing blower...", ProgressPercentage = 60, State = PowerUpState.InitialBlowerActivation }, request.Container.Token);
            Thread.Sleep(1000);

            await Transporter.SendResponse(new StartPowerUpResponse() { Message = "Thread detection...", ProgressPercentage = 70, State = PowerUpState.ThreadDetection }, request.Container.Token);
            Thread.Sleep(1000);

            await Transporter.SendResponse(new StartPowerUpResponse() { Message = "Waiting for cooler...", ProgressPercentage = 80, State = PowerUpState.WaitForCooler }, request.Container.Token);
            Thread.Sleep(4000);

            await Transporter.SendResponse(new StartPowerUpResponse() { Message = "Ready to dye...", ProgressPercentage = 90, State = PowerUpState.MachineReadyToDye }, request.Container.Token, new TransportResponseConfig()
            {
                Completed = true
            });
        }

        private void HandleStartInkFillingStatusRequest(TangoMessage<StartInkFillingStatusRequest> request)
        {
            Task.Factory.StartNew(() =>
            {
                while (IsStarted)
                {
                    if (!_emulateCorruption)
                    {
                        Transporter.SendResponse(new StartInkFillingStatusResponse()
                        {
                            Status = InkFillingStatus
                        }, request.Container.Token);
                    }

                    Thread.Sleep(2000);
                }
            });
        }

        private async void HandleStandByRequest(TangoMessage<StandByRequest> request)
        {
            await Task.Delay(1500);
            MachineStatus.State = MachineState.Sleep;
            await Transporter.SendResponse(new StandByResponse(), request.Container.Token);
        }

        private async void HandleAttemptThreadJoggingRequest(TangoMessage<AttemptThreadJoggingRequest> request)
        {
            await Task.Delay(3000);

            if (_rnd.Next(0, 100) > 50)
            {
                await Transporter.SendResponse(new AttemptThreadJoggingResponse(), request.Container.Token);
            }
            else
            {
                await Transporter.SendResponse(new AttemptThreadJoggingResponse(), request.Container.Token, new TransportResponseConfig() { ErrorCode = ErrorCode.GeneralError });
            }
        }

        private async void HandleDataStoreItemModifiedRequest(TangoMessage<DataStoreItemModifiedRequest> request)
        {
            await Transporter.SendResponse<DataStoreItemModifiedResponse>(new DataStoreItemModifiedResponse(), request.Container.Token);

            GetDataStoreItem(new GetDataStoreItemRequest()
            {
                Collection = request.Message.Collection,
                Key = request.Message.Key
            });
        }

        private async void HandleJobPrepareRequest(TangoMessage<JobPrepareRequest> request)
        {
            await Task.Delay(2000);
            await Transporter.SendResponse<JobPrepareResponse>(new JobPrepareResponse(), request.Container.Token);
        }

        private async void HandleSetInkAutoFillingModeRequest(TangoMessage<SetInkAutoFillingModeRequest> request)
        {
            await Task.Delay(1000);
            MachineStatus.AutoInkFillingDisabled = request.Message.Disabled;
            await Transporter.SendResponse<SetInkAutoFillingModeResponse>(new SetInkAutoFillingModeResponse(), request.Container.Token);
        }

        private async void HandleBitResultsRequest(TangoMessage<BitResultsRequest> request)
        {
            await Task.Delay(10000);

            BitResultsResponse response = new BitResultsResponse();

            foreach (var bitType in Enum.GetValues(typeof(PMR.Diagnostics.BitType)).Cast<PMR.Diagnostics.BitType>().ToList())
            {
                BitResult result = new BitResult();
                result.BitType = bitType;

                var rnd = _rnd.Next(0, 100);

                if (rnd < 25)
                {
                    result.Status = BitResultStatus.Skipped;
                    result.Description = "Skipped";
                }
                else if (rnd >= 25 && rnd < 50)
                {
                    result.Status = BitResultStatus.Passed;
                }
                else if (rnd >= 50 && rnd < 75)
                {
                    result.Status = BitResultStatus.Failed;
                    result.Description = "Emulator error message";
                }
                else if (rnd >= 75)
                {
                    result.Status = BitResultStatus.Warning;
                    result.Description = "Emulator warning message";
                }

                response.Results.Add(result);
            }

            await Transporter.SendResponse<BitResultsResponse>(response, request.Container.Token);
        }

        private async void HandleSpoolTypeChangedRequest(TangoMessage<SpoolTypeChangedRequest> request)
        {
            LogManager.Log($"Spool type changed: '{request.Message.SpoolType}'.");
            await Transporter.SendResponse<SpoolTypeChangedResponse>(new SpoolTypeChangedResponse(), request.Container.Token);
        }

        #endregion

        #region Public Methods

        public async Task<int> ValidateCartridge()
        {
            var response = await Transporter.SendRequest<CartridgeValidationRequest, CartridgeValidationResponse>(new CartridgeValidationRequest()
            {
                Action = CartridgeAction.Inserted,

            }, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(10) });

            return response.Message.Index;
        }

        public async void StartThreadLoading()
        {
            await Transporter.SendResponse<StartThreadLoadingResponse>(new StartThreadLoadingResponse() { State = ThreadLoadingState.Preparing }, _threadLoadingToken);
            await Task.Delay(8000);

            if (_rnd.Next(0, 100) > 50)
            {
                await Transporter.SendResponse<StartThreadLoadingResponse>(new StartThreadLoadingResponse() { State = ThreadLoadingState.PreparationError, ErrorReason = "Emulator preparation random error." }, _threadLoadingToken);
            }
            else
            {
                await Transporter.SendResponse<StartThreadLoadingResponse>(new StartThreadLoadingResponse() { State = ThreadLoadingState.ReadyForLoading }, _threadLoadingToken);
            }
        }

        public async void FinalizeThreadLoading()
        {
            await Transporter.SendResponse<StartThreadLoadingResponse>(new StartThreadLoadingResponse() { State = ThreadLoadingState.Finalizing }, _threadLoadingToken);
            await Task.Delay(3000);

            if (_rnd.Next(0, 100) > 50)
            {
                await Transporter.SendResponse<StartThreadLoadingResponse>(new StartThreadLoadingResponse() { State = ThreadLoadingState.Completed }, _threadLoadingToken);
            }
            else
            {
                await Transporter.SendResponse<StartThreadLoadingResponse>(new StartThreadLoadingResponse() { State = ThreadLoadingState.FinalizationError, ErrorReason = "Emulator finalization random error." }, _threadLoadingToken);
            }
        }

        public void AbortJob()
        {
            _cancelJob = true;
        }

        public async void SetThreadLoadingState(ThreadLoadingState state)
        {
            await Transporter.SendResponse<StartThreadLoadingResponse>(new StartThreadLoadingResponse() { State = state, Message = $"{state.ToString()}", ErrorReason = "Fake emulator error" }, _threadLoadingToken);
        }

        public async void PerformDataStoreTest()
        {
            LogManager.Log("Starting data store test...");

            {
                try
                {
                    LogManager.Log("Testing Int32...");

                    var response = await Transporter.SendRequest<PutDataStoreItemRequest, PutDataStoreItemResponse>(new PutDataStoreItemRequest()
                    {
                        Collection = "TEST",
                        Key = "int",
                        Item = new PMR.DataStore.DataStoreItem()
                        {
                            DataType = DataType.Int32,
                            Int32Value = 100
                        }
                    });

                    if (response.Container.Error != ErrorCode.None)
                    {
                        LogManager.Log("Put Failed.");
                        LogManager.Log(response.ToJsonString());
                    }
                    else
                    {
                        var res = await Transporter.SendRequest<GetDataStoreItemRequest, GetDataStoreItemResponse>(new GetDataStoreItemRequest()
                        {
                            Collection = "TEST",
                            Key = "int"
                        });

                        LogManager.Log(res.Container.Error != ErrorCode.None ? "Get Failed." : "Passed.");

                        LogManager.Log(res.ToJsonString());
                    }
                }
                catch (Exception ex)
                {
                    LogManager.Log(ex, "Failed.");
                }
            }

            {
                try
                {
                    LogManager.Log("Testing float...");

                    var response = await Transporter.SendRequest<PutDataStoreItemRequest, PutDataStoreItemResponse>(new PutDataStoreItemRequest()
                    {
                        Collection = "TEST",
                        Key = "float",
                        Item = new PMR.DataStore.DataStoreItem()
                        {
                            DataType = DataType.Float,
                            FloatValue = 101f
                        }
                    });

                    if (response.Container.Error != ErrorCode.None)
                    {
                        LogManager.Log("Put Failed.");
                        LogManager.Log(response.ToJsonString());
                    }
                    else
                    {
                        var res = await Transporter.SendRequest<GetDataStoreItemRequest, GetDataStoreItemResponse>(new GetDataStoreItemRequest()
                        {
                            Collection = "TEST",
                            Key = "float"
                        });

                        LogManager.Log(res.Container.Error != ErrorCode.None ? "Get Failed." : "Passed.");

                        LogManager.Log(res.ToJsonString());
                    }
                }
                catch (Exception ex)
                {
                    LogManager.Log(ex, "Failed.");
                }
            }

            {
                try
                {
                    LogManager.Log("Testing double...");

                    var response = await Transporter.SendRequest<PutDataStoreItemRequest, PutDataStoreItemResponse>(new PutDataStoreItemRequest()
                    {
                        Collection = "TEST",
                        Key = "double",
                        Item = new PMR.DataStore.DataStoreItem()
                        {
                            DataType = DataType.Double,
                            DoubleValue = 102d
                        }
                    });

                    if (response.Container.Error != ErrorCode.None)
                    {
                        LogManager.Log("Put Failed.");
                        LogManager.Log(response.ToJsonString());
                    }
                    else
                    {
                        var res = await Transporter.SendRequest<GetDataStoreItemRequest, GetDataStoreItemResponse>(new GetDataStoreItemRequest()
                        {
                            Collection = "TEST",
                            Key = "double"
                        });

                        LogManager.Log(res.Container.Error != ErrorCode.None ? "Get Failed." : "Passed.");

                        LogManager.Log(res.ToJsonString());
                    }
                }
                catch (Exception ex)
                {
                    LogManager.Log(ex, "Failed.");
                }
            }

            {
                try
                {
                    LogManager.Log("Testing boolean...");

                    var response = await Transporter.SendRequest<PutDataStoreItemRequest, PutDataStoreItemResponse>(new PutDataStoreItemRequest()
                    {
                        Collection = "TEST",
                        Key = "bool",
                        Item = new PMR.DataStore.DataStoreItem()
                        {
                            DataType = DataType.Boolean,
                            BooleanValue = true
                        }
                    });

                    if (response.Container.Error != ErrorCode.None)
                    {
                        LogManager.Log("Put Failed.");
                        LogManager.Log(response.ToJsonString());
                    }
                    else
                    {
                        var res = await Transporter.SendRequest<GetDataStoreItemRequest, GetDataStoreItemResponse>(new GetDataStoreItemRequest()
                        {
                            Collection = "TEST",
                            Key = "bool"
                        });

                        LogManager.Log(res.Container.Error != ErrorCode.None ? "Get Failed." : "Passed.");

                        LogManager.Log(res.ToJsonString());
                    }
                }
                catch (Exception ex)
                {
                    LogManager.Log(ex, "Failed.");
                }
            }

            {
                try
                {
                    LogManager.Log("Testing string...");

                    var response = await Transporter.SendRequest<PutDataStoreItemRequest, PutDataStoreItemResponse>(new PutDataStoreItemRequest()
                    {
                        Collection = "TEST",
                        Key = "string",
                        Item = new PMR.DataStore.DataStoreItem()
                        {
                            DataType = DataType.String,
                            StringValue = "String Value"
                        }
                    });

                    if (response.Container.Error != ErrorCode.None)
                    {
                        LogManager.Log("Put Failed.");
                        LogManager.Log(response.ToJsonString());
                    }
                    else
                    {
                        var res = await Transporter.SendRequest<GetDataStoreItemRequest, GetDataStoreItemResponse>(new GetDataStoreItemRequest()
                        {
                            Collection = "TEST",
                            Key = "string"
                        });

                        LogManager.Log(res.Container.Error != ErrorCode.None ? "Get Failed." : "Passed.");

                        LogManager.Log(res.ToJsonString());
                    }
                }
                catch (Exception ex)
                {
                    LogManager.Log(ex, "Failed.");
                }
            }

            {
                try
                {
                    LogManager.Log("Testing bytes...");

                    var response = await Transporter.SendRequest<PutDataStoreItemRequest, PutDataStoreItemResponse>(new PutDataStoreItemRequest()
                    {
                        Collection = "TEST",
                        Key = "bytes",
                        Item = new PMR.DataStore.DataStoreItem()
                        {
                            DataType = DataType.Bytes,
                            BytesValue = ByteString.CopyFromUtf8("Bytes TEST TEST TEST"),
                        }
                    });

                    if (response.Container.Error != ErrorCode.None)
                    {
                        LogManager.Log("Put Failed.");
                        LogManager.Log(response.ToJsonString());
                    }
                    else
                    {
                        var res = await Transporter.SendRequest<GetDataStoreItemRequest, GetDataStoreItemResponse>(new GetDataStoreItemRequest()
                        {
                            Collection = "TEST",
                            Key = "bytes"
                        });

                        LogManager.Log(res.Container.Error != ErrorCode.None ? "Get Failed." : "Passed.");

                        LogManager.Log(res.Message.Item.BytesValue.ToStringUtf8());
                        LogManager.Log(res.ToJsonString());
                    }
                }
                catch (Exception ex)
                {
                    LogManager.Log(ex, "Failed.");
                }
            }

            {
                try
                {
                    LogManager.Log("Testing proto...");

                    var response = await Transporter.SendRequest<PutDataStoreItemRequest, PutDataStoreItemResponse>(new PutDataStoreItemRequest()
                    {
                        Collection = "TEST",
                        Key = "proto",
                        Item = new PMR.DataStore.DataStoreItem()
                        {
                            DataType = DataType.Proto,
                            BytesValue = new CalculateRequest() { A = 10, B = 15 }.ToByteString(),
                            ProtoType = DataStoreMessageType.CalculateRequest,
                        }
                    });

                    if (response.Container.Error != ErrorCode.None)
                    {
                        LogManager.Log("Put Failed.");
                        LogManager.Log(response.ToJsonString());
                    }
                    else
                    {
                        var res = await Transporter.SendRequest<GetDataStoreItemRequest, GetDataStoreItemResponse>(new GetDataStoreItemRequest()
                        {
                            Collection = "TEST",
                            Key = "proto"
                        });

                        LogManager.Log(res.Container.Error != ErrorCode.None ? "Get Failed." : "Passed.");

                        LogManager.Log(CalculateRequest.Parser.ParseFrom(res.Message.Item.BytesValue).ToJsonString());
                        LogManager.Log(res.ToJsonString());
                    }
                }
                catch (Exception ex)
                {
                    LogManager.Log(ex, "Failed.");
                }
            }

            {
                try
                {
                    LogManager.Log("Testing int default...");

                    var res = await Transporter.SendRequest<GetDataStoreItemRequest, GetDataStoreItemResponse>(new GetDataStoreItemRequest()
                    {
                        Collection = "TEST",
                        Key = "intDefault",
                        DefaultItem = new PMR.DataStore.DataStoreItem()
                        {
                            DataType = DataType.Int32,
                            Int32Value = 10,
                        },
                    });

                    LogManager.Log(res.Container.Error != ErrorCode.None ? "Get Failed." : "Passed.");
                    LogManager.Log(res.ToJsonString());
                }
                catch (Exception ex)
                {
                    LogManager.Log(ex, "Failed.");
                }
            }

            {
                try
                {
                    LogManager.Log("Testing proto default...");

                    var res = await Transporter.SendRequest<GetDataStoreItemRequest, GetDataStoreItemResponse>(new GetDataStoreItemRequest()
                    {
                        Collection = "TEST",
                        Key = "protoDefault",
                        DefaultItem = new PMR.DataStore.DataStoreItem()
                        {
                            DataType = DataType.Proto,
                            BytesValue = (new CalculateRequest() { A = 10, B = 15 }).ToByteString(),
                            ProtoType = DataStoreMessageType.CalculateRequest,
                        },
                    });

                    LogManager.Log(res.Container.Error != ErrorCode.None ? "Get Failed." : "Passed.");

                    LogManager.Log(CalculateRequest.Parser.ParseFrom(res.Message.Item.BytesValue).ToJsonString());
                    LogManager.Log(res.ToJsonString());
                }
                catch (Exception ex)
                {
                    LogManager.Log(ex, "Failed.");
                }
            }
        }

        public async void PutDataStoreItem(PutDataStoreItemRequest request)
        {
            LogManager.Log($"Sending PutDataStoreItemRequest:\n{request.ToJsonString()}");
            try
            {
                var response = await Transporter.SendRequest<PutDataStoreItemRequest, PutDataStoreItemResponse>(request);
            }
            catch (Exception ex)
            {
                LogManager.Log(ex, "Error putting data store item.");
            }
        }

        public async void GetDataStoreItem(GetDataStoreItemRequest request)
        {
            LogManager.Log($"Sending GetDataStoreItemRequest:\n{request.ToJsonString()}");
            try
            {
                var response = await Transporter.SendRequest<GetDataStoreItemRequest, GetDataStoreItemResponse>(request);

                String protoJson = String.Empty;

                try
                {
                    if (response.Message.Item.DataType == DataType.Proto)
                    {
                        var type = MessageFactory.GetDataStorePMRTypeFromDataStoreMessageType(response.Message.Item.ProtoType);
                        var instance = MessageFactory.ParseProtoMessage(response.Message.Item.BytesValue.ToByteArray(), type);
                        protoJson = instance.ToJsonString();
                    }
                }
                catch (Exception ex)
                {
                    protoJson = ex.Message;
                }

                LogManager.Log($"Received GetDataStoreItemResponse:\n{response.Message.ToJsonString()}\nProtobuf Message:\n{protoJson}");

            }
            catch (Exception ex)
            {
                LogManager.Log(ex, "Error getting data store item.");
            }
        }

        #endregion
    }
}