/************************************************
 *                                              *
 *      MICRO EPSILON SCAN CONTROL 2900         *
 *      Driver class                            *
 *                                              *
 *      Adam Chromy                             *
 *      version: 1.0.0                          *
 *      last modified: 13.03.2018               *
 *                                              *
 ************************************************/

#region CHANGELOG

/*
 * 
 * 
 */

#endregion

using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Text;

namespace Sensors.Scanners.MicroEpsilon
{

    public class scanCONTROL2900BL : IscanCONTROL
    {
        #region class definitions

        /// <summary>Provides device parameters packed in one object</summary>
        public class SensorInformation
        {
            public InterfaceType Interface;
            public uint Resolution;
            public uint PacketDelay;
            public ScannerType DeviceType;
            public string DeviceName;
            public uint[] FirmwareVersions;
            public uint SerialNumber;
            public uint ShutterTime;
            public uint IdleTime;
            public bool AutoShutter;
            public bool AmbientLightSupression;
            public bool VideoFilter;
            public uint ReflectionThreshold;
            public bool InvalidPointsFilter;
            public LaserModes LaserPower;
            public XRanges XRange;
            public NumSamples MedianFilter;
            public NumSamples AverageFilter;

            public SensorInformation(scanCONTROL2900BL scan)
            {
                Interface = scan.Interface;
                Resolution = scan.Resolution;
                PacketDelay = scan.PacketDelay;
                DeviceType = scan.DeviceType;
                DeviceName = scan.DeviceName;
                FirmwareVersions = scan.FirmwareVersions;
                SerialNumber = scan.SerialNumber;
                ShutterTime = scan.ShutterTime;
                IdleTime = scan.IdleTime;
                AutoShutter = scan.AutoShutter;
                AmbientLightSupression = scan.AmbientLightSupression;
                VideoFilter = scan.VideoFilter;
                ReflectionThreshold = scan.ReflectionThreshold;
                InvalidPointsFilter = scan.InvalidPointsFilter;
                LaserPower = scan.LaserPower;
                XRange = scan.XRange;
                MedianFilter = scan.MedianFilter;
                AverageFilter = scan.AverageFilter;
            }
        }

        /// <summary>Encapsulates API functions from DLL library</summary>
        public class CLLTI
        {
            #region "Constant declarations"

            public const uint CONVERT_X = 0x00000800;
            public const uint CONVERT_Z = 0x00001000;
            public const uint CONVERT_WIDTH = 0x00000100;
            public const uint CONVERT_MAXIMUM = 0x00000200;
            public const uint CONVERT_THRESHOLD = 0x00000400;
            public const uint CONVERT_M0 = 0x00002000;
            public const uint CONVERT_M1 = 0x00004000;

            //specify the type for the RS422-multiplexer (27xx)
            public const int RS422_INTERFACE_FUNCTION_AUTO_27xx = 0;
            public const int RS422_INTERFACE_FUNCTION_SERIALPORT_115200_27xx = 1;
            public const int RS422_INTERFACE_FUNCTION_TRIGGER_27xx = 2;
            public const int RS422_INTERFACE_FUNCTION_CMM_TRIGGER_27xx = 3;
            public const int RS422_INTERFACE_FUNCTION_ENCODER_27xx = 4;
            public const int RS422_INTERFACE_FUNCTION_DIGITAL_OUTPUT_27xx = 6;
            public const int RS422_INTERFACE_FUNCTION_TRIGGER_LASER_PULSE_27xx = 7;
            public const int RS422_INTERFACE_FUNCTION_SERIALPORT_57600_27xx = 8;
            public const int RS422_INTERFACE_FUNCTION_SERIALPORT_38400_27xx = 9;
            public const int RS422_INTERFACE_FUNCTION_SERIALPORT_19200_27xx = 10;
            public const int RS422_INTERFACE_FUNCTION_SERIALPORT_9600_27xx = 11;

            //specify the type for the RS422-multiplexer (26xx/29xx)
            public const int RS422_INTERFACE_FUNCTION_SERIALPORT_115200 = 0;
            public const int RS422_INTERFACE_FUNCTION_SERIALPORT_57600 = 1;
            public const int RS422_INTERFACE_FUNCTION_SERIALPORT_38400 = 2;
            public const int RS422_INTERFACE_FUNCTION_SERIALPORT_19200 = 3;
            public const int RS422_INTERFACE_FUNCTION_SERIALPORT_9600 = 4;
            public const int RS422_INTERFACE_FUNCTION_TRIGGER_INPUT = 5;
            public const int RS422_INTERFACE_FUNCTION_TRIGGER_OUTPUT = 6;
            public const int RS422_INTERFACE_FUNCTION_CMM_TRIGGER = 7;

            #endregion

            #region "Return Values"

            //Message-Values
            public const int ERROR_OK = 0;
            public const int ERROR_SERIAL_COMM = 1;
            public const int ERROR_SERIAL_LLT = 7;
            public const int ERROR_CONNECTIONLOST = 10;
            public const int ERROR_STOPSAVING = 100;

            //Return-Values for the is-functions
            public const int IS_FUNC_NO = 0;
            public const int IS_FUNC_YES = 1;

            //General return-values for all functions
            public const int GENERAL_FUNCTION_DEVICE_NAME_NOT_SUPPORTED = 4;
            public const int GENERAL_FUNCTION_PACKET_SIZE_CHANGED = 3;
            public const int GENERAL_FUNCTION_CONTAINER_MODE_HEIGHT_CHANGED = 2;
            public const int GENERAL_FUNCTION_OK = 1;
            public const int GENERAL_FUNCTION_NOT_AVAILABLE = 0;

            public const int ERROR_GENERAL_WHILE_LOAD_PROFILE = -1000;
            public const int ERROR_GENERAL_NOT_CONNECTED = -1001;
            public const int ERROR_GENERAL_DEVICE_BUSY = -1002;
            public const int ERROR_GENERAL_WHILE_LOAD_PROFILE_OR_GET_PROFILES = -1003;
            public const int ERROR_GENERAL_WHILE_GET_PROFILES = -1004;
            public const int ERROR_GENERAL_GET_SET_ADDRESS = -1005;
            public const int ERROR_GENERAL_POINTER_MISSING = -1006;
            public const int ERROR_GENERAL_WHILE_SAVE_PROFILES = -1007;
            public const int ERROR_GENERAL_SECOND_CONNECTION_TO_LLT = -1008;

            //Return-Values for GetDeviceName
            public const int ERROR_GETDEVICENAME_SIZE_TOO_LOW = -1;
            public const int ERROR_GETDEVICENAME_NO_BUFFER = -2;

