【发布时间】:2016-08-10 17:50:46
【问题描述】:
我对 SerialPort 进行了一些尝试(令人沮丧),最终达到了我完全不知道为什么这不起作用的地步。我正在尝试向 USB CDC 设备发送十六进制命令,我这样做的方式是通过它公开的 COM 端口接口。我可以与设备握手,当我说 HI 时,它会回复 HI,但随后我向它发送另一个命令,该命令后面必须跟一个零字节数据包,否则设备将完全停止响应。请记住,这个零字节数据包中绝对没有任何内容,这意味着它没有 \0 或 0x00 或 0 甚至是 null(SerialPort 在 null 上抛出异常)。
现在,我能够规避这种情况的一种方法是使用 libusbdotnet。我直接访问 CDC 设备而不是 COM 接口,正确设置端点并发送类似的十六进制命令。我可以使用以下 c# 代码使用此方法成功发送“0 字节”数据包:
string zlpstring = "";
byte[] zlpbyte = Encoding.Default.GetBytes(zlpstring);
....snip
ecWrite = writer.SubmitAsyncTransfer(zlpbyte, 0, zlpbyte.Length, 100, out usbWriteTransfer);
zlpbyte 是缓冲区,0 是偏移量,zlpbyte.Length 是数据包长度,以字节为单位,100 是超时时间,out usbWriteTransfer 是传输上下文。
当我在 COM 端口上使用相同的方法时:
string zlpstring = "";
byte[] zlpbyte = Encoding.Default.GetBytes(zlpstring);
_serialPort.Write(zlpbyte, 0, zlpbyte.Length);
USB 记录器报告绝对没有发送任何内容。就好像 COM 端口忽略了零字节传输。在提到“你不能这样做”之前,有各种程序可以在不进行任何驱动程序操作的情况下将零字节数据包发送到该设备的 COM 端口。这就是我想要的,这就是为什么我试图放弃 libusbdotnet 并直接使用 COM 端口。
编辑:
经过更多的玩弄和不同的 USB 记录器,我发现发送的不是零字节,而是这个:
IRP_MJ_DEVICE_CONTROL (IOCTL_SERIAL_WAIT_ON_MASK)
我认为这可能是问题所在。如果发送的是 0 字节,那么我认为它会显示为:
IRP_MJ_WRITE > UP > STATUS_SUCCESS >(空白)>(空白)
我的程序正在发回 01 00 00 00 的响应,但是在记录另一个成功的程序时它正在设置等待掩码:
IRP_MJ_DEVICE_CONTROL (IOCTL_SERIAL_SET_WAIT_MASK) DOWN STATUS_SUCCESS 01 00 00 00
如果我的假设是正确的,那么这个问题可能已经变成了如何设置串行端口/COM 端口的等待掩码?在 c# SerialPort 类中绝对没有这方面的内容......这就是为什么我现在可以明白为什么这么多文章称它为“缺乏”的原因。我还浏览了 c++:https://msdn.microsoft.com/en-us/library/aa363214(v=vs.85).aspx 这似乎也没有涵盖等待掩码。使用 USB 过滤器 libusb 开始每分钟看起来都更令人愉悦...(尽管我会永远质疑自己为什么在那里发送零字节有效,但它不能通过 SerialPort)。
第二次编辑:
我是个白痴。这绝对是制造商可能没有想到任何人会触摸也不知道如何设置的设置:
#define EV_RXFLAG 0x0001
SetCommMask(hSerial, EV_RXFLAG);
然后我通过 USB 日志看到了这一点:
IRP_MJ_DEVICE_CONTROL (IOCTL_SERIAL_SET_WAIT_MASK) DOWN STATUS_SUCCESS 01 00 00 00
宾果游戏。 RXFLAG 最初设置为 0x0002。我还没有找到在 C# 中改变它的方法。所以我现在不得不处理一些 C++ 代码。它完全有效,并像它应该发送的那样发送“零字节”,而我实际上没有从代码中发送它。我假设这个设置是我的设备和它在 Flash 模式下与之交互的任何其他东西之间的“握手”方法。希望这可以帮助那些 COM/串行设备拒绝/丢弃零字节数据包但同时需要 ZLP 的其他人......多么愚蠢?!
【问题讨论】:
-
为什么使用默认编码?默认使用 ASCII 过滤不可打印的字符,如 \0。尝试 UTF8 编码。
-
创建 byte[] zlpbyte = new byte[0];并发送 zlpbyte?
-
感谢jdweng 和Mong Zhu 的回复。如果我将编码更改为 UTF8,它会将字符视为完全相同(这令人困惑......)。使用 Encoding.UTF8.GetBytes(zlpstring) 编译后,绝对没有任何变化。 “byte[] zlpbyte = new byte[0];”也会发生同样的事情就像其他任何不具有 1 或更多字节长度的东西......端口只是丢弃它并且它永远不会出现在 USB 记录器中。
标签: c#