diff --git a/__init__.py b/__init__.py index 1f72be4f9..239867118 100644 --- a/__init__.py +++ b/__init__.py @@ -1 +1 @@ -from .panda import Panda, PandaWifiStreaming +from .panda import Panda, PandaWifiStreaming, PandaDFU diff --git a/panda/__init__.py b/panda/__init__.py index 97e1edd6e..4cb8e6a46 100644 --- a/panda/__init__.py +++ b/panda/__init__.py @@ -13,6 +13,89 @@ __version__ = '0.0.3' BASEDIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../") +# *** DFU mode *** + +DFU_DNLOAD = 1 +DFU_UPLOAD = 2 +DFU_GETSTATUS = 3 +DFU_CLRSTATUS = 4 +DFU_ABORT = 6 + +class PandaDFU(object): + def __init__(self, dfu_serial): + context = usb1.USBContext() + for device in context.getDeviceList(skip_on_error=True): + if device.getVendorID() == 0x0483 and device.getProductID() == 0xdf11: + try: + this_dfu_serial = device._getASCIIStringDescriptor(3) + except Exception: + pass + if this_dfu_serial == dfu_serial: + self._handle = device.open() + return + raise Exception("failed to open "+dfu_serial) + + @staticmethod + def list(): + context = usb1.USBContext() + dfu_serials = [] + for device in context.getDeviceList(skip_on_error=True): + if device.getVendorID() == 0x0483 and device.getProductID() == 0xdf11: + try: + dfu_serials.append(device._getASCIIStringDescriptor(3)) + except Exception: + pass + return dfu_serials + + @staticmethod + def st_serial_to_dfu_serial(st): + uid_base = struct.unpack("H"*6, st.decode("hex")) + return struct.pack("!HHH", uid_base[1] + uid_base[5], uid_base[0] + uid_base[4] + 0xA, uid_base[3]).encode("hex").upper() + + + def status(self): + while 1: + dat = str(self._handle.controlRead(0x21, DFU_GETSTATUS, 0, 0, 6)) + if dat[1] == "\x00": + break + + def clear_status(self): + # Clear status + stat = str(self._handle.controlRead(0x21, DFU_GETSTATUS, 0, 0, 6)) + if stat[4] == "\x0a": + self._handle.controlRead(0x21, DFU_CLRSTATUS, 0, 0, 0) + elif stat[4] == "\x09": + self._handle.controlWrite(0x21, DFU_ABORT, 0, 0, "") + self.status() + stat = str(self._handle.controlRead(0x21, DFU_GETSTATUS, 0, 0, 6)) + + def erase(self, address): + self._handle.controlWrite(0x21, DFU_DNLOAD, 0, 0, "\x41" + struct.pack("I", address)) + self.status() + + def program(self, address, dat, block_size): + # Set Address Pointer + self._handle.controlWrite(0x21, DFU_DNLOAD, 0, 0, "\x21" + struct.pack("I", address)) + self.status() + + # Program + dat += "\xFF"*((block_size-len(dat)) % block_size) + for i in range(0, len(dat)/block_size): + ldat = dat[i*block_size:(i+1)*block_size] + print("programming %d with length %d" % (i, len(ldat))) + self._handle.controlWrite(0x21, DFU_DNLOAD, 2+i, 0, ldat) + self.status() + + def reset(self): + # **** Reset **** + self._handle.controlWrite(0x21, DFU_DNLOAD, 0, 0, "\x21" + struct.pack("I", 0x8000000)) + self.status() + self._handle.controlWrite(0x21, DFU_DNLOAD, 2, 0, "") + stat = str(self._handle.controlRead(0x21, DFU_GETSTATUS, 0, 0, 6)) + + +# *** wifi mode *** + def parse_can_buffer(dat): ret = [] for j in range(0, len(dat), 0x10): @@ -82,6 +165,8 @@ class WifiHandle(object): def close(self): self.sock.close() +# *** normal mode *** + class Panda(object): SAFETY_NOOUTPUT = 0 SAFETY_HONDA = 1 @@ -427,3 +512,4 @@ class Panda(object): msg = self.kline_ll_recv(2, bus=bus) msg += self.kline_ll_recv(ord(msg[1])-2, bus=bus) return msg + diff --git a/release/.gitignore b/release/.gitignore new file mode 100644 index 000000000..c4c4ffc6a --- /dev/null +++ b/release/.gitignore @@ -0,0 +1 @@ +*.zip