RevEng the USB data
So I've found my SPL instrument (here) but unfortunately it does run only on Windows XP.
My plan was to use RaspberryPi and Linux to build the environmental monitoring station and I had to find a way to retrieve data from the AR844 SPL meter in realtime... But without manuals and open source drivers ... how to make it?
The only solution is to do some reverse engineering.
I had to find those bits in the protocol that I can use to compute the measure and do my own statistics.
The most professional solution would be to have an USB protocol analyzer, for example the excellent "Beagle USB 12 Protocol Analyzer" available for just around 400USD at Adafruit, but I don't have it (!) And even worst they don't ship to my country (how lucky am I?)
The solution came with an open source USB sniffer tool called USBSNOOP: http://sourceforge.net/projects/usbsnoop/
The tool works under Windows (great!!) and once you launch you can open the USB device list by pressing F2.
That is the list of your connected USB devices and you want to find the one you care about to install the correct sniffer hook. Now the question is: what vendor_id and product_id are used by the AR844 unit? Easy answer..
Connecting the AR844 to my linux laptop and using libusb you can actually browse all the details of the unit:
#> lsusb -v
And you will see something like this output:
Bus 001 Device 005: ID 1234:5678 Brain Actuated Technologies Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 1.10 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 8 idVendor 0x1234 Brain Actuated Technologies idProduct 0x5678 bcdDevice 0.00 iManufacturer 1 SM iProduct 2 SM iSerial 0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 41 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 50mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 0 No Subclass bInterfaceProtocol 0 None iInterface 0 HID Device Descriptor: bLength 9 bDescriptorType 33 bcdHID 1.10 bCountryCode 0 Not supported bNumDescriptors 1 bDescriptorType 34 Report wDescriptorLength 52 Report Descriptors: ** UNAVAILABLE ** Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0008 1x 8 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0008 1x 8 bytes bInterval 0 Device Status: 0xb908 (Bus Powered)
Hell this is a lot of informations ... but we need only few of them:
- idVendor 0x1234 Brain Actuated Technologies
- idProduct 0x5678
- The unit has one input endpoint (dataflow going from AR844 to the computer) at add address 0x81, transfer is 8 bytes, interrupt
- The unit has one output endpoint, address 0x02, 8bytes data, interrupt
So I did install the usbsniffer on the correct id vendor/product while I was connected to the VoiceLab. I wanted to understand what messaging was going on to retrieve the measure and for this purpose I did use Voicelab in manual mode, making one reading for each time I pressed the button.
By looking at the log I was able to understand the following:
- every time I want to trigger a reading from the instrument I have to send a command on the output endpoint with the "b3 00 00 00 00 00 00" data. I'm sure there is more in those bits, but with all the test I did the word "b3" was always sent and so I use it as a constant value.
- the AR844 does return a measure (8 bytes) and somehow tha last part seems not to change a lot..
- here are some USBSniffer logs I've used to reverse the data format: USBLog1 USBLog3
The next step was to manually correlate all those logs with the data I saw from the unit.
Note that it was not just about the number itself, but also all the other important informations: the scale type (A or C) and the measure range set on the unit (30-130dB, 30-80dB etc etc)
I did a spreadsheet and started to stair at the results, here is a table for log n.3: AR844_test3
After a while I was able to retrieve the informations I needed: EUREKA!
It turns out the protocol is pretty simple: we just need the first 3 bytes.
The first two bytes are the one that give you the SPL measure value:
SPL_measure = (Byte0 *256 + Byte1 ) /10
While the 3rd byte is the one containing informations about the curve type (A or C) and the measure range. This time it is a bitmask:
bit0(LSB) : measure range bit0 bit1 : measure range bit1 bit2 : measure range bit2 bit3 : NC bit4 : curve type, A=1, C=0 bit5 : NC bit6 : sampling type, SLOW=1, FAST=0 bit7 : ??
The measure range is specified by 3bits because the unit has 3 levels of sensitivity: 30-130, 30-80, 50-100 and 60-110. Ranges are expressed by these values of the last 3 bits of the 3rd byte:
- 0 = range 30 to 180dB
- 1 = range 30 to 80dB
- 2 = range 50 to 100dB
- 3 = range 60 to 110dB
The next step was to read the usb data from Linux ... libusb!