-
Notifications
You must be signed in to change notification settings - Fork 0
Home
Welcome to the openSMART wiki!
here I will try to sum up how and what I've found out.
Ok, so the first thing you should do when you are reverse engineering a USB protocol is to MITM (man in the middle) the communication between the official driver and the device. But, you don't always have your laptop with you when you want to examine some interesting device. So, why not look if the people who made the device did the right thing and tried to use generic HID stuff? The digitizer definitely works without drivers, and LEDs are in the standard, as well as buttons, and the pen IR sensors are also quite button-like for the purpose of HID communication. As for the firmware update, I suppose there's no generic way of doing that, so for this and other purposes, they would probably implement a vendor specific pipeline in the HID descriptor. If you're wondering why the computer would need to control the LEDs, remember that it's the same with keyboards. It probably makes more sense there, but it is likely based on some universally applicable principle. And, it would be cool to play with the LEDs, so I just hoped.
For getting the descriptor, I just used my android phone. It comes with a way of getting a HID descriptors, but where's the fun in that? More importantly, it was some time before I'd see the subject, so I didn't need to hurry. Anyway, I compiled, after some trial and lots of error, the true lsusb (the one in busybox sucks), and used it to dump some descriptors. You can look at the result here: https://github.com/Mis012/openSMART/blob/master/HID_descriptor_dump.txt
From the descriptor, you can see (if you manage to spot it) that there are two Report IDs. One is for something between a mouse and a touchscreen, and the other one is just towo pairs of generic 'vendor specified' 17 bytes of mystery, one for input and one for output. So, there is nothing obvious like pen tray status or LED control. We need to go deeper.
So, now we have to get something that can run the official drivers, right? Well, not so fast. We can get some additional information by just listening to the device. For this, the Linux has a useful mechanism: hidraw. It's an interface to the HID communication with the device. You can read it, you can write it, and it will take care of sending the data using USB bus. We don't know what to send, but we can still listen.
Using hexdump with a custom format string, I collected these messages from the Board:
02 c3 00 61 80 00 22 00 00 00 00 00 00 00 00 00 00 00
- this is sent all the time. Purpose unknown (for now?)
02 d2 05 10 00 c7 00 00 00 00 00 00 00 00 00 00 00 00
- first pen from the left (black) lifted
02 d2 05 00 00 d7 00 00 00 00 00 00 00 00 00 00 00 00
- any pen down
But, I expected to see the pens to be one-bit-per-pen (or eraser), so I will show you the rest in binary:
00000010 11000011 00000000 01100001 10000000 00000000 00100010 ...
- this is sent all the time.
00000010 11010010 00000101 >00000000< 00000000 11010111 00000000 ...
//ir(5)DOWN
00000010 11010010 00000101 >00000001< 00000000 11010110 00000000 ...
pen '5' UP
00000010 11010010 00000101 >00000010< 00000000 11010101 00000000 ...
pen '4' UP
00000010 11010010 00000101 >00000100< 00000000 11010011 00000000 ...
eraser '3' UP
00000010 11010010 00000101 >00001000< 00000000 11011111 00000000 ...
pen '2' UP
00000010 11010010 00000101 >00010000< 00000000 11000111 00000000 ...
pen '1' UP
| ^ reportID ^ this is it v^ checksum? |
00000010 11010010 00000110 00000001 00000000 11010101 00000000
- button '1'
^^^-- buttons 1,2,3
As you can see, we can find out if a tool was picked up. Actually, we can handle multiple tools at once (take that, official drivers). But, we still don't fully understand the protocol. What are bytes 2 and 3? byte 5? how is the checksum calculated? And how can we blink the LEDs?
This is where we need the official software, and some device to run it. So I installed Fedora LXDE on my BayTrail android tablet (the driver segfaults on lubuntu), and used the SBDiagnostics elf file.
It was actually really useful, especially if you enabled all the debug logging.
Of course, the log is in the repo: TODO
RAW DATA IN < [0x02,0xc3,0x00,0x61,0x80,0x00,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00] RAW DATA OUT > [0x02,0xe1,0x00,0x01,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
^ the mysterious message we saw earlier, it's all over the place. Probably some 'are you there, driver?'; You probably don't need to care about this unless you want the ON light to be GREEN instead of BLINKING GREEN
RAW DATA IN < [0x02,0xd2,0x05,0x08,0x00,0xdf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00] Tool change to: RED PEN, tool source 0, mid stream 0, contact index 1, force send tool change 1. RAW DATA OUT > [0x02,0xd2,0x07,0xff,0x08,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
^ so we were right about the tool signals; And guess what the OUT message is? a LED command! YAY! (and it works :D)
So, let's look at the binary representation:
00000010 11010010 00000111 11111111 00001000 00100010 00000000 ...
- LED '2' ON
| ^ report ID ^?? ^ command? ^??? ^which LED ^checksum? |
Now we can replay these messages to control the LEDs - but just one at a time. So we should try to understand the protocol. Fortunately, there is this thing and some similar ones in the log (emphasis added):
RAW DATA IN < [0x02,0xa5,0x80,0x61,0x00,0x04, 0x16,0x2b ,0x7d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00] Firmware application checksum 0x162b RAW DATA IN < [0x02,0x96,0x80,0x61,0x00,0x05, 0x01,0x01,0x03, 0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00] Firmware boot version 1.1.3.0 RAW DATA IN < [0x02,0xa5,0x80,0x61,0x00,0x06, 0x70,0x47, 0x75,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00] Firmware boot checksum 0x7047
So, the last byte is probably checksum, and before that is variable length data. The 0x80,0x61 is weird.
But hold on! What is the second byte?
Well, if there's any byte count, it's this. And, it seems to be the same for same byte count. But it's somehow encrypted, because ... 0xa5 > 0x96, so ... reverse the nibbles? 0x5a is 90, and 0x69 is 105. 105 > 90, That's good. 105 - 90 is 15, that is 1*15 per byte. So divide by 15?
90/15 = 6; 105/15 = 7. That is the byte count from third byte up excluding checksum. And it actually works on every message I tried. YAY!
So, now we can look back at the messages from the start:
|reportID|| b-count|| data ||checksum|| padding ... 00000010 11010010 00000101 00000000 00000000 11010111 00000000 ...
|command | tools | ??? |
So, that's all for now. Thanks for reading :)