/*
 * SetupMeasurement.cs
 * 
 * Gocator 2000/2300 C# Sample
 * Copyright (C) 2013 by LMI Technologies Inc.
 * 
 * Licensed under The MIT License.
 * Redistributions of files must retain the above copyright notice.
 *
 * Purpose: Connect to Gocator system, setup measurement data under Profile Mode.
 * Please refer to ReceiveMeasurement.c for receiving of the measurement data.
 */

using System;
using System.Runtime.InteropServices;

static class Constants
{
    public const string SENSOR_IP = "192.168.1.10"; // IP of the sensor used for sensor connection GoSystem_FindSensorByIpAddress() call.
#if DEBUG
    public const string GODLLPATH = @"GoSdk.dll";
    public const string KAPIDLLPATH = @"kApi.dll";
#else
    public const string GODLLPATH = @"GoSdk.dll";
    public const string KAPIDLLPATH = @"kApi.dll";
#endif
}

namespace SetupMeasurement
{

    public struct GoStamp
    {
        public UInt64 frameIndex;
        public UInt64 timestamp;
        public Int64 encoder;
        public Int64 encoderAtZ;
        public UInt64 reserved;
    }

    public struct address
    {
        public Int32 version;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] IPaddress;
    }

    class SetupMeasurement
    {
        enum kStatus
        {
            kERROR_STATE = -1000,                                                // Invalid state.
            kERROR_NOT_FOUND = -999,                                             // Item is not found.
            kERROR_COMMAND = -998,                                               // Command not recognized.
            kERROR_PARAMETER = -997,                                             // Parameter is invalid.
            kERROR_UNIMPLEMENTED = -996,                                         // Feature not implemented.
            kERROR_HANDLE = -995,                                                // Handle is invalid.
            kERROR_MEMORY = -994,                                                // Out of memory.
            kERROR_TIMEOUT = -993,                                               // Action timed out.
            kERROR_INCOMPLETE = -992,                                            // Buffer not large enough for data.
            kERROR_STREAM = -991,                                                // Error in stream.
            kERROR_CLOSED = -990,                                                // Resource is no longer avaiable. 
            kERROR_VERSION = -989,                                               // Invalid version number.
            kERROR_ABORT = -988,                                                 // Operation aborted.
            kERROR_ALREADY_EXISTS = -987,                                        // Conflicts with existing item.
            kERROR_NETWORK = -986,                                               // Network setup/resource error.
            kERROR_HEAP = -985,                                                  // Heap error (leak/double-free).
            kERROR_FORMAT = -984,                                                // Data parsing/formatting error. 
            kERROR_READ_ONLY = -983,                                             // Object is read-only (cannot be written).
            kERROR_WRITE_ONLY = -982,                                            // Object is write-only (cannot be read). 
            kERROR_BUSY = -981,                                                  // Agent is busy (cannot service request).
            kERROR_CONFLICT = -980,                                              // State conflicts with another object.
            kERROR_OS = -979,                                                    // Generic error reported by underlying OS.
            kERROR_DEVICE = -978,                                                // Hardware device error.
            kERROR_FULL = -977,                                                  // Resource is already fully utilized.
            kERROR_IN_PROGRESS = -976,                                           // Operation is in progress, but not yet complete.
            kERROR = 0,                                                          // General error. 
            kOK = 1                                                              // Operation successful. 
        }

        enum GoToolType
        {
            GO_TOOL_UNKNOWN = -1,
            GO_TOOL_RANGE_POSITION = 0,
            GO_TOOL_RANGE_THICKNESS = 1,
            GO_TOOL_PROFILE_AREA = 2,
            GO_TOOL_PROFILE_CIRCLE = 3,
            GO_TOOL_PROFILE_DIMENSION = 4,
            GO_TOOL_PROFILE_GROOVE = 5,
            GO_TOOL_PROFILE_INTERSECT = 6,
            GO_TOOL_PROFILE_LINE = 7,
            GO_TOOL_PROFILE_PANEL = 8,
            GO_TOOL_PROFILE_POSITION = 9,
            GO_TOOL_PROFILE_STRIP = 10,
            GO_TOOL_SURFACE_BOUNDING_BOX = 11,
            GO_TOOL_SURFACE_ELLIPSE = 12,
            GO_TOOL_SURFACE_HOLE = 13,
            GO_TOOL_SURFACE_OPENING = 14,
            GO_TOOL_SURFACE_PLANE = 15,
            GO_TOOL_SURFACE_POSITION = 16,
            GO_TOOL_SURFACE_STUD = 17,
            GO_TOOL_SURFACE_VOLUME = 18,
            GO_TOOL_SCRIPT = 19
        }

        enum GoRole
        {
            GO_ROLE_MAIN = 0,                                                    // Sensor is operating as a main sensor.
            GO_ROLE_BUDDY = 1                                                    // Sensor is operating as a buddy sensor.
        }

        // use DLL import to access GoSdkd.dll/GoSdk.dll and kApid.dll/kApi.dll
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoSdk_Construct(ref IntPtr assembly);
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoSystem_Construct(ref IntPtr system, IntPtr allocator);
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoSystem_FindSensorById(IntPtr system, UInt32 id, ref IntPtr sensor);
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoSystem_FindSensorByIpAddress(IntPtr system, IntPtr addr, ref IntPtr sensor);
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoSystem_EnableData(IntPtr system, bool enable);
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoSystem_ReceiveData(IntPtr system, ref IntPtr data, UInt64 timeout);
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoSensor_Connect(IntPtr sensor);
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoSystem_Start(IntPtr system);
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoSystem_Stop(IntPtr system);
        [DllImport(Constants.GODLLPATH)]
        private static extern IntPtr GoSensor_Setup(IntPtr sensor);
        [DllImport(Constants.GODLLPATH)]
        private static extern UInt32 GoDataSet_Count(IntPtr dataset);
        [DllImport(Constants.GODLLPATH)]
        private static extern IntPtr GoDataSet_At(IntPtr dataset, UInt32 index);
        [DllImport(Constants.GODLLPATH)]
        private static extern UInt32 GoStampMsg_Count(IntPtr msg);
        [DllImport(Constants.GODLLPATH)]
        private static extern IntPtr GoStampMsg_At(IntPtr msg, UInt32 index);
        [DllImport(Constants.GODLLPATH)]
        private static extern IntPtr GoSensor_Tools(IntPtr sensor);
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoTools_AddTool(IntPtr tools, GoToolType type, ref IntPtr tool);
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoTool_SetName(IntPtr tools, [MarshalAs(UnmanagedType.LPStr)] string name);
        [DllImport(Constants.GODLLPATH)]
        private static extern IntPtr GoProfilePosition_ZMeasurement(IntPtr tool);
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoMeasurement_Enable(IntPtr measurement, bool enable);
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoMeasurement_SetId(IntPtr measurement, UInt32 id);
        [DllImport(Constants.GODLLPATH)]
        private static extern IntPtr GoProfilePosition_Feature(IntPtr tool);
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoProfileFeature_SetType(IntPtr feature, Int32 featuretype);
        [DllImport(Constants.GODLLPATH)]
        private static extern IntPtr GoProfileFeature_Region(IntPtr feature);
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoProfileRegion_SetX(IntPtr region, double x);
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoProfileRegion_SetZ(IntPtr region, double z);
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoProfileRegion_SetHeight(IntPtr region, double height);
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoProfileRegion_SetWidth(IntPtr region, double width);
        [DllImport(Constants.GODLLPATH)]
        private static extern double GoSetup_TransformedDataRegionX(IntPtr setup, GoRole role);
        [DllImport(Constants.GODLLPATH)]
        private static extern double GoSetup_TransformedDataRegionZ(IntPtr setup, GoRole role);
        [DllImport(Constants.GODLLPATH)]
        private static extern double GoSetup_TransformedDataRegionHeight(IntPtr setup, GoRole role);
        [DllImport(Constants.GODLLPATH)]
        private static extern double GoSetup_TransformedDataRegionWidth(IntPtr setup, GoRole role);
        [DllImport(Constants.GODLLPATH)]
        private static extern IntPtr GoSensor_Output(IntPtr sensor);
        [DllImport(Constants.GODLLPATH)]
        private static extern IntPtr GoOutput_Ethernet(IntPtr output);
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoEthernet_ClearAllSources(IntPtr ethernet);
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoEthernet_AddSource(IntPtr ethernet, Int32 GoOutputSource, UInt32 sourceId);
        [DllImport(Constants.GODLLPATH)]
        private static extern UInt32 GoSetup_XSpacingCount(IntPtr setup, GoRole role);
        [DllImport(Constants.GODLLPATH)]
        private static extern UInt32 GoMeasurementMsg_Count(IntPtr msg);
        [DllImport(Constants.GODLLPATH)]
        private static extern UInt16 GoMeasurementMsg_Id(IntPtr msg);
        [DllImport(Constants.GODLLPATH)]
        private static extern IntPtr GoMeasurementMsg_At(IntPtr msg, UInt32 index);
        [DllImport(Constants.GODLLPATH)]
        private static extern Int32 GoDestroy(IntPtr obj);
        [DllImport(Constants.KAPIDLLPATH)]
        private static extern Int32 kIpAddress_Parse(IntPtr addrPtr, [MarshalAs(UnmanagedType.LPStr)] string text);

        static int Main(string[] args)
        {
            kStatus status;
            IntPtr api = IntPtr.Zero;
            IntPtr system = IntPtr.Zero;
            IntPtr sensor = IntPtr.Zero;
            IntPtr setup = IntPtr.Zero;
            IntPtr tools = IntPtr.Zero;
            IntPtr profilePositionTool = IntPtr.Zero;
            IntPtr zprofileMeasurementTop = IntPtr.Zero;
            IntPtr profileFeatureTop = IntPtr.Zero;
            IntPtr regionTop = IntPtr.Zero;
            IntPtr outputModule = IntPtr.Zero;
            IntPtr ethernetOutput = IntPtr.Zero;
            IntPtr addrPtr = IntPtr.Zero;
            address addr = new address();

            if ((status = (kStatus)GoSdk_Construct(ref api)) != kStatus.kOK)
            {
                Console.WriteLine("GoSdk_Construct Error:{0}", (int)status);
                return (int)status;
            }

            if ((status = (kStatus)GoSystem_Construct(ref system, IntPtr.Zero)) != kStatus.kOK)
            {
                Console.WriteLine("GoSystem_Construct Error:{0}", (int)status);
                return (int)status;
            }

            addrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(addr));
            Marshal.StructureToPtr(addr, addrPtr, false);

            if ((status = (kStatus)kIpAddress_Parse(addrPtr, Constants.SENSOR_IP)) != kStatus.kOK)
            {
                Console.WriteLine("kIpAddress_Parse Error:{0}", (int)status);
                return (int)status;
            }

            if ((status = (kStatus)GoSystem_FindSensorByIpAddress(system, addrPtr, ref sensor)) != kStatus.kOK)
            {
                Console.WriteLine("GoSystem_FindSensorByIpAddress Error:{0}", (int)status);
                return (int)status;
            }

            if ((status = (kStatus)GoSensor_Connect(sensor)) != kStatus.kOK)
            {
                Console.WriteLine("GoSensor_Connect Error:{0}", (int)status);
                return (int)status;
            }

            if ((status = (kStatus)GoSystem_EnableData(system, true)) != kStatus.kOK)
            {
                Console.WriteLine("GoSystem_EnableData Error:{0}", (int)status);
                return (int)status;
            }

            //retrieve setup handle
            setup = GoSensor_Setup(sensor);
            //retrieve tools handle
            tools = GoSensor_Tools(sensor);
            // add ProfilePosition tool, retreive tool handle
            GoTools_AddTool(tools, GoToolType.GO_TOOL_PROFILE_POSITION, ref profilePositionTool);
            // set name for tool
            GoTool_SetName(profilePositionTool, "Profile position Test");
            // add Z measurement for ProfilePosition tool
            zprofileMeasurementTop = GoProfilePosition_ZMeasurement(profilePositionTool);

            if ((status = (kStatus)GoMeasurement_Enable(zprofileMeasurementTop, true)) != kStatus.kOK)
            {
                Console.WriteLine(" GoMeasurement_Enable Error:{0}", (int)status);
                return (int)status;
            }

            if ((status = (kStatus)GoMeasurement_SetId(zprofileMeasurementTop, 0)) != kStatus.kOK)
            {
                Console.WriteLine(" GoMeasurement_SetId Error:{0}", (int)status);
                return (int)status;
            }

            //set ProfilePosition feature to top
            profileFeatureTop = GoProfilePosition_Feature(profilePositionTool);

            if ((status = (kStatus)GoProfileFeature_SetType(profileFeatureTop, 0)) != kStatus.kOK)
            {
                Console.WriteLine(" GoProfileFeature_SetType Error:{0}", (int)status);
                return (int)status;
            }

            // set the ROI to fill the entire active area
            regionTop = GoProfileFeature_Region(profileFeatureTop);
            GoProfileRegion_SetX(regionTop, GoSetup_TransformedDataRegionX(setup, GoRole.GO_ROLE_MAIN));
            GoProfileRegion_SetZ(regionTop, GoSetup_TransformedDataRegionZ(setup, GoRole.GO_ROLE_MAIN));
            GoProfileRegion_SetHeight(regionTop, GoSetup_TransformedDataRegionHeight(setup, GoRole.GO_ROLE_MAIN));
            GoProfileRegion_SetWidth(regionTop, GoSetup_TransformedDataRegionWidth(setup, GoRole.GO_ROLE_MAIN));

            // enable Ethernet output for measurement tool
            outputModule = GoSensor_Output(sensor);
            ethernetOutput = GoOutput_Ethernet(outputModule);
            GoEthernet_ClearAllSources(ethernetOutput);
            GoEthernet_AddSource(ethernetOutput, 8, 0);

            // destroy handles
            GoDestroy(system);
            GoDestroy(api);

            // wait for ESC key
            Console.WriteLine("\nPress ENTER to continue");
            do
            {
                System.Threading.Thread.Sleep(100);

            } while (Console.Read() != (int)ConsoleKey.Enter);

            return (int)kStatus.kOK;
        }
    }
}
