-
Notifications
You must be signed in to change notification settings - Fork 0
/
steps.txt
116 lines (58 loc) · 5.13 KB
/
steps.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
2022-02-18
I connected the srs programmer to a servo through a splitter cable and connected the signal and ground to my logic analyzer
I saw that whenever I press one of the interesting buttons (LEFT, PROGRAM, RIGHT in programming mode), I get a packet.
I determined that the width of each bit is 13us, so I decoded the bits by hand with excel.
I realized that each packet is made of a 10 bit frame with the first bit always 0 and the last always 1.
Knowing this, I felt I was finally able to write a program that decodes the packets automatically from an export capture.
After doing a sequence of {RIGHT (success), LEFT (success), PROGRAM (success)} I got dump1.txt.
There I saw that every packet starts with FF FF and then 7F if the packet is from the programmer or 80 if it's from the servo
I also saw that the packet sent when LEFT or RIGHT are pressed are the same.
I did another dump of the same sequence but setting different limits (dump2.txt) and ran a diff.
I found some differences in the big packet sent to the programmer when PROGRAM is pressed.
More notably, I found that the last 3 bits of the response to RIGHT/LEFT changed, which probably means they contain the servo's position.
2022-04-24
I figured out that the protocol is UART, which means that it's probably LSB first. So 0xFE instead of 0x7F and 0x01 instead of 0x80
Setting the buad rate to 77170, I was now able to extract bytes directly from logic
analyzing uart_dump1, i saw the biggest number was 0x0003FFF8 which means the value returned is 18 bits
This is a bit too high, which leads me to believe the last byte is actually a checksum
After a bit of trial and error I arrived at the formula (~sum(bytes[2:-1]))&0xFF for the checksum byte
2022-04-25
To be able to communicate between my pc and the servo, I connected a CP210 serial to usb adapter to the servo as shown in cp210-wiring.png
At first, I created plot_angle.py, which plots the adc value returned by the servo
It worked pretty well, but if the delay was less than 400ms, the servo would sometimes interpret the data as PWM and spin a little
I also noticed that at some point above 1023, the value returned keeps rising. This is probably due to the small disconnected area in the potentiometer
When the servo is at the zero point, it reports a number around 512
After that I tried sending the PROGRAM button and only got a single packet in response.
I sent the next packet in the transmission and also got a single packet
This means that the 0x01 doesn't mean SRS to programmer as I thought. It probably doesn't have a meaning beyond "a button has been pressed"
Looking at the diff of different PROGRAM sequences, I found that only a pair of 2 bytes is changed each time.
When a factory reset is issued, both of these numbers are set to 1000
The next idea I had was to make the CP210 act as an SRS, to precisely control the adc values
I had some trouble getting it to work but finally I got the communication working after connecting a 10KOhm pull-down resistor to RX of the CP210
With some trail and error, I found out the (65<=LEFT<=411) and (611<=RIGHT<=965) (returned 1000,1000)
Assuming the correlation is linear, I plotted a function from the 2 dots and extrapolated different values, all of which were true!
The function for LEFT is: y-1000=(1000-232)/(65-411)*(x-65)
The function for RIGHT is: y-1000=(1000-213)/(965-611)*(x-965)
Knowing that, I was able to write programmer.py, a PoC SRS-Programmer
After some tests, I found out the 611 and 411 limits are arbitrary, you can set angles as small as 1!
2022-04-26
Setting the servo to continuous mode and then back to servo, I noticed one of the bits of the 2nd PROGRAM message would flip
This bit means the current state, 0 for servo and 1 for continuous
The other command that changed was the long one, I copied it as is to programmer.py and it worked
2022-04-27
I wanted to go a bit deeper, so I layed out all the known packets in a file packets.txt and looked for patterns
After a bit of hypothesizing, I arrived at a generic request structure:
FF FF {FE or 01} {packet length (everything to the right)} {02 read or 03 write or 01} {packet} {checksum}
From that I wrote brute_force.py, which brute forced reading with every possible value
I saw that the length of the response packet was always equal to the second modifiable byte
From that I inferred that the first byte is an address and the second one is how much to read from that address
I wrote another iteration of brute_force.py and I got the same bytes in every packet but shifted each time
This means that the first byte is indeed an address for sequential bytes
From the pattern, I was able to determine that the entire memory space is 68 bytes, so It's probably 64 since that's a power of two
After reading the entire memory, I immediately recognized a big chunk of it. It's the PROGRAM values!
Thus I arrived at a new theory. I separated the packets into two types, read and write
read: {address} {length}
write: {address} {byte 0} ... {byte n}
note: this is only the {packet} part
Knowing that, the long sequence in PROGRAM writes values to address 6. Which is indeed what I see in the memory!
It's all coming together :-)