C#開發usb通知之bulk傳輸


usb通信分為4種傳輸方式,下位機通信協議用的是塊傳輸,也就是bulk傳輸,C#下實現的usb通信使用的是開源的LibUsbDotNet,主要的就是需要在C#中添加LibUsbDotNet.dll引用文件,安裝后的LibUsbDotNet里面有

我是參考bulk傳輸實例,這個需要libusb-1.0.dll文件放在程序的根目錄下或者在windows/system32/目錄下,否則會報錯,提示找不到這個文件:

using System;
using System.Runtime.InteropServices;
using MonoLibUsb.Transfer;
using Usb = MonoLibUsb.MonoUsbApi;

namespace MonoLibUsb.ShowInfo
{
    internal enum TestMode
    {
        Sync,
        Async
    }

    internal class BulkReadWrite
    {
        #region DEVICE SETUP
        private const int MY_CONFIG = 1;
        private const byte MY_EP_READ = 0x81;//讀端點口地址
        private const byte MY_EP_WRITE = 0x01;//寫端點口地址
        private const int MY_INTERFACE = 0;//接口地址
        private const short MY_PID = 0x0053;//設備的VID PID信息
        private const short MY_VID = 0x04d8;
        #endregion

        #region TEST SETUP
        private const int MY_TIMEOUT = 2000;//讀寫超時時間
        private const int TEST_LOOP_COUNT = 1;

        private const int TEST_READ_LEN = 64;

        private const bool TEST_REST_DEVICE = true;
        private const int TEST_WRITE_LEN = 8;

        private static TestMode TEST_MODE = TestMode.Async;
        #endregion

        private static MonoUsbSessionHandle sessionHandle  = null;

        private static void fillTestData(byte[] data, int len)
        {
            int i;
            for (i = 0; i < len; i++)
                data[i] = (byte) (65 + (i & 0xf));
        }

        private static void memset(byte[] data, int value, int len)
        {
            int i;
            for (i = 0; i < len; i++)
                data[i] = (byte) (value);
        }

        // This function originated from bulk_transfer_cb()
        // in sync.c of the Libusb-1.0 source code.
        private static void bulkTransferCB(MonoUsbTransfer transfer)
        {
            Marshal.WriteInt32(transfer.PtrUserData, 1);
            /* caller interprets results and frees transfer */
        }

        // This function originated from do_sync_bulk_transfer()
        // in sync.c of the Libusb-1.0 source code.
        private static MonoUsbError doBulkAsyncTransfer(MonoUsbDeviceHandle dev_handle,
                                                          byte endpoint,
                                                          byte[] buffer,
                                                          int length,
                                                          out int transferred,
                                                          int timeout)
        {
            transferred = 0;
            MonoUsbTransfer transfer = new MonoUsbTransfer(0);
            if (transfer.IsInvalid) return MonoUsbError.ErrorNoMem;

            MonoUsbTransferDelegate monoUsbTransferCallbackDelegate = bulkTransferCB;
            int[] userCompleted = new int[] {0};
            GCHandle gcUserCompleted = GCHandle.Alloc(userCompleted, GCHandleType.Pinned);

            MonoUsbError e;
            GCHandle gcBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned);
            transfer.FillBulk(
                dev_handle,
                endpoint,
                gcBuffer.AddrOfPinnedObject(),
                length,
                monoUsbTransferCallbackDelegate,
                gcUserCompleted.AddrOfPinnedObject(),
                timeout);

            e = transfer.Submit();
            if ((int) e < 0)
            {
                transfer.Free();
                gcUserCompleted.Free();
                return e;
            }
            int r;
            Console.WriteLine("Transfer Submitted..");
            while (userCompleted[0] == 0)
            {
                e = (MonoUsbError) (r = Usb.HandleEvents(sessionHandle));
                if (r < 0)
                {
                    if (e == MonoUsbError.ErrorInterrupted)
                        continue;
                    transfer.Cancel();
                    while (userCompleted[0] == 0)
                        if (Usb.HandleEvents(sessionHandle) < 0)
                            break;
                    transfer.Free();
                    gcUserCompleted.Free();
                    return e;
                }
            }

            transferred = transfer.ActualLength;
            e = MonoUsbApi.MonoLibUsbErrorFromTransferStatus(transfer.Status);
            transfer.Free();
            gcUserCompleted.Free();
            return e;
        }

