Arduino 获得音量计数值
去年买了一个带有 USB 输出噪音计型号是WS1361,我特地去查了一下,2017年2月6日买的,然后一直拖到了最近才动手编写 Arduino 的代码。也多亏找到其他人的研究资料【参考1】,所以才比较顺利的完成解码。这部分的工作就像在解密一样,在不知道答案的情况下是一头雾水,当完成之后如释重负。同样的,USB逻辑分析在这次编写中也发挥了重要。此外,最近接触到的Windows USB分析软件对于反向工程也是很多有效果【参考2】。第一步还是抓取描述符ConnectionStatusDeviceconnected
CurrentConfiguration1
SpeedLow(1.5 Mbit/s)
DeviceAddress2
NumberOf Open Pipes0
DeviceDescriptor WS1361
OffsetFieldSizeValueDescription
0bLength112h
1bDescriptorType101hDevice
2bcdUSB20110hUSBSpec 1.1
4bDeviceClass1FFhVendor-Specific
5bDeviceSubClass100h
6bDeviceProtocol100h
7bMaxPacketSize0108h8bytes
8idVendor216C0hVOTI
10idProduct205DCh
12bcdDevice20102h1.02
14iManufacturer101h"www.wensn.com"
15iProduct102h"WS1361"
16iSerialNumber100h
17bNumConfigurations101h
ConfigurationDescriptor 1 BusPowered, 50 mA
OffsetFieldSizeValueDescription
0bLength109h
1bDescriptorType102hConfiguration
2wTotalLength20012h
4bNumInterfaces101h
5bConfigurationValue101h
6iConfiguration100h
7bmAttributes180hBusPowered
4..0:Reserved ...00000
5:Remote Wakeup ..0.....No
6:Self Powered .0......No,Bus Powered
7:Reserved (set to one)
(bus-powered for 1.0) 1.......
8bMaxPower119h50 mA
InterfaceDescriptor 0/0 0Endpoints
OffsetFieldSizeValueDescription
0bLength109h
1bDescriptorType104hInterface
2bInterfaceNumber100h
3bAlternateSetting100h
4bNumEndpoints100h
5bInterfaceClass100h
6bInterfaceSubClass100h
7bInterfaceProtocol100h
8iInterface100h
之前的键盘鼠标的描述符对于分析非常有用,但是这次描述符在分析过程中几乎可以称作毫无用处。当然,如果非要说有什么作用的话,只是让我得知他使用了自定义的协议。第二步,使用逻辑分析仪查看抓包。这款逻辑分析仪带有USB接口,插入系统后,安装对应的驱动和应用程序可以在电脑上实时看到获得的当前音量(美中不足的是他们的软件没有数字签名,使用Windows 8/8.1/10 64位的朋友,必须禁用签名才能安装和运行起来)。抓到的关键数据如下: Get Device Descriptor(Transfer 12) -> 获取自定义数据(Transfer 13)–> Get Device Descriptor(Transfer 14) 这样循环下去。这样的循环是他的应用程序驱动完成的。在我看来Get Device Descriptor 是毫无用处的。可能是应用程序用来确定设备是否被 remove才做的。详细分析获取数据的过程 Transfer 13, 由 Transaction 283/286/287 三笔来组成。Transaction 283用户自定义的 Setup 过程,我们代码只需要做出和他内容相同的发出去即可。然后Transaction 286 是噪音计回复的数据包,其中有我们需要的当前音量数据。具体格式从【参考1】可以看到。硬件方面使用的是 Arduino USB Host板+ Arduino Uno,因为是 Shield板,直接插上即可使用。为了更清楚的展示接收数据的过程,我使用了巨大的LED数码管(1.8寸),关于这个数码管的介绍可以在之前的文章中找到。根据上述内容,编写程序如下:#include "Usb.h"
USB Usb;
uint16_t LastDB=0;
void digitalshow(int value)
{
//这是数码管要求的数据头信息
Serial.write(0xff);
Serial.write(0x00);
Serial.write(0x04);//显示四位数值
//下面是四位当前值
Serial.write(0x10);//第一位黑
Serial.write((value - value /1000 * 1000) / 100);
//第三位后面有小数点,最高位为 1 表示显示小数点
Serial.write((value - value /100 * 100) / 10+ 0x80);
Serial.write(value % 10);
//最后一位是亮度
Serial.write(1);
}
void DataParser(UsbDevice *pdev)
{
int nbytes=4;
uint8_t value;
Usb.ctrlReq(
pdev->address.devAddress,
0, //EndPoint
0xC0, //bmRequestType
0x04, //bRequest
0x01, //wValeLow
0x00, //wValueHigh
0x0000, //wIndex
nbytes,
nbytes,
&value,
NULL);
if ((value+(value<<8))==LastDB) {
return;
}
else
LastDB=(value+(value<<8));
//Serial.print("RAW:");
//Serial.print(value,HEX);
//Serial.print(" ");
//Serial.println(value,HEX);
//Serial.print(" DB:");
//Serial.println((value + ((value & 3) * 256)) * 0.1 + 30);
digitalshow(((value + ((value & 3) * 256)) * 0.1 + 30)*10);
}
void setup()
{
Serial.begin( 115200 );
Serial.println("Start");
if (Usb.Init() == -1)
Serial.println("OSC did not start.");
delay( 200 );
}
void loop()
{
Usb.Task();
if ( Usb.getUsbTaskState() == USB_STATE_RUNNING )
{
Usb.ForEachUsbDevice(&DataParser);
delay(200);
}
}工作的视频可以在知乎专栏看到 https://zhuanlan.zhihu.com/p/33877460 参考:1. https://www.ebswift.com/reverse-engineering-spl-usb.htmlReverse Engineering the USB Protocol on the WENSN WS1361 Sound Pressure LevelMeter2. http://www.lab-z.com/usblyzer/介绍一个 USB分析软件Usblyzer
请问楼主,表格里彩色的USB数据是怎么弄得呢 MACE 发表于 2018-3-30 10:15
请问楼主,表格里彩色的USB数据是怎么弄得呢
这是 usb 逻辑分析仪抓取的数据,
具体你可以看看之前的文章 我也说一句在不知道答案的情况下是一头雾水,当完成之后如释重负。感同身受
页:
[1]