搜索
bottom↓
回复: 19

CH552 官方 USB HID 示例程序中的一个因未完整处理 16 位长度值导致的 bug

[复制链接]

出0入0汤圆

发表于 2020-8-25 21:49:31 | 显示全部楼层 |阅读模式
本帖最后由 wudicgi 于 2020-8-25 21:51 编辑

很多年没写 51 核单片机的程序了,都遗忘了 C51 程序中为了提高效率,经常使用 8 位长度数据类型所带来的弊端了。

最近在开发 BeatShow 设备的固件恢复功能时发现,使用 CH552 实现的 USB HID 设备总是获取不到设备名称,而 STM32F072 的就没问题。即使将所有 USB 描述符都改成一样的,问题也仍然存在。

调试 PC 端程序看到底层调用的 HidD_GetProductString() 函数执行结果是成功的,只是返回的字符串长度为 0, 所以就得从硬件下手了。

经过抓包,发现对于 CH552 设备,除了设备枚举过程中的正常 GET_DESCRIPTOR 请求,在 PC 端程序调用 HidD_GetProductString() 时系统又发送了额外的 GET_DESCRIPTOR 请求。而且这些请求的返回数据长度只有 2 字节,明显是不正常的。

CH552 设备枚举过程中正常的 GET_DESCRIPTOR 请求, wLength = 0x00FF = 255:


CH552 设备完成枚举后的额外 GET_DESCRIPTOR 请求, wLength = 0x0102 = 258:


STM32 设备在完成枚举后则没有这些额外的 GET_DESCRIPTOR 请求:


对于为什么系统只对 CH552 设备发送了这些额外的 GET_DESCRIPTOR 请求,经过一番搜索没有找到答案。但显然 CH552 的程序在这块的处理上有 bug。

