将lsusb输出中的奇怪字符转换为ruby中的stlink hla_serial

cvxl0en2  于 2023-04-29  发布在  Ruby
关注(0)|答案(1)|浏览(61)

我目前使用的stlink板有lsusb提供的“奇怪”iSerial:下面是一个例子:

lsusb -v -d 0483:3748 | grep iSerial
iSerial                 3 4ÿkVK607 C
iSerial                 3 4ÿkVK60'7 C

我已经得到了在openocd配置文件中使用的相应的hla_serial,它看起来像“\x34\x3f\x6b\x06\x56\x4b\x36\x30\x27\x37\x20\x43”或者如果我们删除十六进制符号=〉“343 f6 b 06564 b363027372043”
我希望能够在这两种格式之间进行转换,但这并不容易。我知道外部团队给我的以下hla_serial(ref)列表对应于lsusb(dec)中的以下奇怪字符串(至少openocd可以处理这些字符串。

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"]

我试过很多打包/解包,但我无法找到正确的编码/解码。壁橱的事

">4ÿkVK60'7 C".unpack('H*')
["34c3bf6b564b363027372043"]

因此,当尝试解码所有iSerial时:

> ref = "343f6b06564b363027372043"
=> "343f6b06564b363027372043"
> ["4ÿqVK606 C","4ÿmVK607 C","4ÿkVK606 C" ,"4ÿlVK60)7 C" ,"4ÿiVK60C7 C" ,"4ÿkVK607 C"  ,"4ÿkVK60'7 C"].each {|t| $stdout << "ref:#{ref}\ndec:#{t.unpack('H*').first}\n\n"}
ref:343f6b06564b363027372043
dec:34c3bf71564b3630362043

ref:343f6b06564b363027372043
dec:34c3bf6d564b3630372043

ref:343f6b06564b363027372043
dec:34c3bf6b564b3630362043

ref:343f6b06564b363027372043
dec:34c3bf6c564b363029372043

ref:343f6b06564b363027372043
dec:34c3bf69564b363043372043

ref:343f6b06564b363027372043
dec:34c3bf6b564b3630372043

ref:343f6b06564b363027372043
dec:34c3bf6b564b363027372043

名单上的最后一个可能是最接近的,但不匹配裁判。您还可以注意到一些解码的数字没有正确的长度。
我尝试在Ruby中直接获取shell命令的输出并对其进行后处理

> require 'open3'
=> true
> o,e,s = Open3.capture3('lsusb -v -d 0483:3748 | grep iSerial')
> dec = o.split("\n").map {|l| l.sub(/.*iSerial.* 3 /,'').unpack('H*').first}
34c3bf7106564b363016362043
34c3bf6d06564b363016372043
34c3bf6b06564b363014362043
34c3bf6c06564b363029372043
34c3bf6906564b363043372043
34c3bf6b06564b363011372043
34c3bf6b06564b363027372043

这样更好,至少每个字符串都有相同的长度(26个字符而不是ref的24个字符)奇怪的是,所有字符串都非常接近ref中的字符串,如果我们像这样删除两个字符:

dec: 34c3bf6b06564b363027372043
ref: 34_3_f6b06564b363027372043

然后我得到了与参考表中完全相同的列表。
现在我只想知道这两个额外的字符的原因。我应该解码不同吗?

u5rb5r59

u5rb5r591#

你需要的是“USB ECN:UNICODE UTF-16 LE for String Descriptors”,从2005年开始,原来的规范只是说“unicode字符串”

  • 咯咯笑 *

ECN中描述了USB字符串描述符应该正式包含utf 16-le字符串,因为这是大多数程序员一直在做的。因此,如果你做任何解码,它应该是UTF-16 LE。..它应该在你从USB子系统得到的数据上。
您还必须意识到,您在控制台中看到的不是utf 16。就是你的控制台决定渲染的内容。现在,你在stdout上得到的字节可能是utf 16,但是当你打印和复制粘贴它们时,只有上帝知道你得到了什么。您的文本编辑器可能会粘贴utf8。我都不想去想那里会发生什么
您没有指定您使用的语言,但看起来像是Python。我将使用python3,因为它有方便的bytes类型和更好的unicode字符串。
看起来st的开发人员已经决定使用0到255之间的unicode代码点来编码他们版本号的字节。而我所说的‘决定’是指他们刚刚那样做了,而我们现在被困在这里;)
所以你看到十六进制编码序列号:343 f6 b 06564 b363027372043实际上是存储在USB字符串描述符中的b“\x34\x00\x3F\x00\x6B\x00\x06\x00\x56\x00\x4B\x00\x36\x00\x30\x00\x27\x00\x37\x00\x20\x00\x43\x00”。您可以看到它是一个有效的utf 16小端编码字符串。
在python3中,当你向pyusb请求序列号时,你会得到一个实际的“unicode字符串”i。即utf 16 USB字符串表示的代码点序列。所有你真正需要的是代码点:
下面是一个使用python3的示例

import usb

devicess = usb.core.find(idVendor=0x0483, find_all=True)
for dev in devicess:
    # encode the unicode character's code points as single bytes and concatenate them
    serial = b''.join([ord(uchar).to_bytes(1, byteorder='little') for uchar in dev.serial_number])

    # encode and print the serial number as a hex string
    print(serial.hex())

或者你也可以使用pyswd来为我们做到这一点。

import swd

for dev in swd.stlink.usb.StlinkUsb._find_all_devices():
    print(dev.serial_no)

相关问题