            //Return-Values for Load/SaveProfiles
            public const int ERROR_LOADSAVE_WRITING_LAST_BUFFER = -50;
            public const int ERROR_LOADSAVE_WHILE_SAVE_PROFILE = -51;
            public const int ERROR_LOADSAVE_NO_PROFILELENGTH_POINTER = -52;
            public const int ERROR_LOADSAVE_NO_LOAD_PROFILE = -53;
            public const int ERROR_LOADSAVE_STOP_ALREADY_LOAD = -54;
            public const int ERROR_LOADSAVE_CANT_OPEN_FILE = -55;
            public const int ERROR_LOADSAVE_FILE_POSITION_TOO_HIGH = -57;
            public const int ERROR_LOADSAVE_AVI_NOT_SUPPORTED = -58;
            public const int ERROR_LOADSAVE_NO_REARRANGEMENT_POINTER = -59;
            public const int ERROR_LOADSAVE_WRONG_PROFILE_CONFIG = -60;
            public const int ERROR_LOADSAVE_NOT_TRANSFERING = -61;

            //Return-Values for profile transfer functions
            public const int ERROR_PROFTRANS_SHOTS_NOT_ACTIVE = -100;
            public const int ERROR_PROFTRANS_SHOTS_COUNT_TOO_HIGH = -101;
            public const int ERROR_PROFTRANS_WRONG_PROFILE_CONFIG = -102;
            public const int ERROR_PROFTRANS_FILE_EOF = -103;
            public const int ERROR_PROFTRANS_NO_NEW_PROFILE = -104;
            public const int ERROR_PROFTRANS_BUFFER_SIZE_TOO_LOW = -105;
            public const int ERROR_PROFTRANS_NO_PROFILE_TRANSFER = -106;
            public const int ERROR_PROFTRANS_PACKET_SIZE_TOO_HIGH = -107;
            public const int ERROR_PROFTRANS_CREATE_BUFFERS = -108;
            public const int ERROR_PROFTRANS_WRONG_PACKET_SIZE_FOR_CONTAINER = -109;
            public const int ERROR_PROFTRANS_REFLECTION_NUMBER_TOO_HIGH = -110;
            public const int ERROR_PROFTRANS_MULTIPLE_SHOTS_ACTIVE = -111;
            public const int ERROR_PROFTRANS_BUFFER_HANDOUT = -112;
            public const int ERROR_PROFTRANS_WRONG_BUFFER_POINTER = -113;
            public const int ERROR_PROFTRANS_WRONG_TRANSFER_CONFIG = -114;

            //Return-Values for Set/GetFunctions
            public const int ERROR_SETGETFUNCTIONS_WRONG_BUFFER_COUNT = -150;
            public const int ERROR_SETGETFUNCTIONS_PACKET_SIZE = -151;
            public const int ERROR_SETGETFUNCTIONS_WRONG_PROFILE_CONFIG = -152;
            public const int ERROR_SETGETFUNCTIONS_NOT_SUPPORTED_RESOLUTION = -153;
            public const int ERROR_SETGETFUNCTIONS_REFLECTION_NUMBER_TOO_HIGH = -154;
            public const int ERROR_SETGETFUNCTIONS_WRONG_FEATURE_ADRESS = -155;
            public const int ERROR_SETGETFUNCTIONS_SIZE_TOO_LOW = -156;
            public const int ERROR_SETGETFUNCTIONS_WRONG_PROFILE_SIZE = -157;
            public const int ERROR_SETGETFUNCTIONS_MOD_4 = -158;
            public const int ERROR_SETGETFUNCTIONS_REARRANGEMENT_PROFILE = -159;
            public const int ERROR_SETGETFUNCTIONS_USER_MODE_TOO_HIGH = -160;
            public const int ERROR_SETGETFUNCTIONS_USER_MODE_FACTORY_DEFAULT = -161;
            public const int ERROR_SETGETFUNCTIONS_HEARTBEAT_TOO_HIGH = -162;


            //Return-Values PostProcessingParameter
            public const int ERROR_POSTPROCESSING_NO_PROF_BUFFER = -200;
            public const int ERROR_POSTPROCESSING_MOD_4 = -201;
            public const int ERROR_POSTPROCESSING_NO_RESULT = -202;
            public const int ERROR_POSTPROCESSING_LOW_BUFFERSIZE = -203;
            public const int ERROR_POSTPROCESSING_WRONG_RESULT_SIZE = -204;

            //Return-Values for GetDeviceInterfaces
            public const int ERROR_GETDEVINTERFACES_WIN_NOT_SUPPORTED = -250;
            public const int ERROR_GETDEVINTERFACES_REQUEST_COUNT = -251;
            public const int ERROR_GETDEVINTERFACES_CONNECTED = -252;
            public const int ERROR_GETDEVINTERFACES_INTERNAL = -253;

            //Return-Values for Connect
            public const int ERROR_CONNECT_LLT_COUNT = -300;
            public const int ERROR_CONNECT_SELECTED_LLT = -301;
            public const int ERROR_CONNECT_ALREADY_CONNECTED = -302;
            public const int ERROR_CONNECT_LLT_NUMBER_ALREADY_USED = -303;
            public const int ERROR_CONNECT_SERIAL_CONNECTION = -304;
            public const int ERROR_CONNECT_INVALID_IP = -305;

            //Return-Values for SetPartialProfile
            public const int ERROR_PARTPROFILE_NO_PART_PROF = -350;
            public const int ERROR_PARTPROFILE_TOO_MUCH_BYTES = -351;
            public const int ERROR_PARTPROFILE_TOO_MUCH_POINTS = -352;
            public const int ERROR_PARTPROFILE_NO_POINT_COUNT = -353;
            public const int ERROR_PARTPROFILE_NOT_MOD_UNITSIZE_POINT = -354;
            public const int ERROR_PARTPROFILE_NOT_MOD_UNITSIZE_DATA = -355;

            //Return-Values for Start/StopTransmissionAndCmmTrigger
            public const int ERROR_CMMTRIGGER_NO_DIVISOR = -400;
            public const int ERROR_CMMTRIGGER_TIMEOUT_AFTER_TRANSFERPROFILES = -401;
            public const int ERROR_CMMTRIGGER_TIMEOUT_AFTER_SETCMMTRIGGER = -402;

            //Return-Values for TranslateErrorValue
            public const int ERROR_TRANSERRORVALUE_WRONG_ERROR_VALUE = -450;
            public const int ERROR_TRANSERRORVALUE_BUFFER_SIZE_TOO_LOW = -451;

            //Read/write config functions
            public const int ERROR_READWRITECONFIG_CANT_CREATE_FILE = -500;
            public const int ERROR_READWRITECONFIG_CANT_OPEN_FILE = -501;
            public const int ERROR_READWRITECONFIG_QUEUE_TO_SMALL = -502;

            #endregion

