Arduino 获得 WS1361 音量计数值

Arduino 获得 WS1361 音量计数值

去年买了一个带有 USB 输出噪音计型号是
WS1361,我特地去查了一下,2017年2月6日买的,然后一直拖到了最近才动手编写 Arduino 的代码。也多亏找到其他人的研究资料【参考1】,所以才比较顺利的完成解码。这部分的工作就像在解密一样,在不知道答案的情况下是一头雾水,当完成之后如释重负。

同样的,USB逻辑分析在这次编写中也发挥了重要。此外,最近接触到的Windows USB分析软件对于反向工程也是很多有效果【参考2】。

第一步还是抓取描述符


之前的键盘鼠标的描述符对于分析非常有用,但是这次描述符在分析过程中几乎可以称作毫无用处。当然,如果非要说有什么作用的话,只是让我得知他使用了自定义的协议。

第二步,使用逻辑分析仪查看抓包。这款逻辑分析仪带有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[2];


Usb.ctrlReq(

pdev->address.devAddress,

0, //EndPoint

0xC0, //bmRequestType

0x04, //bRequest

0x01, //wValeLow

0x00, //wValueHigh

0x0000, //wIndex

nbytes,

nbytes,

&value[0],

NULL);

if ((value[0]+(value[1]<<8))==LastDB) {

return;

}

else

LastDB=(value[0]+(value[1]<<8));

//Serial.print("RAW:");

//Serial.print(value[0],HEX);

//Serial.print(" ");

//Serial.println(value[1],HEX);


//Serial.print(" DB:");

//Serial.println((value[0] + ((value[1] &
3) * 256)) * 0.1 + 30);

digitalshow(((value[0] + ((value[1] & 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://www.zhihu.com/video/948948344039550976

参考:

1. ebswift.com/reverse-eng
Reverse Engineering the USB Protocol on the WENSN WS1361 Sound Pressure Level
Meter

2. lab-z.com/usblyzer/介绍一个 USB
分析软件
Usblyzer

编辑于 2018-02-19

文章被以下专栏收录