USB HID读数据问题,如何知道下位机发送了数据,然后读出相应的数据?

gzwuyh 2018-01-25 04:00:33
如果PC软件写入指令,然后读出数据正常。但PC不送指令,下位机在其它时候发送了数据,如何读出?

即PC写入指令,上位机接收到指令后会返回数据给PC,此时PC能正常接收到上位机发送的数据。

但,过一段时间后,上位机发送其它新数据给PC(发送时间不定),此时PC如何知道上位机发送了数据,然后去接收?

我试过定时多少ms不停的去读数据,但这样不能正常读到发送的数据?

上位机有数据发送到PC,是否有什么状态发生,然后去通知PC读数据?

用Bus Hound或其它工具能正常抓到上位机发送的数据。

PC软件如何才能正常合理接收数据?


...全文
2455 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
gzwuyh 2018-02-01
  • 打赏
  • 举报
回复
引用 15 楼 vc_dreamver 的回复:
@wyhkgd 可不可以修改一下通讯协议。 首先,PC先发查询指令,查询有没有数据准备上报,下位机应答,返回是否有上报数据,及具体数据长度。 第二步再由PC读取,下位机上传。 一般与硬件通讯,我尽可能在一个线程里实现读取与写入,因为接口不一定是线程安全的。
如果只是PC发指令接收,已可以了,但在PC不发指令的情况下,要接收从下位机上传来的数据。 用Bus Hound,PortHelper或其它USB工具都可以看到下位机上传的数据的,肯定是有方法,只是我不知道而已。
vc_dreamver 2018-01-31
  • 打赏
  • 举报
回复
@ooolinux 如果用ReadFile应该可以实现异步读取,与串口类似吧,加回调事件。 不过我觉得这样不如修改一下通讯协议更简单省事。
vc_dreamver 2018-01-31
  • 打赏
  • 举报
回复
@wyhkgd 可不可以修改一下通讯协议。 首先,PC先发查询指令,查询有没有数据准备上报,下位机应答,返回是否有上报数据,及具体数据长度。 第二步再由PC读取,下位机上传。 一般与硬件通讯,我尽可能在一个线程里实现读取与写入,因为接口不一定是线程安全的。
gzwuyh 2018-01-31
  • 打赏
  • 举报
回复
引用 12 楼 vc_dreamver 的回复:
USB Slave 是被动响应的,通讯都先要由USB Host 发起,也就是要先读。如果在线程中读取USB数据,如果下位机数据没有准备好,并且没有使用异步读取,则会阻塞,当下位机有数据时返回。
就是子线程开了异步一下读?主线程如何写入指令呢? 一般怎么处理好一些? 1.正常发送指令,接收数据? 2.如何在不发送指令情况下,检测有上位机数据到PC?
ooolinux 2018-01-31
  • 打赏
  • 举报
回复
@vc_dreamver 可以使用异步读取吗,有没有数据读取函数都返回的?
vc_dreamver 2018-01-31
  • 打赏
  • 举报
回复
USB Slave 是被动响应的,通讯都先要由USB Host 发起,也就是要先读。如果在线程中读取USB数据,如果下位机数据没有准备好,并且没有使用异步读取,则会阻塞,当下位机有数据时返回。
ooolinux 2018-01-29
  • 打赏
  • 举报
回复
你的代码我看不懂,写的时候应该是在某个窗体单元,比如某个ButtonClick里。 开一个子线程,在线程循环中读取。 线程循环中读取的时候,用Sleep主动让出一些CPU。读、写FileStream用CriticalSection来控制,避免冲突。
gzwuyh 2018-01-28
  • 打赏
  • 举报
回复
引用 9 楼 u010165006 的回复:
下发指令时可否停止异步读的线程,下发命令后,再重新打开读? ———— 可以挂起线程,下发后,再继续线程。 你说device.FileStreamDeviceData.BeginRead会一直等待有数据才返回,看看有没有一个成员函数用来判断是否有数据,有数据才读。
没有,如果有,我就会定时查找有数据,然后再读就行了。 1.不开线程情况 下,调用读写,能正常发出指令,且收到数据。

