使用pywinusb读取HID设备数据时仅捕获单包的解决办法
解决pywinusb仅捕获单个USB数据包的问题
首先明确:USB设备通信没有波特率的概念,所以不用调整波特率,问题出在数据捕获的逻辑或配置上。针对你遇到的只抓到1个数据包的情况,按以下步骤排查解决:
1. 确保程序持续监听,不提前退出
原示例代码可能只做了短时间的监听(比如time.sleep(10)),如果设备在程序退出前发送了多个数据包,但程序提前终止,就会漏抓。修改成持续监听直到手动停止:
# 替换原示例中的等待逻辑,改成无限循环 print("监听中,按Ctrl+C停止...") while True: time.sleep(0.1) # 避免占用过高CPU
2. 确认监听的是正确的USB端点
设备可能有多个输入端点(比如中断端点、批量端点),如果代码监听的端点不对,自然收不到所有数据包。检查设备的端点配置(可通过设备管理器的USB属性查看),确保选择了正确的输入端点:
# 替换原示例中的端点查找逻辑,明确指定端点或遍历确认 # 比如找中断输入端点 in_ep = device.find_interrupt_in_ep() # 或者找批量输入端点(如果设备用批量传输) # in_ep = device.find_bulk_in_ep()
3. 检查回调函数的响应能力
如果回调函数里有耗时操作(比如复杂计算、IO写入),会阻塞USB数据接收线程,导致后续数据包无法及时触发回调。回调函数要尽量轻量化,只做数据接收和缓存:
# 示例轻量化回调,把数据缓存到全局列表 received_packets = [] def raw_data_handler(data): global received_packets received_packets.append(data) print(f"收到第{len(received_packets)}个数据包: {data}")
4. 验证设备的数据包传输模式
有些设备会连续发送多个数据包,但pywinusb的回调是每个数据包触发一次,所以要确认回调是否被多次触发。可以在回调里加计数打印,看是否只触发了一次——如果是,说明设备可能只发了一个包(可能是你对设备发送逻辑的判断有误);如果触发多次但没拿到数据,检查端点缓冲区设置。
5. 调整端点缓冲区大小(可选)
如果设备发送的数据包较大或连续发送速度快,默认的端点缓冲区可能不够,导致数据丢失。可以尝试设置更大的缓冲区:
# 设置端点缓冲区大小,比如64字节(根据设备实际需求调整) if in_ep: in_ep.set_buffer_size(64) in_ep.set_raw_data_handler(raw_data_handler)
完整修改后的示例代码
import pywinusb.hid as hid import time received_packets = [] def raw_data_handler(data): global received_packets received_packets.append(data) print(f"收到第{len(received_packets)}个数据包: {data}") def main(): # 替换成你的设备VID和PID(可通过设备管理器查看) VENDOR_ID = 0x1234 PRODUCT_ID = 0x5678 devices = hid.HidDeviceFilter(vendor_id=VENDOR_ID, product_id=PRODUCT_ID).get_devices() if not devices: print("未找到目标设备!") return target_device = devices[0] try: target_device.open() # 查找正确的输入端点 in_endpoint = target_device.find_interrupt_in_ep() if not in_endpoint: print("未找到中断输入端点,尝试查找批量输入端点...") in_endpoint = target_device.find_bulk_in_ep() if in_endpoint: # 设置缓冲区大小(可选,根据设备调整) in_endpoint.set_buffer_size(64) in_endpoint.set_raw_data_handler(raw_data_handler) print("开始监听数据,按Ctrl+C停止") while True: time.sleep(0.1) else: print("未找到可用的输入端点!") except KeyboardInterrupt: print("\n停止监听") except Exception as e: print(f"发生错误: {str(e)}") finally: target_device.close() print(f"共捕获{len(received_packets)}个数据包") if __name__ == "__main__": main()
内容的提问来源于stack exchange,提问作者Akash Chakraborty
相关产品推荐
相关产品推荐

