You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby中lsusb输出特殊字符转stlink hla_serial的编码问题

问题根因

多余的两个hex字符c3、bf来自编码链路错配,和ST-Link本身的序列号无关:

  1. ST-Link的iSerial是原始12字节二进制流,不是标准可打印文本,其中第二个字节固定为0x3f(ASCII问号?),其余字节也夹杂0x06、0x11这类不可打印控制字符。
  2. lsusb输出是面向人类阅读的格式化文本,输出时会把原始字节按当前系统字符集(通常是Latin-1/ISO-8859-1)映射为可显示字符,这个过程中0x3f被错误映射为字符ÿ(Latin-1编码为0xff)。
  3. Ruby调用shell命令捕获输出时,默认按UTF-8编码解析内容,0xff不是合法的UTF-8单字节,会被转码为Unicode字符U+00FF,对应的UTF-8编码就是双字节0xc3 0xbf,平白多占1个字节,最终得到的hex串就比原始参考值多2个hex位(对应1个冗余字节)。
  4. 你之前直接unpack硬编码字符串时长度不对,是因为Ruby源码文件的编码和字符串转义过程吞掉了0x06这类不可打印控制字符;用Open3捕获输出时保留了控制字节,所以长度只差固定的2个hex位。
正确实现方案

不要解析lsusb的人类可读输出,这是最容易踩编码坑的路径,优先直接读取系统暴露的原始二进制数据:

# 方案1:直接读取sysfs下的原始序列号,无任何编码转码问题,结果直接可用
def list_stlink_hla_serials
  result = []
  Dir.glob('/sys/bus/usb/devices/*/idVendor') do |vendor_path|
    dev_dir = File.dirname(vendor_path)
    # 筛选STLink设备:VID=0483 PID=3748
    next unless File.read(vendor_path, encoding: 'binary').strip == '0483'
    next unless File.read(File.join(dev_dir, 'idProduct'), encoding: 'binary').strip == '3748'
    # 读取原始二进制序列号,直接转hex就是OpenOCD可用的hla_serial
    raw_serial = File.read(File.join(dev_dir, 'serial'), encoding: 'binary').strip
    result << raw_serial.unpack1('H*')
  end
  result
end

如果必须兼容解析lsusb输出的场景,只需要把固定转码错误的ÿ替换回原始字节即可,双向转换代码如下:

# lsusb输出的序列号字符串转OpenOCD可用的hla_serial hex串
def lsusb_str_to_hla(lsusb_serial_str)
  bin_str = lsusb_serial_str.b
  # 把转码错误生成的0xc3bf(即字符ÿ)替换回原始字节0x3f
  bin_str.gsub!("\xc3\xbf".b, "\x3f".b)
  bin_str.unpack1('H*')
end

# hla_serial hex串转lsusb显示的字符串
def hla_to_lsusb_str(hla_hex)
  bin_str = [hla_hex].pack('H*').b
  # 模拟lsusb的转码错误,把0x3f替换为ÿ
  bin_str.gsub("\x3f".b, "\xc3\xbf".b).force_encoding('UTF-8')
end
验证

用你提供的样本测试可以完全匹配:

ref = ["343f6b06564b363027372043","343f6b06564b363011372043","343f6906564b363043372043","343f6c06564b363029372043","343f6b06564b363014362043","343f6d06564b363016372043","343f7106564b363016362043"]
dec = ["4ÿqVK606 C","4ÿmVK607 C","4ÿkVK606 C" ,"4ÿlVK60)7 C" ,"4ÿiVK60C7 C" ,"4ÿkVK607 C"  ,"4ÿkVK60'7 C"]

# 你提供的ref和dec列表顺序不是一一对应的,转换后排序即可完全匹配
converted_ref = dec.map { |s| lsusb_str_to_hla(s) }.sort
puts converted_ref == ref.sort # => true

内容的提问来源于stack exchange,提问作者ludelle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 23:39:35