Arduino 获得音量计数值-Arduino中文社区 - Powered by Discuz!

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 5780|回复: 4

Arduino 获得音量计数值

[复制链接]
发表于 2018-2-19 16:09 | 显示全部楼层 |阅读模式
去年买了一个带有 USB 输出噪音计型号是WS1361,我特地去查了一下,201726日买的,然后一直拖到了最近才动手编写 Arduino 的代码。也多亏找到其他人的研究资料【参考1】,所以才比较顺利的完成解码。这部分的工作就像在解密一样,在不知道答案的情况下是一头雾水,当完成之后如释重负。
同样的,USB逻辑分析在这次编写中也发挥了重要。此外,最近接触到的Windows USB分析软件对于反向工程也是很多有效果【参考2】。
第一步还是抓取描述符
  
Connection  Status
  
  
Device  connected
  
  
Current  Configuration
  
  
1
  
  
Speed
  
  
Low  (1.5 Mbit/s)
  
  
Device  Address
  
  
2
  
  
Number  Of Open Pipes
  
  
0
  
DeviceDescriptor WS1361
  
Offset
  
  
Field
  
  
Size
  
  
Value
  
  
Description
  
  
0
  
  
bLength
  
  
1
  
  
12h
  
  
  
  
1
  
  
bDescriptorType
  
  
1
  
  
01h
  
  
Device
  
  
2
  
  
bcdUSB
  
  
2
  
  
0110h
  
  
USB  Spec 1.1
  
  
4
  
  
bDeviceClass
  
  
1
  
  
FFh
  
  
Vendor-Specific
  
  
5
  
  
bDeviceSubClass
  
  
1
  
  
00h
  
  
  
  
6
  
  
bDeviceProtocol
  
  
1
  
  
00h
  
  
  
  
7
  
  
bMaxPacketSize0
  
  
1
  
  
08h
  
  
8  bytes
  
  
8
  
  
idVendor
  
  
2
  
  
16C0h
  
  
VOTI
  
  
10
  
  
idProduct
  
  
2
  
  
05DCh
  
  
  
  
12
  
  
bcdDevice
  
  
2
  
  
0102h
  
  
1.02
  
  
14
  
  
iManufacturer
  
  
1
  
  
01h
  
    
  
15
  
  
iProduct
  
  
1
  
  
02h
  
  
"WS1361"
  
  
16
  
  
iSerialNumber
  
  
1
  
  
00h
  
  
  
  
17
  
  
bNumConfigurations
  
  
1
  
  
01h
  
  
  
ConfigurationDescriptor 1 BusPowered, 50 mA
  
Offset
  
  
Field
  
  
Size
  
  
Value
  
  
Description
  
  
0
  
  
bLength
  
  
1
  
  
09h
  
  
  
  
1
  
  
bDescriptorType
  
  
1
  
  
02h
  
  
Configuration
  
  
2
  
  
wTotalLength
  
  
2
  
  
0012h
  
  
  
  
4
  
  
bNumInterfaces
  
  
1
  
  
01h
  
  
  
  
5
  
  
bConfigurationValue
  
  
1
  
  
01h
  
  
  
  
6
  
  
iConfiguration
  
  
1
  
  
00h
  
  
  
  
7
  
  
bmAttributes
  
  
1
  
  
80h
  
  
Bus  Powered
  
  
  
  
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.......  
  
  
  
  
8
  
  
bMaxPower
  
  
1
  
  
19h
  
  
50 mA
  
InterfaceDescriptor 0/0 0Endpoints
  
Offset
  
  
Field
  
  
Size
  
  
Value
  
  
Description
  
  
0
  
  
bLength
  
  
1
  
  
09h
  
  
  
  
1
  
  
bDescriptorType
  
  
1
  
  
04h
  
  
Interface
  
  
2
  
  
bInterfaceNumber
  
  
1
  
  
00h
  
  
  
  
3
  
  
bAlternateSetting
  
  
1
  
  
00h
  
  
  
  
4
  
  
bNumEndpoints
  
  
1
  
  
00h
  
  
  
  
5
  
  
bInterfaceClass
  
  
1
  
  
00h
  
  
  
  
6
  
  
bInterfaceSubClass
  
  
1
  
  
00h
  
  
  
  
7
  
  
bInterfaceProtocol
  
  
1
  
  
00h
  
  
  
  
8
  
  
iInterface
  
  
1
  
  
00h
  
  
  
之前的键盘鼠标的描述符对于分析非常有用,但是这次描述符在分析过程中几乎可以称作毫无用处。当然,如果非要说有什么作用的话,只是让我得知他使用了自定义的协议。
第二步,使用逻辑分析仪查看抓包。这款逻辑分析仪带有USB接口,插入系统后,安装对应的驱动和应用程序可以在电脑上实时看到获得的当前音量(美中不足的是他们的软件没有数字签名,使用Windows 8/8.1/10 64位的朋友,必须禁用签名才能安装和运行起来)。
抓到的关键数据如下: Get Device Descriptor(Transfer 12) -> 获取自定义数据(Transfer 13)  –> Get Device Descriptor(Transfer 14) 这样循环下去。这样的循环是他的应用程序驱动完成的。在我看来Get Device Descriptor 是毫无用处的。可能是应用程序用来确定设备是否被 remove才做的。
usb1.png
详细分析获取数据的过程 Transfer 13, 由 Transaction 283/286/287 三笔来组成。Transaction 283用户自定义的 Setup 过程,我们代码只需要做出和他内容相同的发出去即可。然后Transaction 286 是噪音计回复的数据包,其中有我们需要的当前音量数据。具体格式从【参考1】可以看到。
硬件方面使用的是 Arduino USB Host板+ Arduino Uno,因为是 Shield板,直接插上即可使用。为了更清楚的展示接收数据的过程,我使用了巨大的LED数码管(1.8寸),关于这个数码管的介绍可以在之前的文章中找到。
usb2.jpg
根据上述内容,编写程序如下:
[kenrobot_code]#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);

  }

}[/kenrobot_code]
工作的视频可以在知乎专栏看到 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 LevelMeter
2.     http://www.lab-z.com/usblyzer/介绍一个 USB分析软件Usblyzer

发表于 2018-3-30 10:15 | 显示全部楼层
请问楼主,表格里彩色的USB数据是怎么弄得呢
 楼主| 发表于 2018-3-30 17:05 | 显示全部楼层
MACE 发表于 2018-3-30 10:15
请问楼主,表格里彩色的USB数据是怎么弄得呢

这是 usb 逻辑分析仪抓取的数据,

具体你可以看看之前的文章
发表于 2018-4-2 22:18 来自手机 | 显示全部楼层
我也说一句在不知道答案的情况下是一头雾水,当完成之后如释重负。感同身受
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2024-11-28 11:40 , Processed in 0.100079 second(s), 21 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表