CH552 实现的 bootloader 是以 WCH 官方的 USB HID 示例程序 CompatibilityHID.C 为基础,逐步重构和修改而来的。这个示例中有一段处理 SETUP 事物的代码是这样的:
  1. case UIS_TOKEN_SETUP | 0:                       // SETUP 事务
  2.     len = USB_RX_LEN;
  3.     if (len == (sizeof(USB_SETUP_REQ)))
  4.     {
  5.         SetupLen = UsbSetupBuf->wLengthL;
  6.         len = 0;                                // 默认为成功并且上传 0 长度
  7.         SetupReq = UsbSetupBuf->bRequest;
  8.         // ...
复制代码

可以看到只取了 wLength 的低字节部分 wLengthL 作为 SetupLen, 完全没有使用高字节部分 wLengthH。而另一个 VendorDefinedDev.C 示例程序中,就对高字节部分 wLengthH 做了检查:
  1. case UIS_TOKEN_SETUP | 0:                       // endpoint 0# SETUP
  2.     len = USB_RX_LEN;
  3.     if (len == sizeof(USB_SETUP_REQ)) {         // SETUP 包长度
  4.         SetupLen = UsbSetupBuf->wLengthL;
  5.         if (UsbSetupBuf->wLengthH || SetupLen > 0x7F) SetupLen = 0x7F;      // 限制总长度
  6.         len = 0;                                // 默认为成功并且上传 0 长度
  7.         SetupReqCode = UsbSetupBuf->bRequest;
  8.         // ...
复制代码

CompatibilityHID.C 示例程序中原本没有任何字符串描述符,也没有对 GET_DESCRIPTOR 请求的处理代码,相关的内容都是我后添加的。这可能是官方程序中这个 bug 存在了这么长时间的原因。

知道原因后就好修改了,如果程序要返回的数据没有超过 255 字节的,只要在 wLengthH 不为 0 时限制一下 SetupLen 的值就可以了:
  1. case UIS_TOKEN_SETUP | 0:                       // SETUP 事务
  2.     len = USB_RX_LEN;
  3.     if (len == (sizeof(USB_SETUP_REQ)))
  4.     {
  5.         SetupLen = UsbSetupBuf->wLengthL;
  6.         if (UsbSetupBuf->wLengthH != 0)
  7.         {
  8.             SetupLen = 0xFF;                    // 限制总长度
  9.         }
  10.         len = 0;                                // 默认为成功并且上传 0 长度
  11.         SetupReq = UsbSetupBuf->bRequest;
  12.         // ...
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

阿莫论坛才是最爱国的,关心国家的经济、社会的发展、担心国家被别国牵连卷入战争、知道珍惜来之不易的和平发展,知道师夷之长,关注世界的先进文化与技术,也探讨中国文化的博大精深,也懂得警惕民粹主义的祸国殃民等等等等,无不是爱国忧民的表现。(坛友:tianxian)

出0入22汤圆

发表于 2020-8-25 21:51:58 来自手机 | 显示全部楼层
对楼主这样的高手的敬仰有如滔滔江水连绵不绝。

出0入0汤圆

 楼主| 发表于 2020-8-25 21:58:32 | 显示全部楼层
查找问题耗了不少时间,主要是一开始就关注为什么描述符修改的都一模一样了,为什么 CH552 这个设备就是获取不到名称
从硬件抓包结果看,CH552 只是因为处理速度慢,比 STM32F072 多了一些 NAK, 数据包的内容完全一样

另外如果有坛友比较熟悉 USB, 遇到过这种枚举后还发个 wLength = 258 的 GET_DESCRIPTOR 请求的情况,
希望能指教一下,实在是困惑

出0入8汤圆

发表于 2020-8-25 22:06:35 | 显示全部楼层
WCH的例程写的质量比较一般,之前用CH554 HOST 驱动过USB printer,发现也有BUG,当然隔了几年记不得细节了。
建议楼主直接电话他们技术支持,服务还是不错的。也可以去他们技术论坛发帖咨询。
最后问下楼主你用什么设备抓的USB包?当初我用串口printf来debug host程序,那叫一个辛苦啊。。。

出0入0汤圆

发表于 2020-8-25 22:10:38 来自手机 | 显示全部楼层
等待其他坛友解答,最近撸羊毛弄到一些…

出0入0汤圆

 楼主| 发表于 2020-8-25 22:14:05 | 显示全部楼层
jingwaner 发表于 2020-8-25 22:06
WCH的例程写的质量比较一般,之前用CH554 HOST 驱动过USB printer,发现也有BUG,当然隔了几年记不得细节了 ...

确实,那个示例程序我开始先是把变量名、函数名和注释之类的都调整了
然后边理解边重构,不少地方写法有问题

WCH 的论坛里边我看回复都很慢,就不指望了,这种问题还是自己调试靠谱

抓包开始是用 Bus Hound, 后来怀疑系统层面抓的包不全,想看最底层通信的包,这样确定有没有差异最靠谱,
抓包工具的名字在软件标题栏有, USB Packet Viewer, 应该就是开源的 TeenyUSB 库的作者搞的

出0入309汤圆

发表于 2020-8-26 00:22:46 | 显示全部楼层
本帖最后由 iamseer 于 2020-8-26 00:28 编辑

看起来不是所有示例都有这个问题。
CDC,u盘示例都是16位长度
SetupLen = ((UINT16)UsbSetupBuf->wLengthH<<8) | (UsbSetupBuf->wLengthL);
但是其他例程的确实是8位。

官方论坛上我没有问过程序问题,但是硬件相关问题,基本第二个工作日都有答复。

出0入309汤圆

发表于 2020-8-26 00:33:34 | 显示全部楼层
wudicgi 发表于 2020-8-25 22:14
确实,那个示例程序我开始先是把变量名、函数名和注释之类的都调整了
然后边理解边重构,不少地方写法有 ...

CH552用逻辑分析仪抓包分析有时候也很方便,还可以让程序把变量打印出来,同步观察。我是用saleae logic抓包,还是很不错的。

分享我常用的一段调试代码。码率是主时钟的1/3。可以让逻辑分析仪直接挂Uart分析。

  1. void sendCharDebug(char c) //8Mbps under 24M clk
  2. {
  3.     uint8_t interruptOn = EA;
  4.     EA = 0;
  5.     //using P1.4
  6.     __asm__(  //any branch will cause unpridictable timing
  7.             "  mov a,dpl         \n"  //seems to be the parameter of func
  8.             
  9.             "  clr c             \n"
  10.             "  mov _P1_4,c       \n"
  11.             "  rrc a             \n"
  12.             "  mov _P1_4,c       \n"
  13.             "  rrc a             \n"
  14.             "  mov _P1_4,c       \n"
  15.             "  rrc a             \n"
  16.             "  mov _P1_4,c       \n"
  17.             "  rrc a             \n"
  18.             "  mov _P1_4,c       \n"
  19.             "  rrc a             \n"
  20.             "  mov _P1_4,c       \n"
  21.             "  rrc a             \n"
  22.             "  mov _P1_4,c       \n"
  23.             "  rrc a             \n"
  24.             "  mov _P1_4,c       \n"
  25.             "  rrc a             \n"
  26.             "  mov _P1_4,c       \n"
  27.             "  setb c            \n"
  28.             "  mov _P1_4,c       \n"
  29.             
  30.             );
  31.     if (interruptOn) EA = 1;
  32.    
  33.     //  return charToSend;
  34. }
复制代码

出0入228汤圆

发表于 2020-8-26 07:41:25 | 显示全部楼层
看了下LZ的BLOG,玩得可真够杂的呀,牛

USB Packet Viewer,  软件真是搞得不错

出0入8汤圆

发表于 2020-8-26 08:41:18 | 显示全部楼层
iamseer 发表于 2020-8-26 00:33
CH552用逻辑分析仪抓包分析有时候也很方便,还可以让程序把变量打印出来,同步观察。我是用saleae logic ...

可以分享一下使用saleae logic解析USB包的效果吗?
好用的话,打算买一个。

出0入0汤圆

发表于 2020-8-26 08:53:15 | 显示全部楼层
USB Packet Viewer  要配合他自己的硬件才能抓么?

出0入309汤圆

发表于 2020-8-27 12:37:08 | 显示全部楼层
jingwaner 发表于 2020-8-26 08:41
可以分享一下使用saleae logic解析USB包的效果吗?
好用的话,打算买一个。

最近没用saleae调usb 大概像这样

https://www.zzzconsulting.se/2020/04/25/sigrok-usb-dev.html

如果你想试试,可以随便先搞一个pulse view支持的逻辑分析仪,我猜CY7C68013A那种应该也可以。要是觉得不错再买saleae。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2020-8-27 21:05:11 | 显示全部楼层


这个软件的显示效果不错

我买这个 USB Packet Viewer 之前用金沙滩的逻辑分析仪抓过,和 Saleae Logic 的界面显示的差不多,
还是以波形为主,数据只是对波形加个注解,看起来比较费劲
而且这类逻辑分析仪都是先抓数据,结束后才能看到,不是随抓随更新

搞个便宜的 USB 抓包设备也不错,连接也简单,不用单接 D+, D-, GND 三根线了

USB Packet Viewer 中,数据包展开后是这样的:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2020-8-27 21:08:58 | 显示全部楼层
iamseer 发表于 2020-8-26 00:33
CH552用逻辑分析仪抓包分析有时候也很方便,还可以让程序把变量打印出来,同步观察。我是用saleae logic ...

这函数用着方便,不过不查的话 51 的汇编已经很多地方看不懂了
占用 1 个 IO 就行,也不用去初始化 UART

出0入0汤圆

 楼主| 发表于 2020-8-27 21:11:59 | 显示全部楼层
chaplin1999 发表于 2020-8-26 08:53
USB Packet Viewer  要配合他自己的硬件才能抓么?

软件和硬件都叫 USB Packet Viewer, 是得配合才能用
作者把软件的协议解析部分 lua 脚本开源了,但我看了下感觉一般人也改不动

我的 STM32 主控的设备用的是 TeenyUSB 这个开源的 USB 库,从它的官网上看到的 USB Packet Viewer 这个设备

出0入0汤圆

发表于 2020-8-30 19:13:06 来自手机 | 显示全部楼层
wudicgi 发表于 2020-8-25 22:14
确实,那个示例程序我开始先是把变量名、函数名和注释之类的都调整了
然后边理解边重构,不少地方写法有 ...

这是软件抓包还是硬件抓包

出0入0汤圆

 楼主| 发表于 2020-8-31 21:51:47 | 显示全部楼层
huangqi412 发表于 2020-8-30 19:13
这是软件抓包还是硬件抓包

硬件抓包,可以抓 Full Speed 和 High Speed 的

出0入0汤圆

发表于 2020-8-31 22:18:41 | 显示全部楼层
wudicgi 发表于 2020-8-31 21:51
硬件抓包,可以抓 Full Speed 和 High Speed 的

谢谢  这个多少钱

出0入0汤圆

发表于 2022-7-31 22:32:22 来自手机 | 显示全部楼层
沁恒的例程有不少bug

出0入0汤圆

发表于 2022-11-5 22:53:44 | 显示全部楼层
这个问题确实也困扰了我好几天。后来找官方,也没说出个所以然和原因,只是他们的例子就是那样子。让先让联系单片机的负责人,打通说了问题,说这个是USB的问题,让联系USB负责人,找了几次,让加个QQ,加了也只说这个也不知道为什么。他们的代码例子就那样子都是对的。我们都放弃方案,用STM
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-16 21:46

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表