mirror of https://github.com/commaai/panda.git
140 lines
4.2 KiB
Python
140 lines
4.2 KiB
Python
|
# python library to interface with panda
|
||
|
import struct
|
||
|
|
||
|
import usb1
|
||
|
from usb1 import USBErrorIO, USBErrorOverflow
|
||
|
|
||
|
class Panda(object):
|
||
|
def __init__(self, serial=None, claim=True):
|
||
|
context = usb1.USBContext()
|
||
|
|
||
|
self.handle = None
|
||
|
for device in context.getDeviceList(skip_on_error=True):
|
||
|
if device.getVendorID() == 0xbbaa and device.getProductID() == 0xddcc:
|
||
|
if serial is None or device.getSerialNumber() == serial:
|
||
|
print "opening device", device.getSerialNumber()
|
||
|
self.handle = device.open()
|
||
|
if claim:
|
||
|
self.handle.claimInterface(0)
|
||
|
break
|
||
|
|
||
|
assert self.handle != None
|
||
|
|
||
|
@staticmethod
|
||
|
def list():
|
||
|
context = usb1.USBContext()
|
||
|
ret = []
|
||
|
for device in context.getDeviceList(skip_on_error=True):
|
||
|
if device.getVendorID() == 0xbbaa and device.getProductID() == 0xddcc:
|
||
|
ret.append(device.getSerialNumber())
|
||
|
return ret
|
||
|
|
||
|
# ******************* health *******************
|
||
|
|
||
|
def health(self):
|
||
|
dat = self.handle.controlRead(usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE, 0xd2, 0, 0, 0x20)
|
||
|
a = struct.unpack("IIBBBBB", dat)
|
||
|
return {"voltage": a[0], "current": a[1],
|
||
|
"started": a[2], "controls_allowed": a[3],
|
||
|
"gas_interceptor_detected": a[4],
|
||
|
"started_signal_detected": a[5],
|
||
|
"started_alt": a[6]}
|
||
|
|
||
|
# ******************* can *******************
|
||
|
|
||
|
def set_gmlan(self, on):
|
||
|
if on:
|
||
|
self.handle.controlWrite(usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE, 0xdb, 1, 0, '')
|
||
|
else:
|
||
|
self.handle.controlWrite(usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE, 0xdb, 0, 0, '')
|
||
|
|
||
|
def can_send_many(self, arr):
|
||
|
snds = []
|
||
|
for addr, _, dat, bus in arr:
|
||
|
snd = struct.pack("II", ((addr << 21) | 1), len(dat) | (bus << 4)) + dat
|
||
|
snd = snd.ljust(0x10, '\x00')
|
||
|
snds.append(snd)
|
||
|
|
||
|
while 1:
|
||
|
try:
|
||
|
self.handle.bulkWrite(3, ''.join(snds))
|
||
|
break
|
||
|
except (USBErrorIO, USBErrorOverflow):
|
||
|
print "CAN: BAD SEND MANY, RETRYING"
|
||
|
|
||
|
def can_send(self, addr, dat, bus):
|
||
|
self.can_send_many([[addr, None, dat, bus]])
|
||
|
|
||
|
def can_recv(self):
|
||
|
def __parse_can_buffer(dat):
|
||
|
ret = []
|
||
|
for j in range(0, len(dat), 0x10):
|
||
|
ddat = dat[j:j+0x10]
|
||
|
f1, f2 = struct.unpack("II", ddat[0:8])
|
||
|
ret.append((f1 >> 21, f2>>16, ddat[8:8+(f2&0xF)], (f2>>4)&0xf))
|
||
|
return ret
|
||
|
dat = ""
|
||
|
while 1:
|
||
|
try:
|
||
|
dat = self.handle.bulkRead(1, 0x10*256)
|
||
|
break
|
||
|
except (USBErrorIO, USBErrorOverflow):
|
||
|
print "CAN: BAD RECV, RETRYING"
|
||
|
return __parse_can_buffer(dat)
|
||
|
|
||
|
# ******************* serial *******************
|
||
|
|
||
|
def serial_read(self, port_number):
|
||
|
return self.handle.controlRead(usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE, 0xe0, port_number, 0, 0x100)
|
||
|
|
||
|
def serial_write(self, port_number):
|
||
|
return self.handle.bulkWrite(2, chr(port_number) + ln)
|
||
|
|
||
|
# ******************* kline *******************
|
||
|
|
||
|
# pulse low for wakeup
|
||
|
def kline_wakeup(self):
|
||
|
ret = self.handle.controlWrite(usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE, 0xf0, 0, 0, "")
|
||
|
|
||
|
def kline_drain(self, bus=2):
|
||
|
# drain buffer
|
||
|
bret = ""
|
||
|
while 1:
|
||
|
ret = self.handle.controlRead(usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE, 0xe0, bus, 0, 0x100)
|
||
|
if len(ret) == 0:
|
||
|
break
|
||
|
bret += str(ret)
|
||
|
return bret
|
||
|
|
||
|
def kline_ll_recv(self, cnt, bus=2):
|
||
|
echo = ""
|
||
|
while len(echo) != cnt:
|
||
|
echo += str(self.handle.controlRead(usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE, 0xe0, bus, 0, cnt-len(echo)))
|
||
|
return echo
|
||
|
|
||
|
def kline_send(self, x, bus=2, checksum=True):
|
||
|
def get_checksum(dat):
|
||
|
result = 0
|
||
|
result += sum(map(ord, dat))
|
||
|
result = -result
|
||
|
return chr(result&0xFF)
|
||
|
|
||
|
self.kline_drain(bus=bus)
|
||
|
if checksum:
|
||
|
x += get_checksum(x)
|
||
|
for i in range(0, len(x), 0x10):
|
||
|
ts = x[i:i+0x10]
|
||
|
self.handle.bulkWrite(2, chr(bus)+ts)
|
||
|
echo = self.kline_ll_recv(len(ts), bus=bus)
|
||
|
if echo != ts:
|
||
|
print "**** ECHO ERROR %d ****" % i
|
||
|
print echo.encode("hex")
|
||
|
print ts.encode("hex")
|
||
|
assert echo == ts
|
||
|
|
||
|
def kline_recv(self, bus=2):
|
||
|
msg = self.kline_ll_recv(2, bus=bus)
|
||
|
msg += self.kline_ll_recv(ord(msg[1])-2, bus=bus)
|
||
|
return msg
|
||
|
|