            #region "Registers"
            //Function defines for the Get/SetFeature function
            public const uint FEATURE_FUNCTION_SERIAL = 0xf0000410;
            public const uint FEATURE_FUNCTION_LASERPOWER = 0xf0f00824;
            public const uint INQUIRY_FUNCTION_LASERPOWER = 0xf0f00524;
            public const uint FEATURE_FUNCTION_MEASURINGFIELD = 0xf0f00880;
            public const uint INQUIRY_FUNCTION_MEASURINGFIELD = 0xf0f00580;
            public const uint FEATURE_FUNCTION_TRIGGER = 0xf0f00830;
            public const uint INQUIRY_FUNCTION_TRIGGER = 0xf0f00530;
            public const uint FEATURE_FUNCTION_SHUTTERTIME = 0xf0f0081c;
            public const uint INQUIRY_FUNCTION_SHUTTERTIME = 0xf0f0051c;
            public const uint FEATURE_FUNCTION_IDLETIME = 0xf0f00800;
            public const uint INQUIRY_FUNCTION_IDLETIME = 0xf0f00500;
            public const uint FEATURE_FUNCTION_PROCESSING_PROFILEDATA = 0xf0f00804;
            public const uint INQUIRY_FUNCTION_PROCESSING_PROFILEDATA = 0xf0f00504;
            public const uint FEATURE_FUNCTION_THRESHOLD = 0xf0f00810;
            public const uint INQUIRY_FUNCTION_THRESHOLD = 0xf0f00510;
            public const uint FEATURE_FUNCTION_MAINTENANCEFUNCTIONS = 0xf0f0088c;
            public const uint INQUIRY_FUNCTION_MAINTENANCEFUNCTIONS = 0xf0f0058c;
            public const uint FEATURE_FUNCTION_ANALOGFREQUENCY = 0xf0f00828;
            public const uint INQUIRY_FUNCTION_ANALOGFREQUENCY = 0xf0f00528;
            public const uint FEATURE_FUNCTION_ANALOGOUTPUTMODES = 0xf0f00820;
            public const uint INQUIRY_FUNCTION_ANALOGOUTPUTMODES = 0xf0f00520;
            public const uint FEATURE_FUNCTION_CMMTRIGGER = 0xf0f00888;
            public const uint INQUIRY_FUNCTION_CMMTRIGGER = 0xf0f00588;
            public const uint FEATURE_FUNCTION_REARRANGEMENT_PROFILE = 0xf0f0080c;
            public const uint INQUIRY_FUNCTION_REARRANGEMENT_PROFILE = 0xf0f0050c;
            public const uint FEATURE_FUNCTION_PROFILE_FILTER = 0xf0f00818;
            public const uint INQUIRY_FUNCTION_PROFILE_FILTER = 0xf0f00518;
            public const uint FEATURE_FUNCTION_RS422_INTERFACE_FUNCTION = 0xf0f008c0;
            public const uint INQUIRY_FUNCTION_RS422_INTERFACE_FUNCTION = 0xf0f005c0;

            public const uint FEATURE_FUNCTION_SATURATION = 0xf0f00814;
            public const uint INQUIRY_FUNCTION_SATURATION = 0xf0f00514;
            public const uint FEATURE_FUNCTION_TEMPERATURE = 0xf0f0082c;
            public const uint INQUIRY_FUNCTION_TEMPERATURE = 0xf0f0052c;
            public const uint FEATURE_FUNCTION_CAPTURE_QUALITY = 0xf0f008c4;
            public const uint INQUIRY_FUNCTION_CAPTURE_QUALITY = 0xf0f005c4;
            public const uint FEATURE_FUNCTION_SHARPNESS = 0xf0f00808;
            public const uint INQUIRY_FUNCTION_SHARPNESS = 0xf0f00508;

            public const uint FEATURE_FUNCTION_PACKET_DELAY = 0x00000d08;
            public const uint FEATURE_FUNCTION_CONNECTION_SPEED = 0x00000670;

            #endregion

            #region "Enums"

            //specify the callback type
            //if you programming language don't support enums, you can use a signed int
            public enum TCallbackType
            {
                STD_CALL = 0,
                C_DECL = 1,
            }

            public struct TPartialProfile
            {
                public uint nStartPoint;
                public uint nStartPointData;
                public uint nPointCount;
                public uint nPointDataWidth;
            }

            public enum TTransferVideoType
            {
                VIDEO_MODE_0 = 0,
                VIDEO_MODE_1 = 1,
                NONE_VIDEOMODE = 2,
            }

            public enum TFileType
            {
                AVI = 0,
                LLT = 1,
                CSV = 2,
                BMP = 3,
                CSV_NEG = 4,
            }

            public unsafe delegate void ProfileReceiveMethod(byte* data, uint iSize, uint pUserData);

            #endregion

            #region "DLL references"

            // Instance functions
            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_CreateLLTDevice",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern uint CreateLLTDevice(InterfaceType iInterfaceType);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_CreateLLTFirewire",
                 CallingConvention = CallingConvention.StdCall)]
            internal static extern uint CreateLLTFirewire();

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_CreateLLTSerial",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern uint CreateLLTSerial();

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetInterfaceType",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetInterfaceType(uint pLLT);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_DelDevice",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int DelDevice(uint pLLT);

            // Connect functions
            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_Connect",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int Connect(uint pLLT);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_Disconnect",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int Disconnect(uint pLLT);

            // Write config functions
            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_ExportLLTConfig",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int ExportLLTConfig(uint pLLT, StringBuilder pFileName);

            // Device interface functions
            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetDeviceInterfaces",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetDeviceInterfaces(uint pLLT, uint[] pInterfaces, int nSize);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetDeviceInterfacesFast",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetDeviceInterfacesFast(uint pLLT, uint[] pInterfaces, int nSize);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_SetDeviceInterface",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int SetDeviceInterface(uint pLLT, uint nInterface, int nAdditional);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetDiscoveryBroadcastTarget",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern uint GetDiscoveryBroadcastTarget(uint pLLT);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_SetDiscoveryBroadcastTarget",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int SetDiscoveryBroadcastTarget(uint pLLT, uint nNetworkAddress, uint nSubnetMask);

            // scanControl identification functions
            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetDeviceName",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetDeviceName(uint pLLT, StringBuilder sbDevName, int nDevNameSize, StringBuilder sbVenName, int nVenNameSize);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetLLTVersions",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetLLTVersions(uint pLLT, ref uint pDSP, ref uint pFPGA1, ref uint pFPGA2);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetLLTType",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetLLTType(uint pLLT, ref ScannerType ScannerType);

            //Get functions
            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetMinMaxPacketSize",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetMinMaxPacketSize(uint pLLT, ref ulong pMinPacketSize, ref ulong pMaxPacketSize);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetResolutions",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetResolutions(uint pLLT, uint[] pValue, int nSize);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetFeature",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetFeature(uint pLLT, uint Function, ref uint pValue);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetBufferCount",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetBufferCount(uint pLLT, ref uint pValue);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetMainReflection",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetMainReflection(uint pLLT, ref uint pValue);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetMaxFileSize",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetMaxFileSize(uint pLLT, ref uint pValue);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetPacketSize",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetPacketSize(uint pLLT, ref uint pValue);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetFirewireConnectionSpeed",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetFirewireConnectionSpeed(uint pLLT, ref uint pValue);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetProfileConfig",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetProfileConfig(uint pLLT, ref ProfileConfig pValue);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetResolution",
                 CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetResolution(uint pLLT, ref uint pValue);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetProfileContainerSize",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetProfileContainerSize(uint pLLT, ref uint pWidth, ref uint pHeight);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetMaxProfileContainerSize",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetMaxProfileContainerSize(uint pLLT, ref uint pMaxWidth, ref uint pMaxHeight);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetEthernetHeartbeatTimeout",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetEthernetHeartbeatTimeout(uint pLLT, ref uint pValue);

