您的位置:首页 > 编程语言 > C#

C#开发usb通知之bulk传输

2015-11-24 11:13 459 查看
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);//如果线程休眠的话,导致接受的数据不完整....
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: