Imports System.Runtime.InteropServices

Module Module1
    Const PROLIFIC_VID As UShort = &H67B
    Const ERROR_SUCCESS As Int32 = 0
    Const ERROR_INSUFFICIENT_BUFFER As Int32 = -1
    Const ERROR_READ_REGISTER_FAIL As Int32 = -2
    Const ERROR_WRITE_REGISTER_FAIL As Int32 = -3
    Const ERROR_READ_DATA_FAIL As Int32 = -4
    Const ERROR_READ_TIMEOUT As Int32 = -5
    Const ERROR_WRITE_DATA_FAIL As Int32 = -6
    Const ERROR_WRITE_TIMEOUT As Int32 = -7
    Const ERROR_DEVICE_NOT_EXIST As Int32 = -8
    Const ERROR_NOT_GPIO_PIN As Int32 = -9
    Const ERROR_DEVICE_OPEN_FAIL As Int32 = -10
    Const ERROR_DATA_LENGTH_TOO_LARGE As Int32 = -11
    Const ERROR_OTHER_FAIL As Int32 = -12
    Const ERROR_I2C_BUS_BUSY As Int32 = -13
    Const ERROR_I2C_ADDRESS_NACK As Int32 = -14
    Const ERROR_I2C_DATA_NACK As Int32 = -15
    Const ERROR_I2C_PROCESSING As Int32 = -16

    Enum SPI_SELECT
        SPI_SELECT0 = &H0
        SPI_SELECT1 = &H10
    End Enum

    Enum SPI_MODE
        SPI_MODE0 = &H0
        SPI_MODE1 = &H10
        SPI_MODE2 = &H20
        SPI_MODE3 = &H30
    End Enum

    <DllImport("HidDeviceSdk.dll")> _
    Public Function EnumDeviceByVid(ByRef HidDeviceCount As UInteger, ByVal VID As UShort) As Int32
    End Function

    <DllImport("HidDeviceSdk.dll")> _
    Public Function OpenDeviceHandle(ByVal DeviceIndex As UInteger, ByRef hDeviceHandle As IntPtr) As Int32
    End Function

    <DllImport("HidDeviceSdk.dll")> _
    Public Function CloseDeviceHandle(ByVal hDeviceHandle As IntPtr) As Int32
    End Function

    <DllImport("HidDeviceSdk.dll")> _
    Public Function SetSPIFrequency(ByVal hDeviceHandle As IntPtr, ByVal FreqDiv As Byte, ByVal spiMode As SPI_MODE) As Int32
    End Function

    <DllImport("HidDeviceSdk.dll")> _
    Public Function SPIRead(ByVal hDeviceHandle As IntPtr, ByVal SPISelect As SPI_SELECT, ByRef ReadBuffer As Byte, _
                            ByVal NumberOfBytesToRead As UInteger, ByRef NumberOfBytesRead As UInteger, _
                            ByVal TimeOutms As UInteger) As Int32
    End Function

    <DllImport("HidDeviceSdk.dll")> _
    Public Function SPIWrite(ByVal hDeviceHandle As IntPtr, ByVal SPISelect As SPI_SELECT, ByRef WriteBuffer As Byte, _
                            ByVal NumberOfBytesToWrite As UInteger, ByRef NumberOfBytesWritten As UInteger, _
                            ByVal TimeOutms As UInteger) As Int32
    End Function

    <DllImport("HidDeviceSdk.dll")> _
    Public Function SPIWriteRead(ByVal hDeviceHandle As IntPtr, ByVal SPISelect As SPI_SELECT, ByRef WriteBuffer As Byte, _
                        ByVal NumberOfBytesToWrite As UInteger, ByRef ReadBuffer As Byte, ByVal NumberOfBytesToRead As UInteger, _
                        ByRef NumberOfBytesUse As UInteger, ByVal TimeOutms As UInteger) As Int32
    End Function

    <DllImport("HidDeviceSdk.dll")> _
    Public Function SPIReset(ByVal hDeviceHandle As IntPtr) As Int32
    End Function

    Sub Main()

        Dim nHidDeviceCount As UInteger = 0
        Dim hDeviceHandle As IntPtr = -1
        Dim nRet As UInteger = 0
        'Step1: Enum Device (&067B ==> USB VID)
        nRet = EnumDeviceByVid(nHidDeviceCount, PROLIFIC_VID)
        If ERROR_SUCCESS = nRet Then
            If nHidDeviceCount > 0 Then
                'Step2: Open Hid Device Array index, ex: 0
                nRet = OpenDeviceHandle(0, hDeviceHandle)
                If ERROR_SUCCESS = nRet Then
                    'Step3: Set SPI Frequency(MAX 4.8 MHZ)
                    'nSPIFreqDiv = 4, SPI Frequency(KHz) = 24000/(4+1) = 4.8 Mhz(Max)
                    'nSPIFreqDiv = 254, SPI Frequency(KHz) = 24000/(254+1) = 94 Khz(Min)
                    Dim nSPIFreqDiv As UInteger = 19    '//SPI Frequency(KHz) = 24000/(19+1) = 1,200 KHz
                    nRet = SetSPIFrequency(hDeviceHandle, nSPIFreqDiv, SPI_MODE.SPI_MODE3)

                    Dim nSpiSelect As SPI_SELECT = SPI_SELECT.SPI_SELECT0
                    Dim nSPICommand As Byte
                    Dim nRealDataLen As UInteger
                    Dim nTimeOutMs As ULong = 1000  'Unit: ms

                    Dim nNumberOfBytesToRead As UInteger
                    'Send Read Identification(RDID) 0x9F Command
                    Dim byReadBuffer(10) As Byte
                    nSPICommand = &H9F
                    nNumberOfBytesToRead = 3
                    nRealDataLen = 0
                    nRet = SPIWriteRead(hDeviceHandle, nSpiSelect, nSPICommand, &H1, byReadBuffer(0), _
                                        nNumberOfBytesToRead, nRealDataLen, nTimeOutMs)
                    If ERROR_SUCCESS = nRet Then
                        Console.WriteLine("ManufactureId=0x{0:X}, MemoryType=0x{1:X}, MemoryDenisty=0x{2:X}", byReadBuffer(0), _
                                          byReadBuffer(1), byReadBuffer(2))
                    Else
                        Console.WriteLine("SPI Read Identification(RDID) Command Fail!")
                    End If

                    'Send Read Status Register(RDSR) 0x05 Command
                    nSPICommand = &H5
                    nNumberOfBytesToRead = 1
                    nRealDataLen = 0
                    nRet = SPIWriteRead(hDeviceHandle, nSpiSelect, nSPICommand, &H1, byReadBuffer(0), _
                                        nNumberOfBytesToRead, nRealDataLen, nTimeOutMs)
                    If ERROR_SUCCESS = nRet Then
                        Console.WriteLine("SPI Status=0x{0:X}", byReadBuffer(0))
                    Else
                        Console.WriteLine("SPI Read Status Register(RDSR) Command Fail!")
                    End If

                    'Send write Enable(WREN) 0x06 Command
                    nSPICommand = &H6       'SPI Write Enable Command
                    nNumberOfBytesToRead = 1
                    nRealDataLen = 0
                    nRet = SPIWrite(hDeviceHandle, nSpiSelect, nSPICommand, &H1, nRealDataLen, nTimeOutMs)
                    'SPIWrite Sample (Send SPI Write Enable Command)
                    If ERROR_SUCCESS = nRet Then
                        Console.WriteLine("SPI Write Enable Command Success!")
                    Else
                        Console.WriteLine("SPI Write Enable Command Fail!")
                    End If

                    'Send Read Status Register(RDSR) 0x05 Command
                    nSPICommand = &H5
                    nNumberOfBytesToRead = 1
                    nRealDataLen = 0
                    Const STATUS_WEL_WRITE_ENABLE As Int32 = &H2    'WEL
                    For n As Integer = 0 To 9
                        nRet = SPIWriteRead(hDeviceHandle, nSpiSelect, nSPICommand, &H1, byReadBuffer(0), _
                             nNumberOfBytesToRead, nRealDataLen, nTimeOutMs)
                        If ERROR_SUCCESS = nRet Then
                            Console.WriteLine("SPI Status=0x{0:X}", byReadBuffer(0))
                        Else
                            Console.WriteLine("SPI Read Status Register(RDSR) Command Fail!")
                        End If

                        'check Write Enable (WEL bit1 = 1)
                        If STATUS_WEL_WRITE_ENABLE = (byReadBuffer(0) And STATUS_WEL_WRITE_ENABLE) Then
                            Console.WriteLine("SPI Write Enable Success!")
                            Exit For
                        Else
                            Threading.Thread.Sleep(100)
                        End If
                    Next

                    'Send Erase Command and Page Program Command

                    'Send Read Status Register(RDSR) 0x05 Command and Wait WIP bit0 = 0

                    'Send read data(Read) 0x03 Command
                    Dim byWriteBuffer(10) As Byte
                    byWriteBuffer(0) = &H3  'Read Data Command
                    byWriteBuffer(1) = 0    'AD1
                    byWriteBuffer(2) = 0    'AD2
                    byWriteBuffer(3) = 0    'AD3

                    nNumberOfBytesToRead = 10
                    nRealDataLen = 0
                    nRet = SPIWriteRead(hDeviceHandle, nSpiSelect, byWriteBuffer(0), &H4, byReadBuffer(0), _
                                        nNumberOfBytesToRead, nRealDataLen, nTimeOutMs)
                    If ERROR_SUCCESS = nRet Then
                        Console.Write("Read Data: ")
                        For n As Integer = 0 To 9
                            Console.Write("0x{0:X} ", byReadBuffer(n))
                        Next
                        Console.WriteLine("")
                    Else
                        Console.WriteLine("SPI Read Data Command Fail!")
                    End If
                Else
                    Console.WriteLine("Open device Fail!")
                End If
                'Step6: Close Hid Device
                nRet = CloseDeviceHandle(hDeviceHandle)
            Else
                Console.WriteLine("No match Hid device!")
            End If
        Else
            Console.WriteLine("EnumDeviceByVid fail!")
        End If
        Console.ReadLine()
    End Sub

End Module
