using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace SLAB_DFU_DLL
{
    public class SLAB_DFU
    {
        /////////////////////////////////////////////////////////////////////////////
        // SLAB_DFU.h
        // For SLAB_DFU.dll version 1.0
        /////////////////////////////////////////////////////////////////////////////

        /////////////////////////////////////////////////////////////////////////////
        // DLL Preprocessor Definitions
        /////////////////////////////////////////////////////////////////////////////

        /////////////////////////////////////////////////////////////////////////////
        // Type Definitions - Windows Types
        /////////////////////////////////////////////////////////////////////////////

        /////////////////////////////////////////////////////////////////////////////
        // Definitions - Windows Definitions
        /////////////////////////////////////////////////////////////////////////////

        public const int MAX_PATH = 260;

        /////////////////////////////////////////////////////////////////////////////
        // Type Definitions - DFU_CODE
        /////////////////////////////////////////////////////////////////////////////

        /////////////////////////////////////////////////////////////////////////////
        // Definitions - byte : Success Return Codes
        /////////////////////////////////////////////////////////////////////////////

        public const byte DFU_CODE_SUCCESS = 0x00;

        /////////////////////////////////////////////////////////////////////////////
        // Definitions - byte : API Errors
        /////////////////////////////////////////////////////////////////////////////

        public const byte DFU_CODE_API_INVALID_PARAMETER = 0x40;

        public const byte DFU_CODE_API_INVALID_BUFFER_SIZE = 0x41;

        public const byte DFU_CODE_API_INVALID_HEX_RECORD = 0x42;

        public const byte DFU_CODE_API_NOT_IN_DFU_IDLE_STATE = 0x43;

        public const byte DFU_CODE_API_DNLOAD_PHASE_FAILED = 0x44;

        public const byte DFU_CODE_API_MANIFEST_PHASE_FAILED = 0x45;

        public const byte DFU_CODE_API_INVALID_IMAGE_FILE = 0x46;

        public const byte DFU_CODE_API_IMAGE_GENERATION_FAILED = 0x47;

        public const byte DFU_CODE_API_INVALID_DEVICE_OBJECT = 0x48;

        public const byte DFU_CODE_API_FATAL_ERROR = 0x49;

        public const byte DFU_CODE_API_ABORTED = 0x4a;

        public const byte DFU_CODE_API_NOT_SUPPORTED = 0x4b;

        /////////////////////////////////////////////////////////////////////////////
        // Definitions - byte : Hardware Interface Errors
        /////////////////////////////////////////////////////////////////////////////

        public const byte DFU_CODE_HWIF_DEVICE_NOT_FOUND = 0x80;

        public const byte DFU_CODE_HWIF_DEVICE_NOT_OPENED = 0x81;

        public const byte DFU_CODE_HWIF_DEVICE_ERROR = 0x82;

        public const byte DFU_CODE_HWIF_TRANSFER_ERROR = 0x83;

        public const byte DFU_CODE_HWIF_TRANSFER_TIMEOUT = 0x84;

        public const byte DFU_CODE_HWIF_TRANSFER_INCOMPLETE = 0x85;

        /////////////////////////////////////////////////////////////////////////////
        // Type Definitions - DFU_STATUS
        /////////////////////////////////////////////////////////////////////////////

        /////////////////////////////////////////////////////////////////////////////
        // Definitions - byte : Status Values
        /////////////////////////////////////////////////////////////////////////////

        public const byte DFU_STATUS_OK = 0x00;

        public const byte DFU_STATUS_ERR_TARGET = 0x01;

        public const byte DFU_STATUS_ERR_FILE = 0x02;

        public const byte DFU_STATUS_ERR_WRITE = 0x03;

        public const byte DFU_STATUS_ERR_ERASE = 0x04;

        public const byte DFU_STATUS_ERR_CHECK_ERASED = 0x05;

        public const byte DFU_STATUS_ERR_PROG = 0x06;

        public const byte DFU_STATUS_ERR_VERIFY = 0x07;

        public const byte DFU_STATUS_ERR_ADDRESS = 0x08;

        public const byte DFU_STATUS_ERR_NOT_DONE = 0x09;

        public const byte DFU_STATUS_ERR_FIRMWARE = 0x0A;

        public const byte DFU_STATUS_ERR_VENDOR = 0x0B;

        public const byte DFU_STATUS_ERR_USBR = 0x0C;

        public const byte DFU_STATUS_ERR_POR = 0x0D;

        public const byte DFU_STATUS_ERR_UNKNOWN = 0x0E;

        public const byte DFU_STATUS_ERR_STALLED_PKT = 0x0F;

        /////////////////////////////////////////////////////////////////////////////
        // Type Definitions - DFU_INTERFACE
        /////////////////////////////////////////////////////////////////////////////

        /////////////////////////////////////////////////////////////////////////////
        // Definitions - byte : Interface Types
        /////////////////////////////////////////////////////////////////////////////

        public const int DFU_INTERFACE_USB = 0;

        public const int DFU_INTERFACE_UART = 1;

        /////////////////////////////////////////////////////////////////////////////
        // Type Definitions - DFU_DATA_BITS
        /////////////////////////////////////////////////////////////////////////////

        /////////////////////////////////////////////////////////////////////////////
        // Definitions - DFU_DATA_BITS
        /////////////////////////////////////////////////////////////////////////////

        public const int DFU_FIVE_DATA_BITS = 5;
        public const int DFU_SIX_DATA_BITS = 6;
        public const int DFU_SEVEN_DATA_BITS = 7;
        public const int DFU_EIGHT_DATA_BITS = 8;

        /////////////////////////////////////////////////////////////////////////////
        // Type Definitions - DFU_PARITY
        /////////////////////////////////////////////////////////////////////////////

        /////////////////////////////////////////////////////////////////////////////
        // Definitions - DFU_PARITY
        /////////////////////////////////////////////////////////////////////////////

        public const int DFU_NO_PARITY = 0;
        public const int DFU_ODD_PARITY = 1;
        public const int DFU_EVEN_PARITY = 2;
        public const int DFU_MARK_PARITY = 3;
        public const int DFU_SPACE_PARITY = 4;

        /////////////////////////////////////////////////////////////////////////////
        // Type Definitions - DFU_STOP_BITS
        /////////////////////////////////////////////////////////////////////////////

        /////////////////////////////////////////////////////////////////////////////
        // Definitions - DFU_STOP_BITS
        /////////////////////////////////////////////////////////////////////////////

        public const int DFU_ONE_STOP_BIT = 0;
        public const int DFU_ONE5_STOP_BITS = 1;
        public const int DFU_TWO_STOP_BITS = 2;

        /////////////////////////////////////////////////////////////////////////////
        // Type Definitions - DFU_FLOW_CONTROL
        /////////////////////////////////////////////////////////////////////////////

        /////////////////////////////////////////////////////////////////////////////
        // Definitions - DFU_FLOW_CONTROL
        /////////////////////////////////////////////////////////////////////////////

        public const int DFU_NO_FLOW_CONTROL = 0;
        public const int DFU_RTS_CTS_FLOW_CONTROL = 1;

        /////////////////////////////////////////////////////////////////////////////
        // Type Definitions - DFU_STATE
        /////////////////////////////////////////////////////////////////////////////

        /////////////////////////////////////////////////////////////////////////////
        // Definitions - byte : State Values
        /////////////////////////////////////////////////////////////////////////////

        public const int DFU_STATE_APP_IDLE = 0;

        public const int DFU_STATE_APP_DETACH = 1;

        public const int DFU_STATE_DFU_IDLE = 2;

        public const int DFU_STATE_DFU_DNLOAD_SYNC = 3;

        public const int DFU_STATE_DFU_DNBUSY = 4;

        public const int DFU_STATE_DFU_DNLOAD_IDLE = 5;

        public const int DFU_STATE_DFU_MANIFEST_SYNC = 6;

        public const int DFU_STATE_DFU_MANIFEST = 7;

        public const int DFU_STATE_DFU_MANIFEST_WAIT_RESET = 8;

        public const int DFU_STATE_DFU_UPLOAD_IDLE = 9;

        public const int DFU_STATE_DFU_ERROR = 10;

        /////////////////////////////////////////////////////////////////////////////
        // String Definitions
        /////////////////////////////////////////////////////////////////////////////

        /////////////////////////////////////////////////////////////////////////////
        // Type Definitions
        /////////////////////////////////////////////////////////////////////////////

        // USB device

        public delegate bool DFU_PROGRESS_CALLBACK(int percent, bool workInProgress, int blockID, IntPtr userData);

        /////////////////////////////////////////////////////////////////////////////
        // Structures
        /////////////////////////////////////////////////////////////////////////////

        [StructLayout(LayoutKind.Sequential)]
        public class DFU_CONTROL_SETUP_PACKET
        {
            public byte RequestType;
            public byte Request;
            public ushort Value;
            public ushort Index;
            public ushort Length;

        }

        [StructLayout(LayoutKind.Sequential)]
        public class DFU_GET_STATUS
        {

            public byte bStatus;

            public uint bwPollTimeout;

            public byte bState;

            public byte iString;

        }

        [StructLayout(LayoutKind.Sequential)]
        public class DFU_GET_INFO
        {

            public ushort length;

            public byte bBootloaderRevision_Major;
            public byte bBootloaderRevision_Minor;

            public uint bmAttributes;

            public uint wBlockSize;

            public uint maxAppSize;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst=16)]
            public byte[] bDeviceID;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst=16)]
            public byte[] bUUID;

        }

        [StructLayout(LayoutKind.Sequential)]
        public class DFU_DEVICE_DESCRIPTOR
        {
            public byte bLength;
            public byte bDescriptorType;
            public ushort bcdUSB;
            public byte bDeviceClass;
            public byte bDeviceSubClass;
            public byte bDeviceProtocol;
            public byte bMaxPacketSize0;
            public ushort idVendor;
            public ushort idProduct;
            public ushort bcdDevice;
            public byte iManufacturer;
            public byte iProduct;
            public byte iSerialNumber;
            public byte bNumConfigurations;

        }

        [StructLayout(LayoutKind.Sequential)]
        public class DFU_INTERFACE_DESCRIPTOR
        {
            public byte bLength;
            public byte bDescriptorType;
            public byte bInterfaceNumber;
            public byte bAlternateSetting;
            public byte bNumEndpoints;
            public byte bInterfaceClass;
            public byte bInterfaceSubClass;
            public byte bInterfaceProtocol;
            public byte iInterface;

        }

        [StructLayout(LayoutKind.Sequential)]
        public class DFU_FUNCTIONAL_DESCRIPTOR
        {
            public byte bLength;
            public byte bDescriptorType;
            public byte bmAttributes;
            public ushort wDetachTimeOut;
            public ushort wTransferSize;
            public ushort bcdDFUVersion;

        }

        /////////////////////////////////////////////////////////////////////////////
        // Exported Library Functions
        /////////////////////////////////////////////////////////////////////////////

        /////////////////////////////////////////////////////////////////////////////
        // Device Management
        /////////////////////////////////////////////////////////////////////////////

        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_GetGuid(ref Guid guid);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_SetGuid(ref Guid guid);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_GetNumDevices(ref uint numDevices);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_GetDevicePath(uint deviceIndex, StringBuilder path);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_GetVidPid(uint deviceIndex, ref ushort vid, ref ushort pid);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_GetInterfaceByIndex(uint deviceIndex, ref byte type);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_GetInterfaceByDevicePath(string path, ref byte type);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_GetOpenedDevicePath(IntPtr device, StringBuilder path);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_GetOpenedVidPid(IntPtr device, ref ushort vid, ref ushort pid);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_GetOpenedInterface(IntPtr device, ref byte type);

        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_OpenByIndex(ref IntPtr device, uint deviceIndex);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_OpenByDevicePath(ref IntPtr device, string path);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_Close(IntPtr device);
        [DllImport("SLAB_DFU.dll")]
        public static extern bool DFU_IsOpened(IntPtr device);

        /////////////////////////////////////////////////////////////////////////////
        // Information
        /////////////////////////////////////////////////////////////////////////////

        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_GetLibraryVersion(ref byte major, ref byte minor, ref bool release);

        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_GetDeviceDescriptor(IntPtr device, [In, Out] DFU_DEVICE_DESCRIPTOR descriptor);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_GetInterfaceDescriptor(IntPtr device, [In, Out] DFU_INTERFACE_DESCRIPTOR descriptor);

        /////////////////////////////////////////////////////////////////////////////
        // Control Transfers
        /////////////////////////////////////////////////////////////////////////////

        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_ControlTransfer(IntPtr device, DFU_CONTROL_SETUP_PACKET setup, byte[] buffer, uint size, ref uint bytesTransferred);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_SetTransferTimeout(IntPtr device, uint timeout);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_GetTransferTimeout(IntPtr device, ref uint timeout);

        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_SetUartConfig(IntPtr device, uint baud, byte dataBits, byte parity, byte stopBits, byte flowControl);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_GetUartConfig(IntPtr device, ref uint baud, ref byte dataBits, ref byte parity, ref byte stopBits, ref byte flowControl);

        /////////////////////////////////////////////////////////////////////////////
        // DFU Mode
        /////////////////////////////////////////////////////////////////////////////

        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_DfuDnload(IntPtr device, byte[] buffer, ushort size, ushort block, ref ushort transferred);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_DfuUpload(IntPtr device, byte[] buffer, ushort size, ushort block, ref ushort transferred);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_DfuGetStatus(IntPtr device, [In, Out] DFU_GET_STATUS status);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_DfuClearStatus(IntPtr device);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_DfuGetState(IntPtr device, ref byte state);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_DfuAbort(IntPtr device);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_SlabGetInfo(IntPtr device, [In, Out] DFU_GET_INFO info);

        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_DownloadImage(IntPtr device, ushort blockSize, string fileName, DFU_PROGRESS_CALLBACK callback, IntPtr userData, [In, Out] DFU_GET_STATUS status);
        [DllImport("SLAB_DFU.dll")]
        public static extern byte DFU_UploadImage(IntPtr device, ushort blockSize, string fileName, DFU_PROGRESS_CALLBACK callback, IntPtr userData);
    }
}