this.MyDeviceManagement.WriteReportToDevice(0, outdatas);
this.MyDeviceManagement.ReadReportFromDevice(0, ref inputdatas, 100);


private byte[] ReadAndWriteToDevice()
        {
            byte[] outdatas = new byte[16];
            outdatas[0] = 0x55;
            outdatas[1] = 0x2;
            outdatas[2] = 0x1;
            outdatas[3] = 0x00;
            byte[] inputdatas = new byte[192];
            byte[] inputs = new byte[8];
            inputs[0] = 0xa1;
            if (inputs != null && inputs.Length > 0)
            {
                outdatas = inputs;
            }
            //this.txtBytesReceived.Clear();
            Application.DoEvents();
            this.MyDeviceManagement.WriteReportToDevice(0, outdatas);
            this.MyDeviceManagement.ReadReportFromDevice(0, ref inputdatas, 100);
            //MyDeviceManagement.ReadReportFromDevice1();
            Application.DoEvents();
            return inputdatas;
        }
2.开了线程,写之前加入取消读属性,然后再调用第1步的写,读,程序会停在读的位置

   private void button2_Click(object sender, EventArgs e)
        {
            if (t1.ThreadState == ThreadState.Running)
            {
                MyDeviceManagement.CancelRead = true;
                while (true)
                {
                    System.Threading.Thread.Sleep(5);
                    if (t1.ThreadState == ThreadState.Stopped)
                    {
                        break;
                    }
                }
            }
            MyDeviceManagement.CancelRead = false;
            this.ReadAndWriteToDevice();
            t1 = new Thread(MyDeviceManagement.ReadReportFromDevice1);
            t1.Start();
        }



这是子线程中判断如果取消了,则中断线程


while (true)
                                    {
                                        if (_cancelRead == true)
                                        {
                                            System.Threading.Thread.CurrentThread.Abort();
                                        }                                                                                
                                        if (this._isStop)
                                            break;
                                        if (!_transferInProgress)
                                        {
                                            break;
                                        }
                                        System.Threading.Thread.Sleep(5);
                                    }
不知道为什么调用Write后,不调用Read,指令出不去?
ooolinux 2018-01-28
  • 打赏
  • 举报
回复
下发指令时可否停止异步读的线程,下发命令后,再重新打开读? ———— 可以挂起线程,下发后,再继续线程。 你说device.FileStreamDeviceData.BeginRead会一直等待有数据才返回,看看有没有一个成员函数用来判断是否有数据,有数据才读。
gzwuyh 2018-01-28
  • 打赏
  • 举报
回复
现在的问题是开子线程调用异步读后: device.FileStreamDeviceData.BeginRead(inputReportBuffer, 0, inputReportBuffer.Length, new AsyncCallback(GetInputReportData), inputReportBuffer); 子线程一直在待命状态,等待有数据来,然后处理读数据。 此时调用write()后不能调用read或BeginRead,指令不能下发? 其实调用异步读时,他本身就有另一个线程的。 下发指令时可否停止异步读的线程,下发命令后,再重新打开读?
gzwuyh 2018-01-28
  • 打赏
  • 举报
回复
USB HID不熟悉,所以用的C#写的读取USB HID设备的测试软件 http://download.csdn.net/download/haiguozhe/8908701#comment改的。