            //Set functions
            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_SetFeature",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int SetFeature(uint pLLT, uint Function, uint Value);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_SetResolution",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int SetResolution(uint pLLT, uint Value);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_SetProfileConfig",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int SetProfileConfig(uint pLLT, ProfileConfig Value);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_SetBufferCount",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int SetBufferCount(uint pLLT, uint pValue);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_SetMainReflection",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int SetMainReflection(uint pLLT, uint pValue);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_SetMaxFileSize",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int SetMaxFileSize(uint pLLT, uint pValue);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_SetPacketSize",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int SetPacketSize(uint pLLT, uint pValue);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_SetFirewireConnectionSpeed",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int SetFirewireConnectionSpeed(uint pLLT, uint pValue);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_SetProfileContainerSize",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int SetProfileContainerSize(uint pLLT, uint nWidth, uint nHeight);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_SetEthernetHeartbeatTimeout",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int SetEthernetHeartbeatTimeout(uint pLLT, uint pValue);

            //Register functions
            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_RegisterCallback",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int RegisterCallback(uint pLLT, TCallbackType tCallbackType, ProfileReceiveMethod tReceiveProfiles, uint pUserData);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_RegisterErrorMsg",
               CallingConvention = CallingConvention.StdCall)]
            internal static extern int RegisterErrorMsg(uint pLLT, uint Msg, IntPtr hWnd, UIntPtr WParam);

            // Profile transfer functions
            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_TransferProfiles",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int TransferProfiles(uint pLLT, TransferProfileType TransferProfileType, int nEnable);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetProfile",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetProfile(uint pLLT);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_TransferVideoStream",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int TransferVideoStream(uint pLLT, TTransferVideoType TransferVideoType, int nEnable, ref uint pWidth, ref uint pHeight);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_MultiShot",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int MultiShot(uint pLLT, uint nCount);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetActualProfile",
               CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetActualProfile(uint pLLT, byte[] pBuffer, int nBuffersize,
              ProfileConfig ProfileConfig, ref uint pLostProfiles);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_ConvertProfile2Values",
               CallingConvention = CallingConvention.StdCall)]
            internal static extern int ConvertProfile2Values(uint pLLT, byte[] pProfile, uint nResolution,
              ProfileConfig ProfileConfig, ScannerType ScannerType, uint nReflection, int nConvertToMM,
              ushort[] pWidth, ushort[] pMaximum, ushort[] pThreshold, double[] pX, double[] pZ,
              uint[] pM0, uint[] pM1);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_ConvertPartProfile2Values",
               CallingConvention = CallingConvention.StdCall)]
            internal static extern int ConvertPartProfile2Values(uint pLLT, byte[] pProfile, ref TPartialProfile ProfileConfig, ScannerType ScannerType, uint nReflection, int nConvertToMM,
              ushort[] pWidth, ushort[] pMaximum, ushort[] pThreshold, double[] pX, double[] pZ,
              uint[] pM0, uint[] pM1);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_SetHoldBuffersForPolling",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int SetHoldBuffersForPolling(uint pLLT, uint uiHoldBuffersForPolling);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetHoldBuffersForPolling",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetHoldBuffersForPolling(uint pLLT, ref uint puiHoldBuffersForPolling);

            //Is functions
            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_IsInterfaceType",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int IsInterfaceType(uint pLLT, int iInterfaceType);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_IsFirewire",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int IsFirewire(uint pLLT);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_IsSerial",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int IsSerial(uint pLLT);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_IsTransferingProfiles",
                CallingConvention = CallingConvention.StdCall)]
            internal static extern int IsTransferingProfiles(uint pLLT);

            //PartialProfile functions
            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetPartialProfileUnitSize",
               CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetPartialProfileUnitSize(uint pLLT, ref uint pUnitSizePoint, ref uint pUnitSizePointData);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetPartialProfile",
               CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetPartialProfile(uint pLLT, ref TPartialProfile pPartialProfile);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_SetPartialProfile",
               CallingConvention = CallingConvention.StdCall)]
            internal static extern int SetPartialProfile(uint pLLT, ref TPartialProfile pPartialProfile);

            //Timestamp convert functions,
            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_Timestamp2CmmTriggerAndInCounter",
               CallingConvention = CallingConvention.StdCall)]
            internal static extern int Timestamp2CmmTriggerAndInCounter(byte[] pBuffer, ref uint pInCounter, ref int pCmmTrigger, ref int pCmmActive, ref uint pCmmCount);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_Timestamp2TimeAndCount",
               CallingConvention = CallingConvention.StdCall)]
            internal static extern int Timestamp2TimeAndCount(byte[] pBuffer, ref double dTimeShutterOpen, ref double dTimeShutterClose, ref uint uiProfileCount);

            //PostProcessing functions
            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_ReadPostProcessingParameter",
               CallingConvention = CallingConvention.StdCall)]
            internal static extern int ReadPostProcessingParameter(uint pLLT, ref uint pParameter, uint nSize);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_WritePostProcessingParameter",
               CallingConvention = CallingConvention.StdCall)]
            internal static extern int WritePostProcessingParameter(uint pLLT, ref uint pParameter, uint nSize);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_ConvertProfile2ModuleResult",
               CallingConvention = CallingConvention.StdCall)]
            internal static extern int ConvertProfile2ModuleResult(uint pLLT, byte[] pProfileBuffer, uint nProfileBufferSize, byte[] pModuleResultBuffer, uint nResultBufferSize, ref TPartialProfile pPartialProfile /* = NULL*/);

            //Load/Save functions
            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_LoadProfiles",
               CallingConvention = CallingConvention.StdCall)]
            internal static extern int LoadProfiles(uint pLLT, StringBuilder pFilename, ref TPartialProfile pPartialProfile, ref ProfileConfig pProfileConfig, ref ScannerType pScannerType, ref uint pRearrengementProfile);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_SaveProfiles",
               CallingConvention = CallingConvention.StdCall)]
            internal static extern int SaveProfiles(uint pLLT, StringBuilder pFilename, TFileType FileType);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_LoadProfilesGetPos",
               CallingConvention = CallingConvention.StdCall)]
            internal static extern int LoadProfilesGetPos(uint pLLT, ref uint pActualPosition, ref uint pMaxPosition);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_LoadProfilesSetPos",
               CallingConvention = CallingConvention.StdCall)]
            internal static extern int LoadProfilesSetPos(uint pLLT, uint nNewPosition);

            //Special CMM trigger functions
            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_StartTransmissionAndCmmTrigger",
               CallingConvention = CallingConvention.StdCall)]
            internal static extern int StartTransmissionAndCmmTrigger(uint pLLT, uint nCmmTrigger, TransferProfileType TransferProfileType, uint nProfilesForerun, StringBuilder pFilename, TFileType FileType, uint Timeout);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_StopTransmissionAndCmmTrigger",
               CallingConvention = CallingConvention.StdCall)]
            internal static extern int StopTransmissionAndCmmTrigger(uint pLLT, int nCmmTriggerPolarity, uint nTimeout);

            // Converts a error-value in a string 
            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_TranslateErrorValue",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int TranslateErrorValue(uint pLLT, int ErrorValue, byte[] pString, int nStringSize);

            //User mode
            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_GetActualUserMode",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int GetActualUserMode(uint pLLT, ref uint pActualUserMode, ref uint pUserModeCount);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_ReadWriteUserModes",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int ReadWriteUserModes(uint pLLT, int nWrite, uint nUserMode);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_TriggerProfile",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int TriggerProfile(uint pLLT);

            [DllImport(DRIVER_DLL_NAME, EntryPoint = "s_SaveGlobalParameter",
              CallingConvention = CallingConvention.StdCall)]
            internal static extern int SaveGlobalParameter(uint pLLT);

            #endregion

            // constructor
            public CLLTI()
            {

            }
        }

        #endregion

        #region constants

        /// <summary>Max. count of simultaneously connected devices</summary>
        public const int MAX_INTERFACE_COUNT = 5;

        /// <summary>Default XRange when connected</summary>
        private const XRanges DEFAULT_XRANGE = XRanges.PLUSMINUS_50;

        /// <summary>Default IP address used when connecting using Open method</summary>
        private const string DEFAULT_IP = "10.0.41.69";

        /// <summary>name of DLL library to load functions from</summary>
        private const string DRIVER_DLL_NAME = "Drivers\\ScannerMicroEpsilonSC2900BL_x86.dll";

        /// <summary>Size of buffer for short texts, eg. name of device</summary>
        private const int BUFFER_SHORTSTRING_LENGTH = 300; //300 characters should be enough for the name of device

        /// <summary>possible return values</summary>
        public class ReturnValues
        {
            public const int DEVICE_NAME_NOT_SUPPORTED = 4;
            public const int PACKET_SIZE_CHANGED = 3;
            public const int CONTAINER_MODE_HEIGHT_CHANGED = 2;
            public const int OK = 1;
            public const int NOT_AVAILABLE = 0;
        }

        #endregion

        #region private data members

        /// <summary>Internal handle to connected device</summary>
        private uint hDevice = 0;

        /// <summary>internal connection flag</summary>
        private bool isConnected = false;

        /// <summary>actual set resolution</summary>
        private uint resolution = 0;

        /// <summary>stores model of actually connected device</summary>
        private ScannerType scannerType = 0;

        #endregion

        #region private methods

        /// <summary>Retrieves selected communication interface</summary>
        private InterfaceType GetInterfaceType()
        {
            return (InterfaceType)CLLTI.GetInterfaceType(hDevice);
        }

        /// <summary>Performs connection procedure via specified interface</summary>
        private bool ConnectionProcedure(InterfaceType Interface, uint parameter1, int parameter2)
        {
            int retValue = 0;

            if (Connected) //already connected
            {
                Debug.WriteLine("scanCONTROL: Already connected");
                return false;
            }

            if (hDevice == 0) //not created yet
            {
                hDevice = CLLTI.CreateLLTDevice(Interface); //create object
                if (hDevice == 0) //error during creating object
                {
                    Debug.WriteLine("scanCONTROL: Error during creating LLT object");
                    return false;
                }
            }

            retValue = CLLTI.SetDeviceInterface(hDevice, parameter1, parameter2); //set IP address
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when applying IP address/Node ID/COM number");
                return false;
            }

            retValue = CLLTI.Connect(hDevice); //connect to device
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when connecting");
                return false;
            }

            if (GetXRange() == 0) //equidistant span is neccessary for many functions, must be switched on
                SetXRange(DEFAULT_XRANGE);

            isConnected = true; //setting internal connection flag
            if (OnConnected != null)
                OnConnected(this, EventArgs.Empty); //raise event

            return true;
        }

        /// <summary>Gets all three properties stored in Threshold property</summary>
        private uint GetThreshAndFilters()
        {
            int retValue = 0;
            uint resValue = 0;

            retValue = CLLTI.GetFeature(hDevice, CLLTI.FEATURE_FUNCTION_THRESHOLD, ref resValue);
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when reading Threshold property");
                return 0;
            }

            return resValue;
        }

        /// <summary>Retrieves if Ambient light supression is enabled</summary>
        private bool GetAmbientLight()
        {
            return (GetThreshAndFilters() & 0x400) > 0; //masking 10.bit which contains desired data
        }

        /// <summary>Enables/disables ambient light supression</summary>
        private void SetAmbientLight(bool enable)
        {
            int retValue = 0;
            uint dword = GetThreshAndFilters();

            if (enable)
                dword |= (1u << 10); //sets 10. bit
            else
                dword &= ~(1u << 10); //clears 10. bit

            retValue = CLLTI.SetFeature(hDevice, CLLTI.FEATURE_FUNCTION_THRESHOLD, dword);
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when writing Ambient light supression property");
                return;
            }
        }

        /// <summary>Retrieves if Video filter is enabled</summary>
        private bool GetVideoFilter()
        {
            return (GetThreshAndFilters() & 0x800) > 0; //masking 11.bit which contains desired data
        }

        /// <summary>Enables/disables video filter</summary>
        private void SetVideoFilter(bool enable)
        {
            int retValue = 0;
            uint dword = GetThreshAndFilters();

            if (enable)
                dword |= (1u << 11); //sets 11. bit
            else
                dword &= ~(1u << 11); //clears 11. bit

            retValue = CLLTI.SetFeature(hDevice, CLLTI.FEATURE_FUNCTION_THRESHOLD, dword);
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when writing Video filter property");
                return;
            }
        }

        /// <summary>Retrieves reflection threshold</summary>
        private uint GetThreshold()
        {
            return (GetThreshAndFilters() & 0x3FF); //masking 0..9bit which contains desired data
        }

        /// <summary>Sets value for reflection threshold</summary>
        private void SetThreshold(uint threshold)
        {
            int retValue = 0;
            uint dword = GetThreshAndFilters();

            dword &= ~(0x3FFu); //clears 0..9 bit
            dword |= (threshold & 0x3FF); //fill 0..9 bit with threshold data 

            retValue = CLLTI.SetFeature(hDevice, CLLTI.FEATURE_FUNCTION_THRESHOLD, dword);
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when writing Threshold property");
                return;
            }
        }

        /// <summary>Retrieves if auto shutter is enabled</summary>
        private bool GetAutoShutter()
        {
            int retValue = 0;
            uint resValue = 0;

            retValue = CLLTI.GetFeature(hDevice, CLLTI.FEATURE_FUNCTION_SHUTTERTIME, ref resValue);
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when reading Automatic shutter property");
                return false;
            }

            return (resValue & 0x1000000) > 0; //masking 24.bit which contains auto shutter setting
        }

        /// <summary>Enables/diables automatic shutter time regulation depending on measured object</summary>
        private void SetAutoShutter(bool value)
        {
            int retValue = 0;
            uint dword = ShutterTime;

            if (value)
                dword |= (1u << 24); //sets 24. bit
            else
                dword &= ~(1u << 24); //clears 24. bit

            retValue = CLLTI.SetFeature(hDevice, CLLTI.FEATURE_FUNCTION_SHUTTERTIME, dword);
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when writing Automatic shutter property");
                return;
            }
        }

        /// <summary>Retrieves time when shutter is opened</summary>
        private uint GetShutterTime()
        {
            int retValue = 0;
            uint resValue = 0;

            retValue = CLLTI.GetFeature(hDevice, CLLTI.FEATURE_FUNCTION_SHUTTERTIME, ref resValue);
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when reading Shutter time property");
                return 0;
            }

            return (resValue & 0xFFF); //masking 0..11bit which contains shuttertime
        }

        /// <summary>Sets shutter time</summary>
        private void SetShutterTime(uint value)
        {
            int retValue = 0;
            uint dword = value;

            if (AutoShutter)
                dword |= (1u << 24); //sets 24. bit
            else
                dword &= ~(1u << 24); //clears 24. bit

            retValue = CLLTI.SetFeature(hDevice, CLLTI.FEATURE_FUNCTION_SHUTTERTIME, dword);
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when writing Shutter time property");
                return;
            }
        }

        /// <summary>Retrieves dead time when shutter is closed</summary>
        private uint GetIdleTime()
        {
            int retValue = 0;
            uint resValue = 0;

            retValue = CLLTI.GetFeature(hDevice, CLLTI.FEATURE_FUNCTION_IDLETIME, ref resValue);
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when reading Idle time property");
                return 0;
            }

            return (resValue & 0xFFF); //masking 0..11bit which contains idletime
        }

        /// <summary>Sets idle time</summary>
        private void SetIdleTime(uint value)
        {
            int retValue = 0;

            retValue = CLLTI.SetFeature(hDevice, CLLTI.FEATURE_FUNCTION_IDLETIME, value);
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when writing Idle time property");
                return;
            }
        }

        /// <summary>Gets actual laser power. Allowed modes are OFF, HALF and FULL.</summary>
        private LaserModes GetLaser()
        {
            int retValue = 0;
            uint resValue = 0;

            retValue = CLLTI.GetFeature(hDevice, CLLTI.FEATURE_FUNCTION_LASERPOWER, ref resValue);
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when reading Laser power property");
                return 0;
            }

            return (LaserModes)resValue;
        }

        /// <summary>Sets laser power. Allowed modes are OFF, HALF and FULL.</summary>
        private void SetLaser(LaserModes mode)
        {
            int retValue = 0;

            retValue = CLLTI.SetFeature(hDevice, CLLTI.FEATURE_FUNCTION_LASERPOWER, (uint)mode);
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when writing Laser power property");
                return;
            }
        }

        /// <summary>retrieves actually set resolution</summary>
        /// <returns>returns value of resolution</returns>
        private uint GetResolution()
        {
            if (resolution > 0) //resolution is stored in internal memory
                return resolution;

            // we dont know value of resolution -> acquire it from device
            int retValue = 0;
            uint resValue = 0;

            retValue = CLLTI.GetResolution(hDevice, ref resValue); //gets resolution
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when getting resolution");
                return 0;
            }

            resolution = resValue; //save resolution to internal memory
            return resValue;
        }

        /// <summary>sets desired resolution</summary>
        /// <returns>returns true if resolution was accepted</returns>
        private void SetResolution(uint value)
        {
            int retValue = 0;

            retValue = CLLTI.SetResolution(hDevice, value); //sets resolution
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when setting resolution");
                return;
            }

            resolution = value; //save to internal parameter
        }

        /// <summary>Returns model of actually connected scanner</summary>
        private ScannerType GetScannerType()
        {
            if (scannerType != 0) //scanner type is stored in internal memory
                return scannerType;

            // we dont know model of device -> acquire it from device
            int retValue = 0;
            ScannerType model = 0;

            retValue = CLLTI.GetLLTType(hDevice, ref model); //sets resolution
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when getting scanner type");
                return 0;
            }

            scannerType = model; //save model to internal memory
            return model;
        }

        /// <summary>Returns name of actually connected device</summary>
        private string GetDeviceName()
        {
            int retValue = 0;
            StringBuilder DeviceName = new StringBuilder(BUFFER_SHORTSTRING_LENGTH);
            StringBuilder VendorName = new StringBuilder(BUFFER_SHORTSTRING_LENGTH);

            retValue = CLLTI.GetDeviceName(hDevice, DeviceName, DeviceName.Capacity, VendorName, VendorName.Capacity);
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when getting scanner name");
                return "";
            }

            return DeviceName.ToString();
        }

        /// <summary>Writes dword into the filter property. Used by other filter functions</summary>
        private bool SetFilterProperty(uint dword)
        {
            int retValue = 0;

            retValue = CLLTI.SetFeature(hDevice, CLLTI.FEATURE_FUNCTION_PROFILE_FILTER, dword);
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when writing Profile filter property");
                return false;
            }

            return true;
        }

        /// <summary>Reads dword from the filter property. Used by other filter functions</summary>
        private uint GetFilterProperty()
        {
            int retValue = 0;
            uint resValue = 0;

            retValue = CLLTI.GetFeature(hDevice, CLLTI.FEATURE_FUNCTION_PROFILE_FILTER, ref resValue);
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when reading Profile filter property");
                return 0;
            }

            return resValue;

        }

        /// <summary>Reads dword from the filter property. Used by other filter functions</summary>
        private uint GetSerialNumber()
        {
            int retValue = 0;
            uint resValue = 0;

            retValue = CLLTI.GetFeature(hDevice, CLLTI.FEATURE_FUNCTION_SERIAL, ref resValue);
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when reading Serial number");
                return 0;
            }

            return resValue;

        }

        /// <summary>Reads dword from the filter property. Used by other filter functions</summary>
        private uint[] GetLLTVersions()
        {
            int retValue = 0;
            uint DSP = 0;
            uint FPGA1 = 0;
            uint FPGA2 = 0;

            retValue = CLLTI.GetLLTVersions(hDevice, ref DSP, ref FPGA1, ref FPGA2);
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when reading firmware version");
                return new uint[0];
            }

            return new uint[] { DSP, FPGA1, FPGA2 };
        }

        /// <summary>Enables/disables filtering of invalid points</summary>
        private void SetInvalidPointsFilter(bool enable)
        {
            uint dword = GetFilterProperty();

            if (enable)
                dword |= (1u << 11); //sets 11. bit
            else
                dword &= ~(1u << 11); //clears 11. bit

            SetFilterProperty(dword);
        }

        /// <summary>Retrieves if filtering of invalid points is enabled</summary>
        private bool GetInvalidPointsFilter()
        {
            uint dword = GetFilterProperty();
            return ((dword & (1u << 11)) == (1u << 11)); //returns value of 11. bit
        }

        /// <summary>Retrieves which range of X axis is set</summary>
        private XRanges GetXRange()
        {
            uint dword = GetFilterProperty();
            return (XRanges)((dword & (0x7 << 4)) >> 4); //returns value of 6..4 bit
        }

        /// <summary>Sets range of scanning in X axis</summary>
        private void SetXRange(XRanges range)
        {
            uint dword = GetFilterProperty();

            dword &= ~(7u << 4); //clears 4..6. bit
            dword |= ((uint)range << 4); //write to 4..6. bit

            SetFilterProperty(dword);
        }

        /// <summary>Retrieves settings of median filter</summary>
        private NumSamples GetMedianFilter()
        {
            uint dword = GetFilterProperty();
            return (NumSamples)((dword & (0x3 << 2)) >> 2); //returns value of 2..3 bit
        }

        /// <summary>Enables/Disables median filter</summary>
        private void SetMedianFilter(NumSamples samples)
        {
            uint dword = GetFilterProperty();

            dword &= ~(3u << 2); //clears 2..3. bit
            dword |= ((uint)samples << 2); //sets 2..3. bit

            SetFilterProperty(dword);
        }

        /// <summary>Retrieves settings of median filter</summary>
        private NumSamples GetAverageFilter()
        {
            uint dword = GetFilterProperty();
            return (NumSamples)(dword & 0x3); //returns value of 0..1 bit
        }

        /// <summary>Enables/Disables median filter</summary>
        private void SetAverageFilter(NumSamples samples)
        {
            uint dword = GetFilterProperty();

            dword &= ~(3u); //clears 0..1. bit
            dword |= (uint)samples; //sets 0..1. bit

            SetFilterProperty(dword);
        }

        /// <summary>Retrieves minimal time between two packets setting (in ms)</summary>
        private uint GetPacketDelay()
        {
            int retValue = 0;
            uint resValue = 0;

            retValue = CLLTI.GetFeature(hDevice, CLLTI.FEATURE_FUNCTION_PACKET_DELAY, ref resValue);
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when reading Packet delay property");
                return 0;
            }

            return resValue;
        }

        /// <summary>Sets minimal time between two packets in ms. Neccessary when more devices connected.</summary>
        /// <param name="time">minimal span of two consequent packets in ms</param>
        private void SetPacketDelay(uint time)
        {
            int retValue = 0;

            retValue = CLLTI.SetFeature(hDevice, CLLTI.FEATURE_FUNCTION_PACKET_DELAY, time);
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when writing Packet delay property");
                return;
            }
        }

        #endregion

        #region constructor / destructor

        /// <summary>Constructor of ScannerLMS400 object</summary>
        public scanCONTROL2900BL()
        {

        }

        /// <summary>Destructor of ScannerLMS400 object</summary>
        public void Dispose()
        {
            if (Connected)
                Disconnect();

            CLLTI.DelDevice(hDevice);

            hDevice = 0;
        }

        #endregion

        #region public methods

        /// <summary>Connects to device using Ethernet</summary>
        /// <param name="IPaddress">IP address of device to connect</param>
        /// <returns>returns true if connected successfully</returns>
        public bool ConnectETH(string IPaddress)
        {
            //converting IP address to desired format
            string[] IPnums = IPaddress.Split('.');
            if (IPnums.Length != 4) //syntax error in IP address
            {
                Debug.WriteLine("scanCONTROL: Syntax error in IP address");
                return false;
            }
            uint IPpacked = (uint.Parse(IPnums[0]) << 24) | (uint.Parse(IPnums[1]) << 16) | (uint.Parse(IPnums[2]) << 8) | uint.Parse(IPnums[3]);

            return ConnectionProcedure(InterfaceType.INTF_TYPE_ETHERNET, IPpacked, 0);
        }

        /// <summary>Connects to device using Ethernet</summary>
        /// <param name="portNumber">number of serial port</param>
        /// <returns>returns true if connected successfully</returns>
        public bool ConnectSerial(uint portNumber)
        {
            return ConnectionProcedure(InterfaceType.INTF_TYPE_SERIAL, portNumber, 115200);
        }

        /// <summary>Connects to device using FireWire</summary>
        /// <param name="portNumber">Node ID</param>
        /// <returns>returns true if connected successfully</returns>
        public bool ConnectFirewire(uint nodeID)
        {
            return ConnectionProcedure(InterfaceType.INTF_TYPE_FIREWIRE, nodeID, 0);
        }

        /// <summary>Connects to device using Ethernet and default IP defined in constants</summary>
        public void Open()
        {
            ConnectETH(DEFAULT_IP);
        }

        /// <summary>Terminates connection with device</summary>
        /// <returns>returns true if disconnected successfully</returns>
        public bool Disconnect()
        {
            int retValue = 0;

            if (Measuring) //if is measuring -> stop
                StopMeas();

            if (!Connected) //already disconnected
            {
                Debug.WriteLine("scanCONTROL: Already disconnected");
                return false;
            }

            retValue = CLLTI.Disconnect(hDevice); //connect to device
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " during disconnect");
                return false;
            }

            isConnected = false; //setting internal connection flag
            if (OnClosed != null)
                OnClosed(this, EventArgs.Empty); //raise event

            return true;
        }
        public void Close()
        {
            Disconnect();
        }

        /// <summary>Starts continuous measuring process</summary>
        /// <returns>returns true if measuring started successfully</returns>
        public bool StartMeas()
        {
            int retValue = 0;

            retValue = CLLTI.TransferProfiles(hDevice, TransferProfileType.NORMAL_TRANSFER, 1); //enables (=1) continuous (=normal) measure
            //if (retValue != ReturnValues.OK)
            //{
            //    Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when starting continuous measure");
            //    return false;
            //}

            //Sleep for a while to warm up the transfer (required by device)
            System.Threading.Thread.Sleep(100);

            if (OnMeasureStart != null)
                OnMeasureStart(this, EventArgs.Empty); //raise event

            return true;
        }

        /// <summary>Stops continuous measuring process</summary>
        /// <returns>returns true if measuring stopped successfully</returns>
        public bool StopMeas()
        {
            int retValue = 0;

            retValue = CLLTI.TransferProfiles(hDevice, TransferProfileType.NORMAL_TRANSFER, 0); //disables (=0) continuous (=normal) measure
            if (retValue != ReturnValues.OK)
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when stopping continuous measure");
                return false;
            }

            if (OnMeasureStop != null)
                OnMeasureStop(this, EventArgs.Empty); //raise event

            return true;
        }

        /// <summary>Returns measured values (profile data)</summary>
        /// <returns>array of points defined by X and Z coordinates</returns>
        public XZpoint[] GetValues()
        {
            int retValue = 0;
            uint uiLostProfiles = 0;
            byte[] profileBuffer = new byte[Resolution * 16 + 16]; //allocation buffer for received data
            double[] valuesX = new double[Resolution]; //buffer for storing converted X values
            double[] valuesZ = new double[Resolution]; //buffer for storing converted Z values
            ushort[] valuesReflectionWidth = new ushort[Resolution]; //buffer for storing converted Z values
            ushort[] valuesMaxReflection = new ushort[Resolution]; //buffer for storing converted Z values

            //acquiring pure byte data
            retValue = CLLTI.GetActualProfile(hDevice, profileBuffer, profileBuffer.GetLength(0), ProfileConfig.QUARTER_PROFILE, ref uiLostProfiles);
            if (retValue != profileBuffer.GetLength(0))
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " when reading actual profile");
                if (retValue == -104) //no profiles, maybe it is disconnected
                {
                    if (CLLTI.IsTransferingProfiles(hDevice) == 0) //it is not transferring data -> it is disconnected
                    {
                        isConnected = false;
                        if (OnClosed != null)
                            OnClosed(this, EventArgs.Empty);
                    }
                }
                return null;
            }

            //conversion byte data to values
            retValue = CLLTI.ConvertProfile2Values(hDevice, profileBuffer, Resolution, ProfileConfig.QUARTER_PROFILE, DeviceType, 0, 1, valuesReflectionWidth, valuesMaxReflection, null, valuesX, valuesZ, null, null);
            if (((retValue & CLLTI.CONVERT_X) == 0) || ((retValue & CLLTI.CONVERT_Z) == 0) || ((retValue & CLLTI.CONVERT_MAXIMUM) == 0) || ((retValue & CLLTI.CONVERT_WIDTH) == 0))
            {
                Debug.WriteLine("scanCONTROL: Error " + retValue.ToString() + " during converting byte data to values");
                return null;
            }

            //reconfiguring data to XZPoint[]
            XZpoint[] points = new XZpoint[Resolution];
            for (int i = 0; i < Resolution; i++)
            {
                points[i] = new XZpoint(valuesX[i], valuesZ[i], valuesMaxReflection[i], valuesReflectionWidth[i]);
            }

            return points;
        }

        /// <summary>Returns true if driver is actually connected to device</summary>
        public bool IsAlive()
        {
            return Connected;
        }

        #endregion

        #region public parameters

        /// <summary>Selected interface for communication</summary>
        public InterfaceType Interface { get { return GetInterfaceType(); } }

        /// <summary>Format of data</summary>
        public uint Resolution { get { return GetResolution(); } set { SetResolution(value); } }

        /// <summary>Minimal time between two packets in us [0-1000 allowed]. Neccessary when more devices connected.</summary>
        public uint PacketDelay { get { return GetPacketDelay(); } set { SetPacketDelay(value); } }

        /// <summary>Type (version) of connected device</summary>
        public ScannerType DeviceType { get { return GetScannerType(); } }

        /// <summary>Name, type and version of connected device</summary>
        public string DeviceName { get { return GetDeviceName(); } }
        public string Name { get { return GetDeviceName(); } }

        /// <summary>Returs array of DSP, FPGA1 and FPGA2 firmware versions</summary>
        public uint[] FirmwareVersions { get { return GetLLTVersions(); } }

        /// <summary>Returs array of DSP, FPGA1 and FPGA2 firmware versions</summary>
        public uint SerialNumber { get { return GetSerialNumber(); } }

        /// <summary>Defines time when shutter is on. Defined in number of 10us, allowed range 1 .. 4095 (eg. 10..40950us)</summary>
        public uint ShutterTime { get { return GetShutterTime(); } set { SetShutterTime(value); } }

        /// <summary>Defines time when shutter is off. Defined in number of 10us, allowed range 1 .. 4095 (eg. 10..40950us)</summary>
        public uint IdleTime { get { return GetIdleTime(); } set { SetIdleTime(value); } }

        /// <summary>Enables automatic regulation of shutter time depending on scanned object</summary>
        public bool AutoShutter { get { return GetAutoShutter(); } set { SetAutoShutter(value); } }

        /// <summary>Enables supression of ambient light</summary>
        public bool AmbientLightSupression { get { return GetAmbientLight(); } set { SetAmbientLight(value); } }

        /// <summary>Enables video filter</summary>
        public bool VideoFilter { get { return GetVideoFilter(); } set { SetVideoFilter(value); } }

        /// <summary>Threshold for the selection of reflections. At targets with several reflections this may lead to better results.</summary>
        public uint ReflectionThreshold { get { return GetThreshold(); } set { SetThreshold(value); } }

        /// <summary>Returns true if driver is actually connected to device</summary>
        public bool Connected { get { return isConnected; } }

        /// <summary>Returns true if device is actually measuring. Some functions are disabled then.</summary>
        public bool Measuring { get { return (CLLTI.IsTransferingProfiles(hDevice) != 0); } }

        /// <summary>Enables interpolating of invalid points</summary>
        public bool InvalidPointsFilter { get { return GetInvalidPointsFilter(); } set { SetInvalidPointsFilter(value); } }

        /// <summary>Mode of Laser emitter</summary>
        public LaserModes LaserPower { get { return GetLaser(); } set { SetLaser(value); } }

        /// <summary>Sets range of scanning in X axis</summary>
        public XRanges XRange { get { return GetXRange(); } set { SetXRange(value); } }

        /// <summary>Enables/disables median filter</summary>
        public NumSamples MedianFilter { get { return GetMedianFilter(); } set { SetMedianFilter(value); } }

        /// <summary>Enables/disables average filter</summary>
        public NumSamples AverageFilter { get { return GetAverageFilter(); } set { SetAverageFilter(value); } }

        /// <summary>Returns actual configuration of device packed in one object</summary>
        public object Params { get { return new SensorInformation(this); } }

        #endregion

        #region static methods

        /// <summary>returns array of actually connected devices by selected interface. There is an array of IP addresses (when Ethernet selected) or Node IDs (Firewire) or usable COM ports (Serial)</summary>
        /// <returns></returns>
        public static string[] GetAvailableDevices(InterfaceType interf)
        {
            uint[] devices = new uint[MAX_INTERFACE_COUNT];

            uint handle = CLLTI.CreateLLTDevice(interf); //create instance for selected interface
            if (handle == 0)
            {
                Debug.WriteLine("scanCONTROL: Error when scanning for connected devices (cannot create device)");
                return new string[0];
            }

            int numOfDevices = CLLTI.GetDeviceInterfaces(handle, devices, devices.GetLength(0)); //acquire list of devices
            if (numOfDevices < 0)
            {
                Debug.WriteLine("scanCONTROL: Error " + numOfDevices.ToString() + " when scanning for connected devices");
                return new string[0];
            }

            CLLTI.DelDevice(handle); //delete instance

            if (interf == InterfaceType.INTF_TYPE_ETHERNET) // if Ethernet, parse IP address
            {
                string[] strDevices = new string[numOfDevices];
                for (int i = 0; i < numOfDevices; i++)
                {
                    strDevices[i] = (devices[i] >> 24).ToString() + "." +
                                    ((devices[i] >> 16) & 0xFF).ToString() + "." +
                                    ((devices[i] >> 8) & 0xFF).ToString() + "." +
                                    (devices[i] & 0xFF).ToString();
                }
                return strDevices;
            }
            else //otherwise, pass the numbers (Node ID or Com port)
                return Array.ConvertAll<uint, string>(devices, intParameter => intParameter.ToString());

        }

        #endregion

        #region events

        /// <summary>Connected to device</summary>
        public event EventHandler OnConnected;

        /// <summary>Disconnected from device</summary>
        public event EventHandler OnClosed;

        /// <summary>Continuous measure start</summary>
        public event EventHandler OnMeasureStart;

        /// <summary>Continuous measure stop</summary>
        public event EventHandler OnMeasureStop;

        #endregion
    }

}

