'ReceiveMeasurement.vb

'Gocator 2000/2300 Visual Basic 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 and receive measurement data under Profile Mode. Measurements should have been setup and have the outputs enabled via Ethernet.
'Please refer to SetupMeasurement.c for configuring the measurements.

Imports System.Threading
Imports System.Runtime.InteropServices

Module ReceiveMeasurement
    Public Const IP As String = "192.168.1.10"
    Public Class Constants
#If DEBUG Then
        Public Const GODLLPATH As String = "GoSdk.dll"
        Public Const KAPIDLLPATH As String = "kApi.dll"
#Else
        Public Const GODLLPATH As String = "GoSdk.dll"
        Public Const KAPIDLLPATH As String = "kApi.dll"
#End If
    End Class
    Public Structure address
        Public version As Char
        <MarshalAs(UnmanagedType.ByValArray, SizeConst:=16)> _
        Public IPaddress() As Byte
    End Structure

    Public Structure GoMeasurementData
        Public value As Double
        Public decision As SByte
    End Structure

    Public Structure GoStamp
        Public frameIndex As UInt64
        Public timestamp As UInt64
        Public encoder As Int64
        Public encoderAtZ As Int64
        Public reserved As UInt64
    End Structure

    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. 
    End Enum

    Enum GoDataMessageTypes
        GO_DATA_MESSAGE_TYPE_UNKNOWN = -1
        GO_DATA_MESSAGE_TYPE_STAMP = 0
        GO_DATA_MESSAGE_TYPE_HEALTH = 1
        GO_DATA_MESSAGE_TYPE_VIDEO = 2
        GO_DATA_MESSAGE_TYPE_RANGE = 3
        GO_DATA_MESSAGE_TYPE_RANGE_INTENSITY = 4
        GO_DATA_MESSAGE_TYPE_PROFILE = 5
        GO_DATA_MESSAGE_TYPE_PROFILE_INTENSITY = 6
        GO_DATA_MESSAGE_TYPE_RESAMPLED_PROFILE = 7
        GO_DATA_MESSAGE_TYPE_SURFACE = 8
        GO_DATA_MESSAGE_TYPE_SURFACE_INTENSITY = 9
        GO_DATA_MESSAGE_TYPE_MEASUREMENT = 10
        GO_DATA_MESSAGE_TYPE_ALIGNMENT = 11
        GO_DATA_MESSAGE_TYPE_EXPOSURE_CAL = 12
    End Enum

    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
    End Enum

    Enum GoRole
        GO_ROLE_MAIN = 0                                                    ' Sensor is operating as a main sensor
        GO_ROLE_BUDDY = 1                                                   ' Sensor is operating as a buddy sensor
    End Enum

    ' use DLL import to access GoSdkd.dll
    ' Note: to import the release version of the GoSdk and kApi, use GoSdk.dll and kApi.dll. GoSdkd.dll and kApid.dll are debug versions of the DLL
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoSdk_Construct(ByRef assembly As IntPtr) As kStatus
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoSystem_Construct(ByRef system As IntPtr, ByVal allocator As IntPtr) As kStatus
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoSystem_FindSensorByIpAddress(ByVal system As IntPtr, ByVal addressPointer As IntPtr, ByRef sensor As IntPtr) As kStatus
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoSystem_EnableData(ByVal system As IntPtr, ByVal enable As Boolean) As kStatus
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoSensor_Connect(ByVal sensor As IntPtr) As kStatus
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoSystem_ReceiveData(ByVal system As IntPtr, ByRef data As IntPtr, ByVal timeout As UInt64) As kStatus
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoSystem_Start(ByVal system As IntPtr) As kStatus
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoSystem_Stop(ByVal system As IntPtr) As kStatus
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoDataSet_Count(ByVal dataset As IntPtr) As UInt32
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoDataSet_At(ByVal dataset As IntPtr, ByVal index As UInt32) As IntPtr
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoStampMsg_Count(ByVal msg As IntPtr) As UInt32
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoStampMsg_At(ByVal msg As IntPtr, ByVal index As UInt32) As IntPtr
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoSensor_Setup(ByVal sensor As IntPtr) As IntPtr
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoSensor_Tools(ByVal sensor As IntPtr) As IntPtr
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoTools_AddTool(ByVal sensor As IntPtr, ByVal type As GoToolType) As IntPtr
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoProfilePosition_ZMeasurement(ByVal tool As IntPtr) As IntPtr
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoMeasurement_Enable(ByVal measurement As IntPtr, ByVal enable As Boolean) As Int32
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoMeasurement_SetId(ByVal measurement As IntPtr, ByVal id As UInt32) As Int32
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoProfilePosition_Feature(ByVal tool As IntPtr) As IntPtr
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoProfileFeature_SetType(ByVal feature As IntPtr, ByVal featuretype As Int32) As Int32
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoProfileFeature_Region(ByVal feature As IntPtr) As IntPtr
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoProfileRegion_SetX(ByVal region As IntPtr, ByVal x As Double) As Int32
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoProfileRegion_SetZ(ByVal region As IntPtr, ByVal z As Double) As Int32
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoProfileRegion_SetHeight(ByVal region As IntPtr, ByVal height As Double) As Int32
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoProfileRegion_SetWidth(ByVal region As IntPtr, ByVal width As Double) As Int32
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoSetup_TransformedDataRegionX(ByVal setup As IntPtr, ByVal role As GoRole) As Double
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoSetup_TransformedDataRegionZ(ByVal setup As IntPtr, ByVal role As GoRole) As Double
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoSetup_TransformedDataRegionHeight(ByVal setup As IntPtr, ByVal role As GoRole) As Double
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoSetup_TransformedDataRegionWidth(ByVal setup As IntPtr, ByVal role As GoRole) As Double
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoSensor_Output(ByVal sensor As IntPtr) As IntPtr
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoOutput_Ethernet(ByVal output As IntPtr) As IntPtr
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoEthernet_ClearAllSources(ByVal ethernet As IntPtr) As Int32
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoEthernet_AddSource(ByVal ethernet As IntPtr, ByVal GoOutputSource As Int32, ByVal sourceId As UInt32) As Int32
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoDataMsg_Type(ByVal msg As IntPtr) As GoDataMessageTypes
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoMeasurementMsg_Count(ByVal msg As IntPtr) As UInt32
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoMeasurementMsg_Id(ByVal msg As IntPtr) As UInt16
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoMeasurementMsg_At(ByVal msg As IntPtr, ByVal index As UInt32) As IntPtr
    End Function
    <DllImport(Constants.GODLLPATH)> _
    Public Function GoDestroy(ByVal obj As IntPtr) As kStatus
    End Function
    <DllImport(Constants.KAPIDLLPATH)> _
    Public Function kIpAddress_Parse(ByVal addressPointer As IntPtr, ByVal text As String) As kStatus
    End Function

    Function Main() As Integer
        Dim status As kStatus
        Dim api As IntPtr = IntPtr.Zero
        Dim system As IntPtr = IntPtr.Zero
        Dim sensor As IntPtr = IntPtr.Zero
        Dim dataset As IntPtr = IntPtr.Zero
        Dim dataObj As IntPtr = IntPtr.Zero
        Dim stampMsg As IntPtr = IntPtr.Zero
        Dim stampPtr As IntPtr = IntPtr.Zero
        Dim measurementMsg As IntPtr = IntPtr.Zero
        Dim measurementMsgPtr As IntPtr = IntPtr.Zero
        Dim addr As New address
        Dim addrPtr As IntPtr = IntPtr.Zero
        Dim stamp As GoStamp
        Dim measurementdata As GoMeasurementData


        status = GoSdk_Construct(api)
        If status <> 1 Then
            Console.WriteLine("GoSdk_Construct Error:{0}", status)
            Return status
        End If

        status = GoSystem_Construct(system, IntPtr.Zero)
        If status <> 1 Then
            Console.WriteLine("GoSystem_Construct Error:{0}", status)
            Return status
        End If

        addrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(addr))
        Marshal.StructureToPtr(addr, addrPtr, False)

        status = kIpAddress_Parse(addrPtr, IP)
        If status <> 1 Then
            Console.WriteLine("kIpAddress_Parse Error:{0}", status)
            Return status
        End If

        status = GoSystem_FindSensorByIpAddress(system, addrPtr, sensor)
        If status <> 1 Then
            Console.WriteLine("GoSystem_FindSensorByIpAddress Error:{0}", status)
            Return status
        End If

        status = GoSensor_Connect(sensor)
        If status <> 1 Then
            Console.WriteLine("GoSensor_Connect Error:{0}", status)
            Return status
        End If

        status = GoSystem_EnableData(system, True)
        If status <> 1 Then
            Console.WriteLine("GoSystem_EnableData Error:{0}", status)
            Return status
        End If

        status = GoSystem_Start(system)
        If status <> 1 Then
            Console.WriteLine("GoSystem_Start Error:{0}", status)
            Return status
        End If

        ' read data from sensor
        status = GoSystem_ReceiveData(system, dataset, 2000000)
        If status = 1 Then
            Dim itemCount = GoDataSet_Count(dataset)
            ' each result can have multiple data items
            ' loop through all items in result message
            For i As Integer = 0 To itemCount - 1
                dataObj = GoDataSet_At(dataset, i)
                ' retrieve GoStamp message
                If GoDataMsg_Type(dataObj) = GoDataMessageTypes.GO_DATA_MESSAGE_TYPE_STAMP Then
                    stampMsg = dataObj
                    For j As Integer = 0 To GoStampMsg_Count(stampMsg) - 1
                        stampPtr = GoStampMsg_At(stampMsg, j)
                        stamp = Marshal.PtrToStructure(stampPtr, GetType(GoStamp))
                        Console.WriteLine("Frame Index = {0}", stamp.frameIndex)
                        Console.WriteLine("Time Stamp = {0}", stamp.timestamp)
                        Console.WriteLine("Encoder Value = {0}", stamp.encoder)
                    Next
                End If
                ' retrieve measurement message
                If GoDataMsg_Type(dataObj) = GoDataMessageTypes.GO_DATA_MESSAGE_TYPE_MEASUREMENT Then
                    measurementMsg = dataObj
                    Console.WriteLine("  Measurement Message batch count: {0}", GoMeasurementMsg_Count(measurementMsg))
                    For j As Integer = 0 To GoStampMsg_Count(stampMsg) - 1
                        measurementMsgPtr = GoMeasurementMsg_At(measurementMsg, j)
                        measurementdata = Marshal.PtrToStructure(measurementMsgPtr, GetType(GoMeasurementData))
                        Console.WriteLine("ID: {0}", GoMeasurementMsg_Id(measurementMsg))
                        Console.WriteLine("Value: {0}", measurementdata.value)
                        Console.WriteLine("Decision: {0}", measurementdata.decision)
                    Next
                End If
            Next
        End If

        status = GoSystem_Stop(system)
        If status <> 1 Then
            Console.WriteLine("GoSystem_Stop Error:{0}", status)
            Return status
        End If

        status = GoDestroy(system)
        If status <> 1 Then
            Console.WriteLine("GoDestroy Error:{0}", status)
            Return status
        End If

        status = GoDestroy(api)
        If status <> 1 Then
            Console.WriteLine("GoDestroy Error:{0}", status)
            Return status
        End If

        'wait for ENTER key
        Console.WriteLine("Press ENTER to continue")
        Do While Not Console.ReadKey(True).Key = ConsoleKey.Enter
            Thread.Sleep(100)
        Loop
        Return status
    End Function
End Module
