標籤:

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


推薦閱讀:

正品 Teensy
AP3216C 模塊
如何用processing做出如下圖案?
Arduino 的 Serial.write() 和 Serial.print() 的區別在哪裡?
做一個智能花草照料花盆(五) 麵包板

TAG:Arduino |