10. Command #1 & 2 - LED blinky!
我们会编写发送命令#1的python代码,来观察会发生什么。从我们的日志中,我们知道发送命令是从host-to-device, 我们应该设置bRequestType值为0x40 (验证这个值,可以查看the bmRequestType bits of the command packets), wIndex and wLength of zero
For command #1, set bRequest to 0x06 and a wValue to 0x4. 最后一个参数是一个空数组[ ],表示没有数据传输。
ret = dev.ctrl_transfer(0x40, 0x6, 0x4, 0, [])
我们运行Python代码,结果....什么都没发生!
也许这只是一个初始化的命令。Lets replace it with the next command #2, set bRequest to 0x06 and a wValue to 0x1
ret = dev.ctrl_transfer(0x40, 0x6, 0x1, 0, [])
import usb.core
import usb.util
import sys
# find our device
dev = usb.core.find(idVendor=0x045e, idProduct=0x02B0)
# was it found?
if dev is None:
raise ValueError('Device not found')
# set the active configuration. With no arguments, the first
# configuration will be the active one
dev.set_configuration()
ret = dev.ctrl_transfer(0x40, 0x6, 0x1, 0, [])
print ret
我们运行这个命令,马达还是没有转动,但是LED灯却停止了闪烁。
为了好玩,我们再次运行之前的命令,结果LED灯又开始闪烁了。
现在我们有了一个想法:也许bRequest 0x6 用于控制LED灯。
On your own, continue this line of thought by trying different wValues from 0 on up to see what other wValues do, keep track of them all in a notebook or project file.
11. Command #3 &4 - Let's move!
在上一节里,我们已经征服了一个命令。现在,我们将征服另一个命令。Try to replicate command #3, set bRequest to 0x31 and a wValue to 0xffd0 (also known as -48 for a 2-byte word)
ret = dev.ctrl_transfer(0x40, 0x31, 0xffd0, 0, [])
运行Python脚本,the motor move its 'head' down.
Now try command #4, wValue to 0xfff0 (also known as -16 for a 2-byte word)
ret = dev.ctrl_transfer(0x40, 0x31, 0xfff0, 0, [])
This makes the head move up.
现在,马达和LED都在我们的控制之下了。 Here is a video we shot a few minutes after getting the motor working, using a python script to move it up and down.(译者:视频见原文)
12. Bonus accelerometer!(奖金冲刺)
我们回来重温下这个神秘的读取命令0x31,这个命令我们还有一点模糊。它也在日志里,一定要确认set your filter to show both Host-to-Device and Device-to-Host since its a 'read' not a 'write'
We were pretty close with our commands, 看起来我们应该读取的只有10个字节。It also looks like the data doesn't really change much except for a bit further down…
在我们发送了命令bRequest 0x31 (motor movement)之后,第七个字节改变了很多次。That implies that this data read is somehow affected by the motor, 可能是马达反馈字节?
Checking out a tear-down of the device (from iFixit) we see that there is an 'inclinometer'/accelerometer (Kionix KXSD9). The datasheet indicates it is used for image stabilization, and it has 3 axes (X Y and Z) with 10 bits of data per axis.
让我们持续不断的读取数据.
import usb.core
import usb.util
import sys
import time
# find our device
dev = usb.core.find(idVendor=0x045e, idProduct=0x02B0)
# was it found?
if dev is None:
raise ValueError('Device not found')
dev.set_configuration()
while True:
# Get data from brequest 0x31
ret = dev.ctrl_transfer(0xC0, 0x31, 0x0, 0x0, 10)
print map(hex, ret)
晃动Kinect的同时运行脚本,你会清楚的看到,这个数据的变化与运动有关。
To identify the accelerometer axes, rotate it only one way at a time and note what changes. You can also see how this data is in bytes but the accelerometer data should be a signed word because there are flips from 0xfff7 to 0x0007 which would indicate a negative to positive conversion.
We can cast two bytes to a signed value by 'hand' (in C this is a little easier, we know)
import usb.core
import usb.util
import sys
import time
# find our device
dev = usb.core.find(idVendor=0x045e, idProduct=0x02B0)
# was it found?
if dev is None:
raise ValueError('Device not found')
dev.set_configuration()
while True:
# Get data from brequest 0x31
ret = dev.ctrl_transfer(0xC0, 0x31, 0x0, 0x0, 10)
#print map(hex, ret)
x = (ret[2] << 8) | ret[3]
x = (x + 2 ** 15) % 2**16 - 2**15 # convert to signed 16b
y = (ret[4] << 8) | ret[5]
y = (y + 2 ** 15) % 2**16 - 2**15 # convert to signed 16b
z = (ret[6] << 8) | ret[7]
z = (z + 2 ** 15) % 2**16 - 2**15 # convert to signed 16b
print x, "\t", y, "\t", z
现在,当我们运行脚本,已经可以看到有符号的数据显示正常了。
13. More Kinect!
We hope you enjoyed this reverse-engineering tutorial. For more information about Open Kinect, please visit the github repository and google group