        public static int Main(string[] args)
        {
            MonoUsbDeviceHandle device_handle = null;

            int r = 0;
            int transferred;
            byte[] testWriteData = new byte[TEST_WRITE_LEN];
            byte[] testReadData = new byte[TEST_READ_LEN];

            if (args.Length > 0)
            {
                switch (args[0].ToLower())
                {
                    case "sync":
                        TEST_MODE = TestMode.Sync;
                        break;
                    case "async":
                        TEST_MODE = TestMode.Async;
                        break;
                }
            }

            fillTestData(testWriteData, TEST_WRITE_LEN);
            memset(testReadData, 0, TEST_READ_LEN);

            int loopCount = 0;
            do
            {
                try
                {
                    do
                    {
                        sessionHandle=new MonoUsbSessionHandle();
                        if (sessionHandle.IsInvalid) throw new Exception("Invalid session handle.");

                        Console.WriteLine("Opening Device..");
                        device_handle = MonoUsbApi.OpenDeviceWithVidPid(sessionHandle, MY_VID, MY_PID);
                        if ((device_handle == null) || device_handle.IsInvalid) break;

                        // If TEST_REST_DEVICE = True, reset the device and re-open
                        if (TEST_REST_DEVICE)
                        {
                            MonoUsbApi.ResetDevice(device_handle);
                            device_handle.Close();
                            device_handle = MonoUsbApi.OpenDeviceWithVidPid(sessionHandle, MY_VID, MY_PID);
                            if ((device_handle == null) || device_handle.IsInvalid) break;
                        }

                        // Set configuration
                        Console.WriteLine("Set Config..");
                        r = MonoUsbApi.SetConfiguration(device_handle, MY_CONFIG);
                        if (r != 0) break;

                        // Claim interface
                        Console.WriteLine("Set Interface..");
                        r = MonoUsbApi.ClaimInterface(device_handle, MY_INTERFACE);
                        if (r != 0) break;

                        /////////////////////
                        // Write test data //
                        /////////////////////
                        int packetCount = 0;
                        int transferredTotal = 0;
                        do
                        {
                            Console.WriteLine("Sending test data..");

                            // If the Async TEST_MODE enumeration is set, use
                            // the internal transfer function
                            if (TEST_MODE == TestMode.Async)
                            {
                                r = (int)doBulkAsyncTransfer(device_handle,
                                                                MY_EP_WRITE,
                                                                testWriteData,
                                                                TEST_WRITE_LEN,
                                                                out transferred,
                                                                MY_TIMEOUT);
                            }
                            else
                            {
                                // Use the sync bulk transfer API function 
                                r = MonoUsbApi.BulkTransfer(device_handle,
                                                                       MY_EP_WRITE,
                                                                       testWriteData,
                                                                       TEST_WRITE_LEN,
                                                                       out transferred,
                                                                       MY_TIMEOUT);
                            }
                            if (r == 0)
                            {
                                packetCount++;
                                transferredTotal += transferred;
                            }
                            // Keep writing data until an error occurs or
                            // 4 packets have been sent.
                        } while (r == 0 && packetCount < 5);


                        if (r == (int) MonoUsbError.ErrorTimeout)
                        {
                            // This is considered normal operation
                            Console.WriteLine("Write Timed Out. {0} packet(s) written ({1} bytes)", packetCount, transferredTotal);
                        }
                        else if (r != (int) MonoUsbError.ErrorTimeout && r != 0)
                        {
                            // An error, other than ErrorTimeout was received. 
                            Console.WriteLine("Write failed:{0}", (MonoUsbError) r);
                            break;
                        }
                        ////////////////////
                        // Read test data //
                        ////////////////////
                        Console.WriteLine("Reading test data..");
                        packetCount = 0;
                        transferredTotal = 0;
                        do
                        {
                            // If the Async TEST_MODE enumeration is set, use
                            // the internal transfer function
                            if (TEST_MODE == TestMode.Async)
                            {
                                r = (int) doBulkAsyncTransfer(device_handle,
                                                                MY_EP_READ,
                                                                testReadData,
                                                                TEST_READ_LEN,
                                                                out transferred,
                                                                MY_TIMEOUT);
                            }
                            else
                            {
                                // Use the sync bulk transfer API function 
                                r = MonoUsbApi.BulkTransfer(device_handle,
                                                                       MY_EP_READ,
                                                                       testReadData,
                                                                       TEST_READ_LEN,
                                                                       out transferred,
                                                                       MY_TIMEOUT);
                            }
                            if (r == (int) MonoUsbError.ErrorTimeout)
                            {
                                // This is considered normal operation
                                Console.WriteLine("Read Timed Out. {0} packet(s) read ({1} bytes)", packetCount, transferredTotal);
                            }
                            else if (r != 0)
                            {
                                // An error, other than ErrorTimeout was received. 
                                Console.WriteLine("Read failed:{0}", (MonoUsbError)r);
                            }
                            else
                            {
                                transferredTotal += transferred;
                                packetCount++;

                                // Display test data.
                                Console.Write("Received: ");
                                Console.WriteLine(System.Text.Encoding.Default.GetString(testReadData, 0, transferred));
                            }
                            // Keep reading data until an error occurs, (ErrorTimeout)
                        } while (r == 0);
                    } while (false);
                }
                finally
                {
                    // Free and close resources
                    if (device_handle != null)
                    {
                        if (!device_handle.IsInvalid)
                        {
                            MonoUsbApi.ReleaseInterface(device_handle, MY_INTERFACE);
                            device_handle.Close();
                        }
                    }
                    if (sessionHandle!=null)
                    {
                        sessionHandle.Close();
                        sessionHandle = null;
                    }
                }
                // Run the entire test TEST_LOOP_COUNT times.
            } while (++loopCount < TEST_LOOP_COUNT);

            Console.WriteLine("\nDone!  [Press any key to exit]");
            Console.ReadKey();

            return r;
        }
    }
}