public class DeviceInformation
    {
        public Boolean DeviceIsDetected;
        public String myDevicePathName;
        public HIDD_ATTRIBUTES DeviceAttributes;
        public HIDP_CAPS Capabilities;
        public IntPtr DeviceNotificationHandle;
        public int NumberOfInputBuffers;
        public Boolean ExclusiveAccess;
        public FileStream FileStreamDeviceData;
        public SafeFileHandle HidHandle;
        public String HidUsage;
    }

 private void ReOpenDeviceFileStreamHandler(DeviceInformation findDevice)
        {
            //关闭句柄并用读/写模式重新打开
            findDevice.HidHandle.Close();
            findDevice.HidHandle = FileIO.CreateFile(findDevice.myDevicePathName, FileIO.GENERIC_READ | FileIO.GENERIC_WRITE, FileIO.FILE_SHARE_READ | FileIO.FILE_SHARE_WRITE, IntPtr.Zero, FileIO.OPEN_EXISTING, 0, 0);
            Debug.WriteLine("在函数ReOpenDeviceFileStreamHandler中" + this.MyDebugging.ResultOfAPICall("CreateFile"));

            if (findDevice.HidHandle.IsInvalid)
            {
                findDevice.ExclusiveAccess = true;
                Debug.WriteLine("此设备是一个系统" + findDevice.HidUsage + "." + "对于此设备,Windows 2000 和 Windows XP 才能使用 Input 和 Output reports功能.");
            }
            else
            {
                if (findDevice.Capabilities.InputReportByteLength > 0)
                {
                    //  Set the size of the Input report buffer. 
                    Byte[] inputReportBuffer = null;

                    inputReportBuffer = new Byte[findDevice.Capabilities.InputReportByteLength];
                    findDevice.FileStreamDeviceData = new FileStream(findDevice.HidHandle, FileAccess.Read | FileAccess.Write, inputReportBuffer.Length, false);
                }

                //  Flush any waiting reports in the input buffer. (optional)
                _hidObject.FlushQueue(findDevice.HidHandle);
            }
        }
写数据:


if (device.FileStreamDeviceData.CanWrite)
                                {
                                    device.FileStreamDeviceData.Write(outputReportBuffer, 0, outputReportBuffer.Length);                                                                                                            
                                    success = true;
                                }
读数据:

 ar=device.FileStreamDeviceData.BeginRead(inputReportBuffer, 0, inputReportBuffer.Length, new AsyncCallback(GetInputReportData), inputReportBuffer);
如果现在单调用写指令,然后调用读指令,能正常送出指令和接收返回的指令,但如果不送指令,就收不到下位机的数据。 如果用子线程循环调用读,能正常读出下位机发出的所有数据,但又不能送出指令。
ooolinux 2018-01-28
  • 打赏
  • 举报
回复
线程循环中读取的时候,用Sleep让出一些CPU,两个cpp读、写FileStream用CriticalSection来控制,避免冲突。
ooolinux 2018-01-28
  • 打赏
  • 举报
回复
Read没有数据可读时不会返回吗?为什么是FileStream.Read,操作对象为什么是FileStream?
gzwuyh 2018-01-28
  • 打赏
  • 举报
回复
引用 3 楼 u010165006 的回复:
开个线程一直读吧,循环中Sleep(1)一下可以降低CPU占有率。
开线程一直读是能读到下位机发送的数据,但是,PC发不出指令了。 原来的方法是: 1.用FileStream.Write()写数据。 2.用FileStream.BeginRead或FileStream.Read读数据 即要调用读后,写的数据才实际写到下拉机。 即只调用FileStream.Write(),在Bus Hound看不到有数据输出,当调用Read后,Bus Hound有输出数据,和返回的数据了 但问题是子线程一直在调用FileStream.Read读数据,所以现在程序执行到Read后一直停在那里,不下去了。
ooolinux 2018-01-28
  • 打赏
  • 举报
回复
开个线程一直读吧,循环中Sleep(1)一下可以降低CPU占有率。
gzwuyh 2018-01-28
  • 打赏
  • 举报
回复
引用 1 楼 chinayu2007 的回复:
和读串口差不多,首先你要找到设备名,有了设备名就可以象打开文件一样操作了.
PC发送一条指令后,能正常收到下位机上传的数据。 写用:FileStream.wirte() 读用:BeginRead() 但在PC不发送指令的情况下,下位机上传数据到PC?不知道何时去读,一直循环去读?
chinayu2007 2018-01-27
  • 打赏
  • 举报
回复
和读串口差不多,首先你要找到设备名,有了设备名就可以象打开文件一样操作了.

1,221

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