我正在开发基于 Arduino Micro 的自定义 HID 兼容 UPS。当我将其连接到 Apple OSX(我使用 Macbook 作为主机)或 Windows 10 VM 计算机时,操作系统会正确确定我的“UPS”,并且我还可以将剩余电池容量和其他参数报告回主机。
但是,当我将其插入 Ubuntu 18.04 LTS 时,它无法工作(电源设置中未显示)。同时,商用 APC UPS 在 Ubuntu 下工作正常。lsusb 的发布如下:
abratchik@ubuntu-parallels-vm:~$ lsusb
Bus 001 Device 003: ID 203a:fffa
Bus 001 Device 002: ID 203a:fffa
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 002: ID 203a:fff9
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 004: ID 2341:8036 Arduino SA Leonardo (CDC ACM, HID)
Bus 002 Device 006: ID 051d:0003 American Power Conversion UPS
Bus 002 Device 003: ID 203a:fffe
Bus 002 Device 002: ID 203a:fffc
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
abratchik@ubuntu-parallels-vm:~$ lsusb -t
/: Bus 04.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/12p, 5000M
|__ Port 1: Dev 2, If 0, Class=Video, Driver=uvcvideo, 5000M
|__ Port 1: Dev 2, If 1, Class=Video, Driver=uvcvideo, 5000M
/: Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/2p, 480M
/: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=uhci_hcd/2p, 12M
|__ Port 1: Dev 2, If 0, Class=Human Interface Device, Driver=usbhid, 12M
|__ Port 1: Dev 2, If 1, Class=Human Interface Device, Driver=usbhid, 12M
|__ Port 2: Dev 3, If 0, Class=Hub, Driver=hub/15p, 12M
|__ Port 5: Dev 4, If 2, Class=Human Interface Device, Driver=usbhid, 12M
|__ Port 5: Dev 4, If 0, Class=Communications, Driver=cdc_acm, 12M
|__ Port 5: Dev 4, If 1, Class=CDC Data, Driver=cdc_acm, 12M
|__ Port 4: Dev 6, If 0, Class=Human Interface Device, Driver=usbhid, 12M
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/15p, 480M
|__ Port 1: Dev 2, If 0, Class=Printer, Driver=usblp, 480M
|__ Port 2: Dev 3, If 0, Class=Printer, Driver=usblp, 480M
在第一张打印输出中,我的定制 UPS 的 ID 为 2341:8036,而 APC UPS 的 ID 为 051d:0003。第二张打印输出也显示它们都被正确识别为 HID 设备(我的 UPS 为总线 02 端口 5 接口 2,APC 为端口 4 接口 0),并且两者都使用连接USB驱动程序,这也是正确的并且符合预期。
但是,Ubuntu 正确地将 APC 检测为 UPS,而我的 UPS 根本没有显示:
abratchik@ubuntu-parallels-vm:~$ upower -e
/org/freedesktop/UPower/devices/line_power_ADP0
/org/freedesktop/UPower/devices/battery_BAT0
/org/freedesktop/UPower/devices/ups_hiddev3
/org/freedesktop/UPower/devices/DisplayDevice
abratchik@ubuntu-parallels-vm:~$ upower -i /org/freedesktop/UPower/devices/ups_hiddev3
native-path: /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2.4/2-2.4:1.0/usbmisc/hiddev3
vendor: American Power Conversion
model: Smart-UPS C 1500 FW:UPS 10.0 / ID=1005
serial: 3S1838X02676
power supply: yes
updated: Thu 03 Dec 2020 10:00:04 AM +04 (-11 seconds ago)
has history: yes
has statistics: yes
ups
present: yes
state: fully-charged
warning-level: none
time to empty: 2.0 hours
percentage: 100%
icon-name: 'battery-full-charged-symbolic'
此外,Arduino 板上的 RX/TX LED 不闪烁,因此看起来板子和 VM 之间没有交换。正如我上面提到的,同一块板子在 OSX 和 Windows 10 下运行良好。
我搜索了一下,发现关于这个主题的许多文章都提到了 usbhid-ups 驱动程序,据我所知,默认情况下不会安装该驱动程序,需要进行一些配置。我真的想避免这种情况,让我的 UPS 完全“即插即用”,类似于 APC UPS。已经不知道我的 UPS 可能有什么不同,除了供应商 ID/产品 ID,但这将是我尝试更改这些的最后选择。任何提示我遗漏了什么都将不胜感激。
答案1
最后我明白了它是如何工作的。Linux 中的 usbhid 驱动程序没有问题,它只是 HID 协议的低级解析器,除了解密设备响应并将其传递给管理层之外,并没有真正做任何智能工作,管理层是udev(Linux 内核设备管理器)和优力管理器,位于 udev 之上。
UPower 实际上定义了所有支持的供应商 ID/产品 ID 的列表,并以以下形式将其提供给 udevudev 规则。所以我是对的 - 在这种情况下,供应商 ID/产品 ID 确实很重要 - 如果您是 APC,那么您的 UPS 将被自动检测到,否则即使该设备符合 HID 标准,UPower 也会忽略它。
幸运的是,有一个解决方法。udev 规则以文本格式存储在 /etc/udev/rules.d/ 文件夹中,因此可以轻松定义其他规则。必须创建文件98-upower-hid.规则(我认为确切的文件名并不那么重要)在此文件夹中并添加以下行:
ATTRS{idVendor}=="2341", ENV{UPOWER_VENDOR}="Arduino"
ATTRS{idVendor}=="2341", ATTRS{idProduct}=="8036", ENV{UPOWER_BATTERY_TYPE}="ups"
重启。之后,Ubuntu 就可以正常识别带有 UPS 草图的 Arduino 板了。