I’ve bought cheap USB handset from eBay to use with my VoIP provider. In Widows it worked good with supplied app which supported few VoIP programs and Skype. Since I use Linux on my desktop, I tried to plug it in. In USB listing it showed up as soundcard and HID device.
Bus 001 Device 008: ID 04b4:0307 Cypress Semiconductor Corp. Couldn't open device, some information will be missing Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 1.10 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 8 idVendor 0x04b4 Cypress Semiconductor Corp. idProduct 0x0307 bcdDevice 1.10 iManufacturer 0 iProduct 0 iSerial 0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 224 bNumInterfaces 4 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 0 bInterfaceClass 1 Audio bInterfaceSubClass 1 Control Device bInterfaceProtocol 0 iInterface 0 AudioControl Interface Descriptor: bLength 10 bDescriptorType 36 bDescriptorSubtype 1 (HEADER) bcdADC 1.00 wTotalLength 79 bInCollection 2 baInterfaceNr( 0) 1 baInterfaceNr( 1) 2 AudioControl Interface Descriptor: bLength 12 bDescriptorType 36 bDescriptorSubtype 2 (INPUT_TERMINAL) bTerminalID 1 wTerminalType 0x0101 USB Streaming bAssocTerminal 0 bNrChannels 2 wChannelConfig 0x0003 Left Front (L) Right Front (R) iChannelNames 0 iTerminal 0 AudioControl Interface Descriptor: bLength 9 bDescriptorType 36 bDescriptorSubtype 3 (OUTPUT_TERMINAL) bTerminalID 3 wTerminalType 0x0301 Speaker bAssocTerminal 0 bSourceID 2 iTerminal 0 AudioControl Interface Descriptor: bLength 10 bDescriptorType 36 bDescriptorSubtype 6 (FEATURE_UNIT) bUnitID 2 bSourceID 1 bControlSize 1 bmaControls( 0) 0x03 Mute Control Volume Control bmaControls( 1) 0x00 bmaControls( 2) 0x00 iFeature 0 AudioControl Interface Descriptor: bLength 12 bDescriptorType 36 bDescriptorSubtype 2 (INPUT_TERMINAL) bTerminalID 5 wTerminalType 0x0201 Microphone bAssocTerminal 0 bNrChannels 1 wChannelConfig 0x0000 iChannelNames 0 iTerminal 0 AudioControl Interface Descriptor: bLength 9 bDescriptorType 36 bDescriptorSubtype 3 (OUTPUT_TERMINAL) bTerminalID 7 wTerminalType 0x0101 USB Streaming bAssocTerminal 0 bSourceID 6 iTerminal 0 AudioControl Interface Descriptor: bLength 8 bDescriptorType 36 bDescriptorSubtype 6 (FEATURE_UNIT) bUnitID 6 bSourceID 5 bControlSize 1 bmaControls( 0) 0x03 Mute Control Volume Control iFeature 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 0 bInterfaceClass 1 Audio bInterfaceSubClass 2 Streaming bInterfaceProtocol 0 iInterface 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 1 bNumEndpoints 1 bInterfaceClass 1 Audio bInterfaceSubClass 2 Streaming bInterfaceProtocol 0 iInterface 0 AudioStreaming Interface Descriptor: bLength 7 bDescriptorType 36 bDescriptorSubtype 1 (AS_GENERAL) bTerminalLink 1 bDelay 1 frames wFormatTag 1 PCM AudioStreaming Interface Descriptor: bLength 11 bDescriptorType 36 bDescriptorSubtype 2 (FORMAT_TYPE) bFormatType 1 (FORMAT_TYPE_I) bNrChannels 2 bSubframeSize 2 bBitResolution 16 bSamFreqType 1 Discrete tSamFreq[ 0] 48000 Endpoint Descriptor: bLength 9 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 9 Transfer Type Isochronous Synch Type Adaptive Usage Type Data wMaxPacketSize 0x00c0 1x 192 bytes bInterval 1 bRefresh 0 bSynchAddress 0 AudioControl Endpoint Descriptor: bLength 7 bDescriptorType 37 bDescriptorSubtype 1 (EP_GENERAL) bmAttributes 0x00 bLockDelayUnits 0 Undefined wLockDelay 0 Undefined Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 0 bInterfaceClass 1 Audio bInterfaceSubClass 2 Streaming bInterfaceProtocol 0 iInterface 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 1 bNumEndpoints 1 bInterfaceClass 1 Audio bInterfaceSubClass 2 Streaming bInterfaceProtocol 0 iInterface 0 AudioStreaming Interface Descriptor: bLength 7 bDescriptorType 36 bDescriptorSubtype 1 (AS_GENERAL) bTerminalLink 7 bDelay 1 frames wFormatTag 1 PCM AudioStreaming Interface Descriptor: bLength 11 bDescriptorType 36 bDescriptorSubtype 2 (FORMAT_TYPE) bFormatType 1 (FORMAT_TYPE_I) bNrChannels 1 bSubframeSize 2 bBitResolution 16 bSamFreqType 1 Discrete tSamFreq[ 0] 8000 Endpoint Descriptor: bLength 9 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 1 Transfer Type Isochronous Synch Type None Usage Type Data wMaxPacketSize 0x0010 1x 16 bytes bInterval 1 bRefresh 0 bSynchAddress 0 AudioControl Endpoint Descriptor: bLength 7 bDescriptorType 37 bDescriptorSubtype 1 (EP_GENERAL) bmAttributes 0x00 bLockDelayUnits 0 Undefined wLockDelay 0 Undefined Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 3 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 36 Report Descriptors: ** UNAVAILABLE ** 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 48 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x04 EP 4 OUT bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0020 1x 32 bytes bInterval 1
Soundcard was working out of box: headset speaker and mic were correctly working when set in my linphone SIP client. But I also wanted to utilize phones keyboard and display. I checked which /dev/hidrawX device corresponds to my phone and started
sudo cat /dev/hidraw1 | hexdump. When I pressed buttons, following output has appeared:
#sudo cat /dev/hidraw1 | hexdump 0000000 0301 0100 0101 0101 0001 0100 0101 0101 0000010 0901 0100 0101 0101 0001 0100 0101 0101 0000020 0f01 0100 0101 0101 0001 0100 0101 0101 0000030 0401 0100 0101 0101 0001 0100 0101 0101 0000040 0a01 0100 0101 0101 0001 0100 0101 0101 0000050 1001 0100 0101 0101 0001 0100 0101 0101 0000060 0501 0100 0101 0101 0001 0100 0101 0101 0000070 0b01 0100 0101 0101 0001 0100 0101 0101 0000080 1101 0100 0101 0101 0001 0100 0101 0101
Good! One line for each button press. So I created a short python script to open /dev/hidraw1, read inputs, then map it to keys and print to stdout and it worked great!
#!/usr/bin/python keys = { 0x00 : "", 0x03 : "1", 0x09 : "2", 0x0f : "3", 0x04 : "4", 0x0a : "5", 0x10 : "6", 0x05 : "7", 0x0b : "8", 0x11 : "9", 0x06 : "*", 0x0c : "0", 0x12 : "#", 0x02 : "yes", 0x08 : "S", 0x0e : "no", 0x01 : "left", 0x13 : "up", 0x16 : "down", 0x0d : "right", 0x19 : "vol+", 0x1c : "vol-", 0x1b : "mute", } file = open( "/dev/hidraw1", "w+b" ); def getKey(): buf = file.read(8) return keys[ord(buf[1])] while( 1 ): k = getKey(); print k file.close();
Next mission was to make the display work. My assumption was, that it will also communicate through hidraw device. So I fired dd if=/dev/urandom of=/dev/hidraw1 and YES! Time to time the display blinked or showed some messy pixel block.
So I returned back to windows. I fired up usbsnoop to see what does the original software send to update screen. I found out, that it sends many blocks in form:
0x0301XXYYZZZZZZZZZZZZZZZZZZZZZZX’s and Y’s were incrementing independently and Z’s were apparently some data. I experimented with sending 0x0301XXYYFFFFFFFFFFFFFFFFFFFFFF with various X’s and Y’s like this:
buf="0301".decode("hex")+chr(x)+chr(y)+"ffffffffffffffffffffff".decode("hex") file.write(buf)
Some of them were written to display as full black blocks and some were not. I spent some time experimenting what’s wrong after I found out, that I have to file.flush() after writing each block.
Afer this, I was able to successfully write any block on the screen. In following code you can check exactly how.
#!/usr/bin/python import struct import Image, ImageDraw, ImageFont import time keys = { 0x00 : "", 0x03 : "1", 0x09 : "2", 0x0f : "3", 0x04 : "4", 0x0a : "5", 0x10 : "6", 0x05 : "7", 0x0b : "8", 0x11 : "9", 0x06 : "*", 0x0c : "0", 0x12 : "#", 0x02 : "yes", 0x08 : "S", 0x0e : "no", 0x01 : "left", 0x13 : "up", 0x16 : "down", 0x0d : "right", 0x19 : "vol+", 0x1c : "vol-", 0x1b : "mute", } file = open( "/dev/hidraw1", "w+b" ); def getKey(): buf = file.read(8) return keys[ord(buf[1])] def paint(): pixels = img.load() # create the pixel map pixels = img.transpose(Image.ROTATE_180).load() # create the pixel map b = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] for r in range(0, 8): for s in range (0, 12): for i in range (0, 12): b[i] = 0 for j in range (0, 8): if (pixels[i + 12 * s, j + 8 * r] < 128): b[i] |= 2**j buf="0301".decode("hex")+chr(r)+chr(s*11)+chr(b[0])+chr(b[1])+chr(b[2])+chr(b[3])+chr(b[4])+chr(b[5])+chr(b[6])+chr(b[7])+chr(b[8])+chr(b[9])+chr(b[10])+chr(b[11]) file.write(buf) file.flush() def drawText(text): draw.text((0, 0), drawText.old , 255, font=font) draw.text((0, 0), text , 0, font=font) drawText.old = text paint() drawText.old = "" img = Image.new( '1', (144,64), "white") draw = ImageDraw.Draw(img) font = ImageFont.truetype("/usr/share/fonts/truetype/msttcorefonts/arial.ttf", 20) text = "" # draw logo into canvas logo = Image.open("logo.png").convert("1") img.paste(logo, (0,0)) # write canvas to display paint() # clear canvas draw.rectangle((0,0,142,63), fill=255) while( 1 ): k = getKey(); if (k == ""): 0 elif (k == "no"): text = "" drawText(text) elif (k == "yes"): text = "" drawText("calling...") else: text = text + k drawText(text) # img.show() file.close();
Note: Displays first pixel is in the lower right corner, so when displaying things, you have to rotate image 180°.
I know that all this can possibly be found in phones chip documentation but this way it was definitely more fun.
Meanwhile I stopped using VoIP services so my motivation to integrate this with some VoIP phone is gone :). Feel free to finish this and share.
To end up, I attach some photos.
This was a very interesting post. I have a similar product but without the display.
Will try to hack it and use it with internal asterisk server.
Interesting. Does it work with Android 5.0+ phones as usb headset?
I have idea to make GSM phone gate way. Check it out, you may like it.
https://github.com/axet/android-gsm-gate
Hi,
I don’t see the benefit of using Android phone. Why not use USB 3G/4G dongle with SIM?
https://github.com/bg111/asterisk-chan-dongle
Use of an Android Tablet would allow many SIP apps. A USB phone connected to the Android tablet would allow a physical handset for those that want it.