// Created with MonoDevelop
//
//    Copyright (C) 2023 Hiperscan GmbH Dresden, Germany
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Runtime.InteropServices;

using Hiperscan.SGS.Common;
using Hiperscan.SGS.Benchtop.LightSourceControl;
using Hiperscan.SGS.Benchtop.TemperatureControl;

namespace Hiperscan.SGS.SgsNt.Protocol
{
    public abstract partial class BaseProtocol
    {
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct HardwarePcbData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.U1)] public byte Board;
            [MarshalAs(UnmanagedType.U1)] public byte FinderPosition;
            [MarshalAs(UnmanagedType.U1)] public byte LightSource;
            [MarshalAs(UnmanagedType.U1)] public byte Casing;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct FirmwareInfoReadData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.U2)] public UInt16 Major;
            [MarshalAs(UnmanagedType.U2)] public UInt16 Minor;
            [MarshalAs(UnmanagedType.U2)] public UInt16 Patch;
            [MarshalAs(UnmanagedType.U2)] public UInt16 Build;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct KeyData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.U1)] public KeyIndex Index;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = BaseDevice.KEY_PAD_SIZE)]
            public byte[] Key;

            public KeyData(KeyIndex index, byte[] data) : this()
            {
                this.Index = index;
                this.Key = new byte[BaseDevice.KEY_PAD_SIZE];
                Array.Copy(data, this.Key, data.Length);
            }
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct ChallengeData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.U1)] public KeyIndex Index;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = BaseDevice.KEY_SIZE)]
            public byte[] Key;

            public ChallengeData(KeyIndex index, byte[] data) : this()
            {
                this.Index = index;
                this.Key = new byte[BaseDevice.KEY_SIZE];
                Array.Copy(data, this.Key, data.Length);
            }
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct PeripheralInfoReadData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] VersionBytes;

            [MarshalAs(UnmanagedType.U1)] public byte MajorProtocolVersion;
            [MarshalAs(UnmanagedType.U1)] public byte MinorProtocolVersion;
            [MarshalAs(UnmanagedType.U1)] public byte MajorFirmwareVersion;
            [MarshalAs(UnmanagedType.U1)] public byte MinorFirmwareVersion;
            [MarshalAs(UnmanagedType.U1)] public byte PeripheralId;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct LutReadData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.U8)] public UInt64 Timestamp;
            [MarshalAs(UnmanagedType.U4)] public UInt32 SkipCount;
            [MarshalAs(UnmanagedType.R4)] public float MinWavelength;
            [MarshalAs(UnmanagedType.R4)] public float MaxWavelength;
            [MarshalAs(UnmanagedType.R4)] public float Increment;
            [MarshalAs(UnmanagedType.R4)] public float ExtensionRange;
            [MarshalAs(UnmanagedType.U4)] public UInt32 DarkIntensityEndpoint;
            [MarshalAs(UnmanagedType.U4)] public UInt32 Length;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2800)]
            public float[] Data;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct LutWriteData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.U1)] public byte Channel;
            [MarshalAs(UnmanagedType.U8)] public UInt64 Timestamp;
            [MarshalAs(UnmanagedType.U4)] public UInt32 SkipCount;
            [MarshalAs(UnmanagedType.R4)] public float MinWavelength;
            [MarshalAs(UnmanagedType.R4)] public float MaxWavelength;
            [MarshalAs(UnmanagedType.R4)] public float Increment;
            [MarshalAs(UnmanagedType.R4)] public float ExtensionRange;
            [MarshalAs(UnmanagedType.U4)] public UInt32 DarkIntensityEndpoint;
            [MarshalAs(UnmanagedType.U4)] public UInt32 Length;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2800)]
            public float[] Data;

            public LutWriteData(Spectrometer.LUT lut) : this()
            {
                this.Channel = lut.AcquisitionChannelMask;
                this.Timestamp = (ulong)lut.Timestamp.Ticks;
                this.SkipCount = lut.SkipCount;
                this.MinWavelength = (uint)lut.MinWavelength;  // FIXME: remove cast if type is corrected
                this.MaxWavelength = (uint)lut.MaxWavelength;
                this.Increment = (uint)lut.Increment;
                this.ExtensionRange = (uint)lut.ExtensionRange;
                this.DarkIntensityEndpoint = lut.DarkIntensityEndpoint;
                this.Length = (uint)lut.Length;

                this.Data = new float[lut.Length];
                Array.Copy(lut.Data, this.Data, lut.Length);
            }

            public LutWriteData(ChannelType channel, LutReadData lut_read_data) : this()
            {
                this.Channel = (byte)channel;
                this.Timestamp = lut_read_data.Timestamp;
                this.SkipCount = lut_read_data.SkipCount;
                this.MinWavelength = lut_read_data.MinWavelength;
                this.MaxWavelength = lut_read_data.MaxWavelength;
                this.Increment = lut_read_data.Increment;
                this.ExtensionRange = lut_read_data.ExtensionRange;
                this.DarkIntensityEndpoint = lut_read_data.DarkIntensityEndpoint;
                this.Length = lut_read_data.Length;

                this.Data = new float[this.Length];
                Array.Copy(lut_read_data.Data, this.Data, lut_read_data.Length);
            }
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct IntensityReadData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.R4)] public float MemsFrequency;
            [MarshalAs(UnmanagedType.R4)] public float Temperature;
            [MarshalAs(UnmanagedType.R4)] public float DarkIntensity;
            [MarshalAs(UnmanagedType.U1)] public byte AcquisitionChannelMask;
            [MarshalAs(UnmanagedType.U2)] public ushort Average;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2768)]
            public float[] Intensities;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct FinderReadDataStatus : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.Struct)] public CapsuleHeaterReadData Capsule;
            [MarshalAs(UnmanagedType.Struct)] public DetectorStateReadData DetectorState;
            [MarshalAs(UnmanagedType.Struct)] public DetectorHeaterReadData Detector;
            [MarshalAs(UnmanagedType.I2)] public short finder_temp;
            [MarshalAs(UnmanagedType.I2)] public short finder_status;

            [MarshalAs(UnmanagedType.I2)] public short scan_engine_temp;
            [MarshalAs(UnmanagedType.I2)] public short error_flag;

            [MarshalAs(UnmanagedType.Struct)] public EnvironmentReadData Environment;
            [MarshalAs(UnmanagedType.Struct)] public LightSourceStateReadData LightSourceState;
            [MarshalAs(UnmanagedType.Struct)] public LightSourceOperatingTimeCounter LightSourceOperatingTime;
            [MarshalAs(UnmanagedType.U4)] public uint system_write_operations;

            public DeviceTemperatures GetUpdatedDeviceTemperatures(DeviceTemperatures temperatures)
            {
                temperatures = temperatures.Clone();
                if (temperatures.SupportsCapsule)
                    temperatures.Capsule = this.GetUpdatedCapsule(temperatures.Capsule);
                if (temperatures.SupportsDetector)
                    temperatures.Detector = this.GetUpdatedDetector(temperatures.Detector);
                if (temperatures.SupportsEnvironment)
                    temperatures.Environment = this.GetUpdatedEnvironmentQuery(temperatures.Environment);
                if (temperatures.SupportsScanEngine)
                    temperatures.ScanEngine = this.GetUpdatedScanEngine(temperatures.ScanEngine);
                if (temperatures.SupportsFinder)
                    temperatures.Finder = this.GetUpdatedFinderTemperature(temperatures.Finder);
                return temperatures;
            }

            public CapsuleTemperature GetUpdatedCapsule(CapsuleTemperature capsule)
            {
                capsule = capsule.Clone();
                capsule.ActualTemperature.Add(((double)this.Capsule.ActTemperature) / 100.00);
                capsule.SetTemperature = ((double)this.Capsule.SetTemperature) / 100.00;
                capsule.ConvertToMode(this.Capsule.Mode);
                return capsule;
            }

            public DetectorTemperature GetUpdatedDetector(DetectorTemperature detector)
            {
                detector = detector.Clone();

                detector.State = this.DetectorState.State;
                detector.Sensor = this.DetectorState.Sensor;

                detector.AmplifierTemperature.Add(((double)this.Detector.AmplifierTemperature) / 100.00);
                detector.TransisitorTemperature.Add(((double)this.Detector.TransistorTemperature) / 100.00);
                detector.SetTemperature = ((double)this.Detector.SetTemperature) / 100.00;
                detector.PidControl.ProportionalComponent = this.Detector.ProportionalComponent;
                detector.PidControl.IntegralComponent = this.Detector.IntegralComponent;
                detector.PidControl.DerivativeComponent = this.Detector.DerivativeComponent;
                return detector;
            }

            public Temperature GetUpdatedFinderTemperature(Temperature finder_temperature)
            {
                finder_temperature.Add(((double)this.finder_temp) / 100.00);
                return finder_temperature;
            }

            public Temperature GetUpdatedScanEngine(Temperature scan_engine_temperature)
            {
                scan_engine_temperature.Add(((double)this.scan_engine_temp) / 100.00);
                return scan_engine_temperature;
            }

            public EnvironmentQuery GetUpdatedEnvironmentQuery(EnvironmentQuery environment)
            {
                environment.AtmosphericPressure = this.Environment.AtmosphericPressure;
                environment.Humidity = this.Environment.Humidity;
                environment.PeripheralBoardTemperature.Add(((double)this.Environment.TouchBoardTemperature) / 100.00);
                environment.TouchBoardTemperature.Add(((double)this.Environment.PeripheralBoardTemperature) / 100.00);
                return environment;
            }

            public LightSourceQuery GetNewLightSourceQuery()
            {
                return new LightSourceQuery()
                {
                    ActLampCurrent_mA = this.LightSourceState.LampCurrent,
                    LampSelection = this.LightSourceState.LampActSelection,
                    ActLampVoltag_mV = this.LightSourceState.LampActVoltage,
                    SetLampVoltage_mV = this.LightSourceState.LampSetVoltage,
                    State = this.LightSourceState.State
                };
            }

            public LightSourceOperatingTimes GetNewLightSourceOperatingTimes()
            {
                return new LightSourceOperatingTimes()
                {
                    Lamp1OperatingTimeSeconds = this.LightSourceOperatingTime.Lamp1OperatingTimeSeconds,
                    Lamp1SwitchedCycles = this.LightSourceOperatingTime.Lamp1SwitchedCycles,
                    Lamp2OperatingTimeSeconds = this.LightSourceOperatingTime.Lamp2OperatingTimeSeconds,
                    Lamp2SwitchedCycles = this.LightSourceOperatingTime.Lamp2SwitchedCycles,
                    Lamp3OperatingTimeSeconds = this.LightSourceOperatingTime.Lamp3OperatingTimeSeconds,
                    Lamp3SwitchedCycles = this.LightSourceOperatingTime.Lamp3SwitchedCycles,
                    SystemOperatingTimeSeconds = this.LightSourceOperatingTime.SystemOperatingTimeSeconds,
                };
            }

            public short GetErrorFlag()
            {
                return this.error_flag;
            }
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct StepperSpeedWriteData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.U4)] public uint StepperSpeed;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct IntensityReadDataExtended : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.R4)] public float MemsFrequency;
            [MarshalAs(UnmanagedType.R4)] public float Temperature;
            [MarshalAs(UnmanagedType.R4)] public float DarkIntensity;
            [MarshalAs(UnmanagedType.U1)] public byte AcquisitionChannelMask;
            [MarshalAs(UnmanagedType.U2)] public ushort Average;

            [MarshalAs(UnmanagedType.Struct)] public CapsuleHeaterReadData Capsule;
            [MarshalAs(UnmanagedType.Struct)] public DetectorStateReadData DetectorState;
            [MarshalAs(UnmanagedType.Struct)] public DetectorHeaterReadData Detector;

            [MarshalAs(UnmanagedType.I2)] public short finder_temp;
            [MarshalAs(UnmanagedType.I2)] public short finder_status;
            [MarshalAs(UnmanagedType.I2)] public short scan_engine_temp;
            [MarshalAs(UnmanagedType.I2)] public short error_flag;

            [MarshalAs(UnmanagedType.Struct)] public EnvironmentReadData Environment;
            [MarshalAs(UnmanagedType.Struct)] public LightSourceStateReadData LightSourceState;
            [MarshalAs(UnmanagedType.Struct)] public LightSourceOperatingTimeCounter LightSourceOperatingTime;
            [MarshalAs(UnmanagedType.U4)] public uint system_write_operations;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2768)]
            public float[] Intensities;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct StatusReadData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.I2)] public short Temperature;
            [MarshalAs(UnmanagedType.U2)] public ushort ErrorFlag;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct TcrtlInfoData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.U1)] public byte Version;
            [MarshalAs(UnmanagedType.U1)] public byte ControlValue;
            [MarshalAs(UnmanagedType.I2)] public Int16 TargetTemperature;

            public TcrtlInfoData(byte version, byte control_value, double target_temperature) : this()
            {
                this.Version = version;
                this.ControlValue = control_value;
                this.TargetTemperature = (Int16)(target_temperature * 100.0);
            }
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct HwPropertyData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
            public byte[] Type;
            [MarshalAs(UnmanagedType.U2)] public UInt16 GridConstant;
            [MarshalAs(UnmanagedType.U2)] public UInt16 IncidenceAngle;
            [MarshalAs(UnmanagedType.U2)] public UInt16 DiffractionAngle;
            [MarshalAs(UnmanagedType.I2)] public Int16 MinTemperature;
            [MarshalAs(UnmanagedType.I2)] public Int16 MaxTemperature;
            [MarshalAs(UnmanagedType.U2)] public UInt16 SpectralResolution;
            [MarshalAs(UnmanagedType.U2)] public UInt16 WavelengthDrift;
            [MarshalAs(UnmanagedType.U4)] public UInt32 Sensitivity;
            [MarshalAs(UnmanagedType.U2)] public UInt16 SignalNoiseRatio;
            [MarshalAs(UnmanagedType.U2)] public UInt16 DynamicRange;

            public HwPropertyData(HardwareProperties hw) : this()
            {
                this.Type = new byte[2];

                if (hw.Type.Length == 1)
                    hw.Type += " ";

                if (hw.Type.Length == 2)
                {
                    this.Type[0] = (byte)hw.Type[0];
                    this.Type[1] = (byte)hw.Type[1];
                }
                else
                {
                    this.Type[0] = byte.MaxValue;
                    this.Type[1] = byte.MaxValue;
                }
                this.GridConstant = (UInt16)hw.GridConstant;
                this.IncidenceAngle = (UInt16)(hw.IncidenceAngle * 10.0);
                this.DiffractionAngle = (UInt16)(hw.DiffractionAngle * 10.0);
                this.MinTemperature = (Int16)(hw.MinTemperature * 100.0);
                this.MaxTemperature = (Int16)(hw.MaxTemperature * 100.0);
                this.SpectralResolution = (UInt16)(hw.SpectralResolution * 10.0);
                this.WavelengthDrift = (UInt16)(hw.WavelengthDrift * 10.0);
                this.Sensitivity = (UInt32)(hw.Sensitivity);
                this.SignalNoiseRatio = (UInt16)(hw.SignalNoiseRatio);
                this.DynamicRange = (UInt16)(hw.DynamicRange);
            }
        }

        // Neues Struct zur Parametrierung der Lichtquelle (Schreiben der Setzspannung und Auswahl der Leuchtmittel) die im Anschluss mit "FL"-Befehl An und Aus geschalten wird


        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct LightSourceConfigWriteData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.U2)] public UInt16 LampSetVoltage; // Vorschlag Umbenennung in LampSetVoltage --> Setz-/ Soll-Spannung der Lichtquelle in mV
            [MarshalAs(UnmanagedType.U1)] public LampSelection LampActSelection; // Im Device momentan gesetzte Auswahl der Lichtquelle(n) die mit dem "FL"-Befehl ein und aus geschalten werden; binäre Maskierung in einem Byte nach Schema: 0b00000L3L2L1 (L1-L3 Lampe 1 bis 3 mit Wert 1 für aktiv, Wert 0 inaktiv); Finder2 verfügt über --> L1,L2,(L3 (in Hardware vorhanden momentan jedoch ungenutzt)); Finder3 verfügt über --> L1,L2           
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct LightSourceStateReadData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.U2)] public LightSourceState State; // Rückgabe des Lichtquellenstatus (0 = Lichtquelle aus; 1= Lichtquelle aktiv; 2= Lichtquelle aktiv und stabil für den Messbetrieb; 3= Fehler Lampe kaputt (Lampenwendel im Kurzschluss oder offen)  
            [MarshalAs(UnmanagedType.U2)] public UInt16 LampSetVoltage; // Vorschlag Umbenennung in LampSetVoltage --> Setz-/ Soll-Spannung der Lichtquelle in mV
            [MarshalAs(UnmanagedType.U2)] public UInt16 LampActVoltage; // Vorschlag Umbenennung in LampActVoltage (Lamp Actual Voltage) ? --> Gemessene Ist-Spannung der Lichtquelle in mV
            [MarshalAs(UnmanagedType.R4)] public float LampCurrent; // Gemessener Ist-Strom durch die Lichtquelle in mA
            [MarshalAs(UnmanagedType.U1)] public LampSelection LampActSelection; // Im Device momentan gesetzte Auswahl der Lichtquelle(n) die mit dem "FL"-Befehl ein und aus geschalten werden; binäre Maskierung in einem Byte nach Schema: 0b00000L3L2L1 (L1-L3 Lampe 1 bis 3 mit Wert 1 für aktiv, Wert 0 inaktiv); Finder2 verfügt über --> L1,L2,(L3 (in Hardware vorhanden momentan jedoch ungenutzt)); Finder3 verfügt über --> L1,L2           
        }

        // Parameter für die Kapselheizung (Heizfolie angeklebt an optische Bank ES-20 + Temperaturfühler verschraubt mit optischer Bank)

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct CapsuleHeaterWriteData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct // Vorschlag Umbenennung CapsuleHeaterWrite Data
        {
            [MarshalAs(UnmanagedType.U2)] public UInt16 SetTemperature; // !Achtung! Hier können auch negative Werte zurückgegeben werden -> int16; Vorschlag Umbenennung: CapsuleHeaterSetTemperature; Regel Soll-Temperatur innerhalb der Kapsel in °C mit 2 Nachkommastellen x 100 
            [MarshalAs(UnmanagedType.U2)] public UInt16 Hysteresis; // Vorschlag Umbenennung: CapsuleHeaterHysteresis, Hysterese der Kapseltemperaturregelung in °C mit 2 Nachkommastellen x 100 
            [MarshalAs(UnmanagedType.U1)] public byte Mode; // Vorschlag Umbenennung: St; binäre Maskierung in einem Byte 0bMMxxxxHF MM codiert den Modus (00.. Stabilisierend, 01..Manuell, 10..Oszillierend) F und H steuern im manuellen Modus den Lüfter und die Heizung 1 = an, 0 = aus
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct CapsuleHeaterReadData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.I2)] public Int16 ActTemperature; // !Achtung! Hier können auch negative Werte zurückgegeben werden -> int16; Gemessene Ist-Temperatur an der optischen Bank innerhalb der Kapsel in °C mit 2 Nachkommastellen x 100
            [MarshalAs(UnmanagedType.I2)] public Int16 SetTemperature; // Regel Soll-Temperatur innerhalb der Kapsel in °C mit 2 Nachkommastellen x 100
            [MarshalAs(UnmanagedType.U2)] public UInt16 HysteresisTemperature;
            [MarshalAs(UnmanagedType.U1)] public byte Mode; // Vorschlag Umbenennung: CapsuleHeaterMode 
        }

        // Parameter für die Detektordiodenheizung (Transistor als Heizelement auf der Empfängerplatine, Regelung der Heizung erfolgt mittels autark arbeitender Aufsteckplatine DSES ((D)etektor(S)tabilisierung(E)bert(S)pektrometer)

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct DetectorHeaterWriteData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.U1)] public byte Enable;
            [MarshalAs(UnmanagedType.U1)] public byte Reset;
            [MarshalAs(UnmanagedType.U2)] public UInt16 SetTemperature; // Vorschlag Umbenennung DetectorHeaterSetTemperature
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct DetectorHeaterReadData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.I2)] public Int16 TransistorTemperature;
            [MarshalAs(UnmanagedType.I2)] public Int16 AmplifierTemperature;
            [MarshalAs(UnmanagedType.I2)] public Int16 SetTemperature;

            [MarshalAs(UnmanagedType.R4)] public float ProportionalComponent;
            [MarshalAs(UnmanagedType.R4)] public float IntegralComponent;
            [MarshalAs(UnmanagedType.R4)] public float DerivativeComponent;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct EnvironmentReadData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.I2)] public Int16 TouchBoardTemperature;
            [MarshalAs(UnmanagedType.I2)] public Int16 PeripheralBoardTemperature;

            [MarshalAs(UnmanagedType.R4)] public float AtmosphericPressure;
            [MarshalAs(UnmanagedType.R4)] public float Humidity;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct LightSourceVoltage : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            public LightSourceVoltage(LightSourceSettings voltages)
            {
                this.Lamp1Voltage = voltages.Lamp1Voltage_mV;
                this.Lamp2Voltage = voltages.Lamp2Voltage_mV;
                this.Lamp3Voltage = voltages.Lamp3Voltage_mV;
                this.Reserve = voltages.Reserved;
            }

            [MarshalAs(UnmanagedType.U2)] public UInt16 Lamp1Voltage;
            [MarshalAs(UnmanagedType.U2)] public UInt16 Lamp2Voltage;
            [MarshalAs(UnmanagedType.U2)] public UInt16 Lamp3Voltage;
            [MarshalAs(UnmanagedType.U2)] public UInt16 Reserve;
        }

        [StructLayout(LayoutKind.Sequential, Pack =1)]
        public struct LightSourceOperatingTimeCounter : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            internal SGS.Benchtop.LightSourceControl.LightSourceOperatingTimes GetLightSourceOperatingTimes()
            {
                return new LightSourceOperatingTimes()
                {
                    Lamp1OperatingTimeSeconds  = this.Lamp1OperatingTimeSeconds,
                    Lamp1SwitchedCycles        = this.Lamp1SwitchedCycles,
                    Lamp2OperatingTimeSeconds  = this.Lamp2OperatingTimeSeconds,
                    Lamp2SwitchedCycles        = this.Lamp2SwitchedCycles,
                    Lamp3OperatingTimeSeconds  = this.Lamp3OperatingTimeSeconds,
                    Lamp3SwitchedCycles        = this.Lamp3SwitchedCycles,
                    SystemOperatingTimeSeconds = this.SystemOperatingTimeSeconds,
                };
            }

            [MarshalAs(UnmanagedType.U4)] public UInt32 Lamp1OperatingTimeSeconds;
            [MarshalAs(UnmanagedType.U4)] public UInt32 Lamp1SwitchedCycles;
            [MarshalAs(UnmanagedType.U4)] public UInt32 Lamp2OperatingTimeSeconds;
            [MarshalAs(UnmanagedType.U4)] public UInt32 Lamp2SwitchedCycles;
            [MarshalAs(UnmanagedType.U4)] public UInt32 Lamp3OperatingTimeSeconds;
            [MarshalAs(UnmanagedType.U4)] public UInt32 Lamp3SwitchedCycles;
            [MarshalAs(UnmanagedType.U4)] public UInt32 SystemOperatingTimeSeconds;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct DetectorStateReadData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.U1)] public HeaterState State;
            [MarshalAs(UnmanagedType.U1)] public DetectorSensorType Sensor;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct DetectorPIDWriteData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.R4)] public float ProportionalComponent;
            [MarshalAs(UnmanagedType.R4)] public float IntegralComponent;
            [MarshalAs(UnmanagedType.R4)] public float DerivativeComponent;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct DetectorSensorWriteData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.U1)] public DetectorSensorType DestinationSensor;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct PositionDetectionSensorReadData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.R4)] public float Position;
            [MarshalAs(UnmanagedType.R4)] public float UpperPhotodiodeADC;
            [MarshalAs(UnmanagedType.R4)] public float LowerPhotodiodeADC;
            [MarshalAs(UnmanagedType.R4)] public float BrightnessUpperLightSensor;
            [MarshalAs(UnmanagedType.R4)] public float BrightnessLowerLightSensor;
            [MarshalAs(UnmanagedType.R4)] public float FlowDensityX;
            [MarshalAs(UnmanagedType.R4)] public float FlowDensityY;
            [MarshalAs(UnmanagedType.R4)] public float FlowDensityZ;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct SamplePositionDetectionData : Hiperscan.SGS.SgsNt.Protocol.BaseProtocol.ITransferStruct
        {
            [MarshalAs(UnmanagedType.R4)] public float UpperXMinMT;// = 1.6f,
            [MarshalAs(UnmanagedType.R4)] public float UpperAbsYMaxMT;// = 3.3f,
            [MarshalAs(UnmanagedType.R4)] public float UpperZMinMT;// = -26.6f,
            [MarshalAs(UnmanagedType.R4)] public float UpperZMaxMT;//= -8.0f,

            [MarshalAs(UnmanagedType.R4)] public float CenterXMaxMT;//= -18.6f,
            [MarshalAs(UnmanagedType.R4)] public float CenterAbsYMaxMT;//= 3.3f,
            [MarshalAs(UnmanagedType.R4)] public float CenterAbsZMaxMT;//= 4.6f,

            [MarshalAs(UnmanagedType.R4)] public float LowerXMinMT;//= 1.0f,
            [MarshalAs(UnmanagedType.R4)] public float LowerAbsYMaxMT;// = 3.3f,
            [MarshalAs(UnmanagedType.R4)] public float LowerZMinMT;//= 8.0f,
            [MarshalAs(UnmanagedType.R4)] public float LowerZMaxMT;//= 26.6f,
        }
    }
}