我在winfrom的主要思路和上面差不多,但是還有有點區別的,畢竟控制端程序和桌面程序在代碼上還是有點區別的。由於項目的要求只能放部分代碼

1.設置相關的通信信息,和上面的差不多

        //設置設備信息,包括接口、斷點等信息 
        private void setDevice()
        {
            sessionHandle = new MonoUsbSessionHandle();
            if (sessionHandle.IsInvalid) throw new Exception("Invalid session handle.");
            //Console.WriteLine("Opening Device..");
            device_handle = MonoUsbApi.OpenDeviceWithVidPid(sessionHandle, MY_VID, MY_PID);
            if ((device_handle == null) || device_handle.IsInvalid)
            {
                Console.WriteLine("device_handle為空");
                isContinue = false;
                labelInfo.Text = "未找到設備";
                ScanBtn.Enabled = false;
            }
            else
            {
                //設置配置信息
                r = MonoUsbApi.SetConfiguration(device_handle, MY_CONFIG);
                if (r != 0) { Console.WriteLine("config出錯"); };
                // 索賠接口
                r = MonoUsbApi.ClaimInterface(device_handle, MY_INTERFACE);
                if (r != 0) { Console.WriteLine("interface出錯"); };
                labelInfo.Text = "成功打開設備";
            }
        }

2.然后在按鈕的監聽器里面實現發送命令的方法:

        private void sendCommand()
        {
            if (device_handle == null)
            {
                setDevice();
            }
            byte[] data = DataFix.getCommand(interTimes, scanCounts, manual);
            //r = (int)doBulkAsyncTransfer(device_handle, MY_EP_WRITE, command, command.Length, out transferred, MY_TIMEOUT);
            r = MonoUsbApi.BulkTransfer(device_handle, MY_EP_WRITE, data, data.Length, out transferred, MY_TIMEOUT);
            if (r == (int)MonoUsbError.ErrorTimeout)
            {
                // 寫入超時錯誤信息
                //Console.WriteLine("Write Timed Out. {0} packet(s) written ({1} bytes)", packetCount, transferredTotal);
            }
            else if (r != (int)MonoUsbError.ErrorTimeout && r != 0)
            {
                Console.WriteLine("Write failed:{0}", (MonoUsbError)r);
            }
            resultList.Clear();
        }

3.其實最終的就是第三點,你需要在程序啟動的時候就開啟一個新的線程,然后里面實現while(true)循環的監聽端點口數據的返回

#region 開啟一個新的線程
xferData = new Thread(DataGetFromPoint);
xferData.IsBackground = true;
xferData.Priority = ThreadPriority.Highest;
xferData.Start();
#endregion

DataGetFromPoint()方法

        public void DataGetFromPoint()
        {
            bufDataIn = new byte[inLength];
            while (isContinue)
            {
                //Console.WriteLine("Reading data....");
                r = MonoUsbApi.BulkTransfer(device_handle, MY_EP_READ, bufDataIn, inLength, out transferred, MY_TIMEOUT);
                if (r == (int)MonoUsbError.ErrorTimeout)
                {
                    //這個可以看出是一個正常的操作
                    //Console.WriteLine("Read Timed Out.");
                }
                else if (r != 0)
                {
                    //除了寫入超時錯誤的信息外,其他的信息會在這里顯示
                    Console.WriteLine("Read failed:{0}", (MonoUsbError)r);
                }
                else
                {
                    Console.writeln(DataFix.byteToHexString(bufDataIn));//字節數組轉換成16進制字符串顯示
                }
                //Thread.Sleep(1);//如果線程休眠的話,導致接受的數據不完整....
            }
        }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM