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. https://www.ebswift.com/reverse-engineering-spl-usb.html
Reverse Engineering the USB Protocol on the WENSN WS1361 Sound Pressure LevelMeter2. http://www.lab-z.com/usblyzer/介紹一個 USB
分析軟體Usblyzer推薦閱讀:
※正品 Teensy
※AP3216C 模塊
※如何用processing做出如下圖案?
※Arduino 的 Serial.write() 和 Serial.print() 的區別在哪裡?
※做一個智能花草照料花盆(五) 麵包板
TAG:Arduino |