Help me reverse-engineer some bitstrings
January 19, 2012 12:56 AM
Hackers of MeFi, assemble! I have an undocumented serial protocol I want to reverse engineer - help me turn some mysterious bit strings into meaningful data.
I recently bought a V-Fit 10kpt treadmill for use in a treadmill desk arrangement, which is working out well. Like most treadmills it has a fairly rubbish interface on a control unit; the control unit talks to the treadmill itself over a single-wire serial protocol, which I've reverse-engineered enough to replace the control unit with my own microprocessor + desktop application.
So far so good, but my solution involves capturing the serial traffic at a given speed as a bit sequence and then playing that bit sequence back to set that speed on the treadmill. I'm like the man in the chinese room experiment.
This is where you, the good people of ask metafilter, come in; can you help me turn these meaningless bits into comprehensible data?
At a given speed the device plays out a 120 bit sequence at 1200 baud, repeated every 7.2 milliseconds; here is an example bit sequence (this is a recording of the logic levels on the wire with no further processing). Each of these 120 bit sequences is a speed command.
It turns out that every command starts with 0x0b 0x30 0x83 0x02 0x30, and ends with 0x13, so I'll leave those off from now on; from there we have one special command, played when the device is stopped:
Over to you, metafilter; thanks!
I recently bought a V-Fit 10kpt treadmill for use in a treadmill desk arrangement, which is working out well. Like most treadmills it has a fairly rubbish interface on a control unit; the control unit talks to the treadmill itself over a single-wire serial protocol, which I've reverse-engineered enough to replace the control unit with my own microprocessor + desktop application.
So far so good, but my solution involves capturing the serial traffic at a given speed as a bit sequence and then playing that bit sequence back to set that speed on the treadmill. I'm like the man in the chinese room experiment.
This is where you, the good people of ask metafilter, come in; can you help me turn these meaningless bits into comprehensible data?
At a given speed the device plays out a 120 bit sequence at 1200 baud, repeated every 7.2 milliseconds; here is an example bit sequence (this is a recording of the logic levels on the wire with no further processing). Each of these 120 bit sequences is a speed command.
bin: 00001011 00110000 10000011 00000010 00110000 01010111 00000000 01110100 00111111 00000000 01110001 01000111 01011011 00110110 00010011 hex: 0x0b 0x30 0x83 0x02 0x30 0x57 0x00 0x74 0x3f 0x00 0x71 0x47 0x5b 0x36 0x13I've broken this into bytes as its length is divisible by 8, and I can't see any obvious pattern of start and stop bits like you'd get in normal RS232.
It turns out that every command starts with 0x0b 0x30 0x83 0x02 0x30, and ends with 0x13, so I'll leave those off from now on; from there we have one special command, played when the device is stopped:
stop (bin): 00000111 00000000 01110000 00000111 00000000 01110001 01000111 00011110 01110110 stop (hex): 0x7 0x0 0x70 0x7 0x0 0x71 0x47 0x1e 0x76and then at least 96 speed commands, going from 0.5kph to 10kph in 0.1kph increments. Every speed command is prefixed with 0x57, presumably identifying it as a speed, followed by 3 variable bytes, followed by 0x00 0x71 0x47, followed by two variable bytes whose final nibble is always 6. Here are some examples (leading 0x57 omitted):
0.5kph 00000000 01110100 00111111 00000000 01110001 01000111 01011011 00110110 0x0 0x74 0x3f 0x0 0x71 0x47 0x5b 0x36 0.6kph 01000000 00110011 10000011 00000000 01110001 01000111 01101100 10110110 0x40 0x33 0x83 0x0 0x71 0x47 0x6c 0xb6 0.7kph 01000000 00110110 11100011 00000000 01110001 01000111 00001001 10110110 0x40 0x36 0xe3 0x0 0x71 0x47 0x9 0xb6 0.8kph 01000000 00110000 10110011 00000000 01110001 01000111 01010111 11110110 0x40 0x30 0xb3 0x0 0x71 0x47 0x57 0xf6 0.9kph 01000000 00110101 01001111 00000000 01110001 01000111 00100010 01110110 0x40 0x35 0x4f 0x0 0x71 0x47 0x22 0x76 1.0kph 01000000 00110010 00011011 00000000 01110001 01000111 01111001 00110110 0x40 0x32 0x1b 0x0 0x71 0x47 0x79 0x36 1.1kph 01000000 00110111 10111011 00000000 01110001 01000111 00011111 00110110 0x40 0x37 0xbb 0x0 0x71 0x47 0x1f 0x36 1.2kph 00100000 00110001 11000011 00000000 01110001 01000111 00101010 11110110 0x20 0x31 0xc3 0x0 0x71 0x47 0x2a 0xf6 ... 9.9kph 01000100 01110110 10110011 00000000 01110001 01000111 00001000 00110110 0x44 0x76 0xb3 0x0 0x71 0x47 0x8 0x36 10kph 01000100 01110000 11001011 00000000 01110001 01000111 01010110 01110110 0x44 0x70 0xcb 0x0 0x71 0x47 0x56 0x76My guesses so far on speed command format are:
- First 3 bytes could be a 24-bit floating point; they are not lexically ordered against speed which fits this possibility
- Final two bytes could be a checksum of some sort; the device has lots of ambient EMF because of the motor, and it would be bad if a few bit errors could stop the belt or run it at 10kph suddenly
- Middle bytes are just a separator, maybe again to provide some bit error / timing error stability
Over to you, metafilter; thanks!
Can you post the complete list of speed commands to pastebin or similar? Unlabeled raw data is fine.
posted by anon_for_this at 3:49 AM on January 19, 2012
posted by anon_for_this at 3:49 AM on January 19, 2012
bit 0: low
bit 1 - 10: data + parity
bit 11 - 13: high
posted by anon_for_this at 4:52 AM on January 19, 2012
bit 1 - 10: data + parity
bit 11 - 13: high
posted by anon_for_this at 4:52 AM on January 19, 2012
The speed of the V-Fit 10KPT treadmill varies between 1.0 and 10.0 km/h. The different speed settings are easily changeable. Also, the V-Fit 10KPT treadmill comes with a manually adjusted decline that can be set to three different positions up to a maximum of 7%.So no incline settings, but there are different speed programs.
For safety reasons the V-Fit 10KPT comes with a magnetic auto stop system.
Other features include an LCD exercise monitor (that comes with calorie, distance and time settings amongst others), three different pre selected speed programs and a shock absorbing design.
posted by zamboni at 6:38 AM on January 19, 2012
Based on the provided data and the protocol I posted above, this is the data format:
byte 4: upper speed component
byte 5: middle speed component
byte 8: lower speed component
Here is the byte stream decoded per the protocol I posted earlier. The serial line is pulled down for one clock cycle, 8 bytes are sent in little endian order, a parity bit is sent, then the line is release for two clock cycles:
(desired kph - 0.5) * 450 + 225
For example 20kph would be about 0x2328.
posted by anon_for_this at 6:43 AM on January 19, 2012
byte 4: upper speed component
byte 5: middle speed component
byte 8: lower speed component
Here is the byte stream decoded per the protocol I posted earlier. The serial line is pulled down for one clock cycle, 8 bytes are sent in little endian order, a parity bit is sent, then the line is release for two clock cycles:
byte 4 byte 5 byte 8 xxxxxxxx- xxxxxxxx- xxxxxxxx- 0.5kph 0 000101100 11 0 000100000 11 0 000001000 11 0 000010101 11 0 000000001 11 0 100001111 11 0 000000001 11 0 001010001 11 0 101101100 11 0 110000100 11 0.6kph 0 000101100 11 0 000100000 11 0 000001000 11 0 000010101 11 0 100000000 11 0 011100000 11 0 000000001 11 0 001010001 11 0 110110010 11 0 110000100 11 0.7kph 0 000101100 11 0 000100000 11 0 000001000 11 0 000010101 11 0 100000000 11 0 110111000 11 0 000000001 11 0 001010001 11 0 000100110 11 0 110000100 11 0.8kph 0 000101100 11 0 000100000 11 0 000001000 11 0 000010101 11 0 100000000 11 0 000101100 11 0 000000001 11 0 001010001 11 0 101011111 11 0 110000100 11 0.9kph 0 000101100 11 0 000100000 11 0 000001000 11 0 000010101 11 0 100000000 11 0 101010011 11 0 000000001 11 0 001010001 11 0 010001001 11 0 110000100 11 1.0kph 0 000101100 11 0 000100000 11 0 000001000 11 0 000010101 11 0 100000000 11 0 010000110 11 0 000000001 11 0 001010001 11 0 111100100 11 0 110000100 11 1.1kph 0 000101100 11 0 000100000 11 0 000001000 11 0 000010101 11 0 100000000 11 0 111101110 11 0 000000001 11 0 001010001 11 0 001111100 11 0 110000100 11 1.2kph 0 000101100 11 0 000100000 11 0 000001000 11 0 000010101 11 0 010000000 11 0 001110000 11 0 000000001 11 0 001010001 11 0 010101011 11 0 110000100 11 9.9kph 0 000101100 11 0 000100000 11 0 000001000 11 0 000010101 11 0 100010001 11 0 110101100 11 0 000000001 11 0 001010001 11 0 000100000 11 0 110000100 11 10.kph 0 000101100 11 0 000100000 11 0 000001000 11 0 000010101 11 0 100010001 11 0 000110010 11 0 000000001 11 0 001010001 11 0 101011001 11 0 110000100 11When you combine the upper speed component (byte 4) and middle speed component (byte 5) you get an increasing number. byte 7 is presumably just a minor component added to that number. Here is byte 4 and 5 shown in hex:
byte 4: byte 5: 00000000 10000111 0x00E1 10000000 01110000 0x010E 10000000 11011100 0x013B 10000000 00010110 0x0168 10000000 10101001 0x0195 10000000 01000011 0x01C2 10000000 11110111 0x01EF 01000000 00111000 0x021C 10001000 11010110 0x116B 10001000 00011001 0x1198The numbers are monotonically increasing by a factor of 0x2D, so you can control the treadmill by specifying different numbers in byte positions 4 and 5. The desired speed formula is:
(desired kph - 0.5) * 450 + 225
For example 20kph would be about 0x2328.
posted by anon_for_this at 6:43 AM on January 19, 2012
I meant to say 8 *bits* are sent in little endian order. And the minor speed component is byte 8, not 7.
posted by anon_for_this at 6:45 AM on January 19, 2012
posted by anon_for_this at 6:45 AM on January 19, 2012
Excellent stuff, thanks very much anon_for_this; sorry for the delay / lack of feedback, I posted before going to work, UK time.
I will get to implementing this later on, it's always nice to replace a large table of constants with a small function. Will find out what byte 8 does and get back to you as well.
posted by larkery at 8:48 AM on January 19, 2012
I will get to implementing this later on, it's always nice to replace a large table of constants with a small function. Will find out what byte 8 does and get back to you as well.
posted by larkery at 8:48 AM on January 19, 2012
OK, one implementation implemented - the method works, but byte 3 has to have the correct value to work, so it's not just some fine control byte but is another check byte of some kind.
If anyone fancies a look, here are the triplets of values; what is connecting 'em?
posted by larkery at 10:37 AM on January 19, 2012
If anyone fancies a look, here are the triplets of values; what is connecting 'em?
0x0 0x0 0x3c ------------- 0x0 0xe1 0x6d 0x1 0xe 0x9b 0x1 0x3b 0xc8 0x1 0x68 0xf5 0x1 0x95 0x22 0x1 0xc2 0x4f 0x1 0xef 0x7c 0x2 0x1c 0xaa 0x2 0x49 0xd7 0x2 0x76 0x4 0x2 0xa3 0x31 0x2 0xd0 0x5e 0x2 0xfd 0x8b 0x3 0x2a 0xb9 0x3 0x57 0xe6 0x3 0x84 0x13 0x3 0xb1 0x40 0x3 0xdf 0x6e 0x4 0xc 0x9c 0x4 0x39 0xc9 0x4 0x66 0xf6 0x4 0x93 0x23 0x4 0xc0 0x50 0x4 0xed 0x7d 0x5 0x1a 0xab 0x5 0x47 0xd8 0x5 0x74 0x5 0x5 0xa1 0x32 0x5 0xce 0x5f 0x5 0xfb 0x8c 0x6 0x28 0xba 0x6 0x55 0xe7 0x6 0x82 0x14 0x6 0xaf 0x41 0x6 0xdc 0x6e 0x7 0x9 0x9c 0x7 0x36 0xc9 0x7 0x63 0xf6 0x7 0x90 0x23 0x7 0xbe 0x51 0x7 0xeb 0x7e 0x8 0x18 0xac 0x8 0x45 0xd9 0x8 0x72 0x6 0x8 0x9f 0x33 0x8 0xcc 0x60 0x8 0xf9 0x8d 0x9 0x26 0xbb 0x9 0x53 0xe8 0x9 0x80 0x15 0x9 0xad 0x42 0x9 0xda 0x6f 0xa 0x7 0x9d 0xa 0x34 0xca 0xa 0x61 0xf7 0xa 0x8e 0x24 0xa 0xbb 0x51 0xa 0xe8 0x7e 0xb 0x15 0xac 0xb 0x42 0xd9 0xb 0x6f 0x6 0xb 0x9d 0x34 0xb 0xca 0x61 0xb 0xf7 0x8e 0xc 0x24 0xbc 0xc 0x51 0xe9 0xc 0x7e 0x16 0xc 0xab 0x43 0xc 0xd8 0x70 0xd 0x5 0x9e 0xd 0x32 0xcb 0xd 0x5f 0xf8 0xd 0x8c 0x25 0xd 0xb9 0x52 0xd 0xe6 0x7f 0xe 0x13 0xad 0xe 0x40 0xda 0xe 0x6d 0x7 0xe 0x9a 0x34 0xe 0xc7 0x61 0xe 0xf4 0x8e 0xf 0x21 0xbc 0xf 0x4e 0xe9 0xf 0x7c 0x17 0xf 0xa9 0x44 0xf 0xd6 0x71 0x10 0x3 0x9f 0x10 0x30 0xcc 0x10 0x5d 0xf9 0x10 0x8a 0x26 0x10 0xb7 0x53 0x10 0xe4 0x80 0x11 0x11 0xae 0x11 0x3e 0xdb 0x11 0x6b 0x8 0x11 0x98 0x35
posted by larkery at 10:37 AM on January 19, 2012
So it's async serial 8-odd-2. That's an odd setting but many UARTs should handle it. The ATmega8 USART can, at any rate.
1/450 km/hour is a weird unit; maybe it's just an internal encoder count? It's kind of close to being miles/hour in a fixed-point-binary representation (mph + mph/256), but not quite.
Just guessing, but does byte 8 make the mod-256 sum of the other bytes (including 6 and 7) come out to 0?
posted by hattifattener at 10:46 AM on January 19, 2012
1/450 km/hour is a weird unit; maybe it's just an internal encoder count? It's kind of close to being miles/hour in a fixed-point-binary representation (mph + mph/256), but not quite.
Just guessing, but does byte 8 make the mod-256 sum of the other bytes (including 6 and 7) come out to 0?
posted by hattifattener at 10:46 AM on January 19, 2012
(Er, if you negate it, I guess. At any rate, in those triples, A+B-C=116 mod 256.)
posted by hattifattener at 10:55 AM on January 19, 2012
posted by hattifattener at 10:55 AM on January 19, 2012
That's the one; just figured that myself. Cheers everyone - question resolved entirely.
I expect the units are just something like PWM mark/space ratio; the motor controller is probably PWM, but I haven't investigated further than trying to download the program off it as it has big fat cables which exceed my RDA of volts & amps.
posted by larkery at 11:51 AM on January 19, 2012
I expect the units are just something like PWM mark/space ratio; the motor controller is probably PWM, but I haven't investigated further than trying to download the program off it as it has big fat cables which exceed my RDA of volts & amps.
posted by larkery at 11:51 AM on January 19, 2012
For the record, the check byte is just the sum of bits 2-8 of the message sent (mod 255), which is typically 0x08 + 0x20 + (control = 0x50 or 0x0) + speed 1 + speed 2 + 0x0 + 0x14.
posted by larkery at 1:25 AM on January 20, 2012
posted by larkery at 1:25 AM on January 20, 2012
« Older Help me find more information about Orange Bowl... | Eliminating my dream job based on vision concerns? Newer »
This thread is closed to new comments.
posted by BigCalm at 3:13 AM on January 19, 2012