Merge pull request #13 from diamondman/usb_bulk_to_interrupt

Usb bulk to interrupt
This commit is contained in:
George Hotz 2017-06-21 09:19:10 -07:00 committed by GitHub
commit 47a1329e9e
2 changed files with 116 additions and 62 deletions

View File

@ -128,29 +128,49 @@ uint8_t device_desc[] = {
uint8_t configuration_desc[] = {
DSCR_CONFIG_LEN, DSCR_CONFIG_TYPE, // Length, Type,
0x27, 0x00, // Total Len (uint16)
TOUSBORDER(0x0045), // Total Len (uint16)
0x01, 0x01, 0x00, // Num Interface, Config Value, Configuration
0xc0, 0x32, // Attributes, Max Power
// interface 0
// interface 0 ALT 0
DSCR_INTERFACE_LEN, DSCR_INTERFACE_TYPE, // Length, Type
0x00, 0x00, 0x03, // Index, Alt Index idx, Endpoint count
0xff, 0xFF, 0xFF, // Class, Subclass, Protocol
0XFF, 0xFF, 0xFF, // Class, Subclass, Protocol
0x00, // Interface
// endpoint 1, read CAN
DSCR_ENDPOINT_LEN, DSCR_ENDPOINT_TYPE, // Length, Type
ENDPOINT_RCV | 1, ENDPOINT_TYPE_BULK, // Endpoint Num/Direction, Type
TOUSBORDER(0x0040), // Max Packet (0x0040)
0x00, // Polling Interval
// endpoint 2, send serial
DSCR_ENDPOINT_LEN, DSCR_ENDPOINT_TYPE, // Length, Type
ENDPOINT_SND | 2, ENDPOINT_TYPE_BULK, // Endpoint Num/Direction, Type
TOUSBORDER(0x0040), // Max Packet (0x0040)
0x00, // Polling Interval
// endpoint 3, send CAN
DSCR_ENDPOINT_LEN, DSCR_ENDPOINT_TYPE, // Length, Type
ENDPOINT_SND | 3, ENDPOINT_TYPE_BULK, // Endpoint Num/Direction, Type
TOUSBORDER(0x0040), // Max Packet (0x0040)
0x00, // Polling Interval
// endpoint 1, read CAN
DSCR_ENDPOINT_LEN, DSCR_ENDPOINT_TYPE, // Length, Type
ENDPOINT_RCV | 1, ENDPOINT_TYPE_BULK, // Endpoint Num/Direction, Type
TOUSBORDER(0x0040), // Max Packet (0x0040)
0x00, // Polling Interval (NA)
// endpoint 2, send serial
DSCR_ENDPOINT_LEN, DSCR_ENDPOINT_TYPE, // Length, Type
ENDPOINT_SND | 2, ENDPOINT_TYPE_BULK, // Endpoint Num/Direction, Type
TOUSBORDER(0x0040), // Max Packet (0x0040)
0x00, // Polling Interval
// endpoint 3, send CAN
DSCR_ENDPOINT_LEN, DSCR_ENDPOINT_TYPE, // Length, Type
ENDPOINT_SND | 3, ENDPOINT_TYPE_BULK, // Endpoint Num/Direction, Type
TOUSBORDER(0x0040), // Max Packet (0x0040)
0x00, // Polling Interval
// interface 0 ALT 1
DSCR_INTERFACE_LEN, DSCR_INTERFACE_TYPE, // Length, Type
0x00, 0x01, 0x03, // Index, Alt Index idx, Endpoint count
0XFF, 0xFF, 0xFF, // Class, Subclass, Protocol
0x00, // Interface
// endpoint 1, read CAN
DSCR_ENDPOINT_LEN, DSCR_ENDPOINT_TYPE, // Length, Type
ENDPOINT_RCV | 1, ENDPOINT_TYPE_INT, // Endpoint Num/Direction, Type
TOUSBORDER(0x0040), // Max Packet (0x0040)
0x05, // Polling Interval (5 frames)
// endpoint 2, send serial
DSCR_ENDPOINT_LEN, DSCR_ENDPOINT_TYPE, // Length, Type
ENDPOINT_SND | 2, ENDPOINT_TYPE_BULK, // Endpoint Num/Direction, Type
TOUSBORDER(0x0040), // Max Packet (0x0040)
0x00, // Polling Interval
// endpoint 3, send CAN
DSCR_ENDPOINT_LEN, DSCR_ENDPOINT_TYPE, // Length, Type
ENDPOINT_SND | 3, ENDPOINT_TYPE_BULK, // Endpoint Num/Direction, Type
TOUSBORDER(0x0040), // Max Packet (0x0040)
0x00, // Polling Interval
};
uint8_t string_0_desc[] = {
@ -183,6 +203,9 @@ uint16_t string_3_desc[] = {
USB_Setup_TypeDef setup;
uint8_t usbdata[0x100];
// Store the current interface alt setting.
int current_int0_alt_setting = 0;
// packet read and write
void *USB_ReadPacket(void *dest, uint16_t len) {
@ -198,14 +221,17 @@ void *USB_ReadPacket(void *dest, uint16_t len) {
void USB_WritePacket(const uint8_t *src, uint16_t len, uint32_t ep) {
#ifdef DEBUG_USB
puts("writing ");
hexdump(src, len);
puts("writing ");
hexdump(src, len);
#endif
uint8_t numpacket = (len+(MAX_RESP_LEN-1))/MAX_RESP_LEN;
uint32_t count32b = 0, i = 0;
count32b = (len + 3) / 4;
// bullshit
USBx_INEP(ep)->DIEPTSIZ = (USB_OTG_DIEPTSIZ_PKTCNT & (1 << 19)) | (len & USB_OTG_DIEPTSIZ_XFRSIZ);
USBx_INEP(ep)->DIEPTSIZ = ((numpacket << 19) & USB_OTG_DIEPTSIZ_PKTCNT) |
(len & USB_OTG_DIEPTSIZ_XFRSIZ);
USBx_INEP(ep)->DIEPCTL |= (USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA);
// load the FIFO
@ -374,6 +400,12 @@ void usb_setup() {
USB_WritePacket((void*)&resp, 2, 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
case USB_REQ_SET_INTERFACE:
// Store the alt setting number for IN EP behavior.
current_int0_alt_setting = setup.b.wValue.w;
USB_WritePacket(0, 0, 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
default:
resp_len = usb_cb_control_msg(&setup, resp, 1);
USB_WritePacket(resp, min(resp_len, setup.b.wLength.w), 0);
@ -515,7 +547,6 @@ void usb_irqhandler(void) {
puts("\n");
#endif
if (((rxst & USB_OTG_GRXSTSP_PKTSTS) >> 17) == STS_DATA_UPDT) {
int endpoint = (rxst & USB_OTG_GRXSTSP_EPNUM);
int len = (rxst & USB_OTG_GRXSTSP_BCNT) >> 4;
@ -632,8 +663,7 @@ void usb_irqhandler(void) {
USBx_OUTEP(3)->DOEPINT = USBx_OUTEP(3)->DOEPINT;
}
// in endpoint hit
// interrupt endpoint hit (Page 1221)
if (gintsts & USB_OTG_GINTSTS_IEPINT) {
#ifdef DEBUG_USB
puts(" ");
@ -643,29 +673,51 @@ void usb_irqhandler(void) {
puts(" IN ENDPOINT\n");
#endif
// this happens first
if (USBx_INEP(1)->DIEPINT & USB_OTG_DIEPINT_XFRC) {
#ifdef DEBUG_USB
puts(" IN PACKET SEND\n");
#endif
//USBx_DEVICE->DIEPEMPMSK = ~(1 << 1);
}
// Should likely check the EP of the IN request even if there is
// only one IN endpoint.
// *** IN token received when TxFIFO is empty
if (USBx_INEP(1)->DIEPINT & USB_OTG_DIEPMSK_ITTXFEMSK) {
#ifdef DEBUG_USB
// No need to set NAK in OTG_DIEPCTL0 when nothing to send,
// Appears USB core automatically sets NAK. WritePacket clears it.
// Handle the two interface alternate settings. Setting 0 is has
// EP1 as bulk. Setting 1 has EP1 as interrupt. The code to handle
// these two EP variations are very similar and can be
// restructured for smaller code footprint. Keeping split out for
// now for clarity.
//TODO add default case. Should it NAK?
switch(current_int0_alt_setting){
case 0: ////// Bulk config
// *** IN token received when TxFIFO is empty
if (USBx_INEP(1)->DIEPINT & USB_OTG_DIEPMSK_ITTXFEMSK) {
#ifdef DEBUG_USB
puts(" IN PACKET QUEUE\n");
#endif
// TODO: always assuming max len, can we get the length?
USB_WritePacket((void *)resp, usb_cb_ep1_in(resp, 0x40, 1), 1);
#endif
// TODO: always assuming max len, can we get the length?
USB_WritePacket((void *)resp, usb_cb_ep1_in(resp, 0x40, 1), 1);
}
break;
case 1: ////// Interrupt config
// Check if there is anything to actually send.
if (can_rx_q.w_ptr != can_rx_q.r_ptr) {
// *** IN token received when TxFIFO is empty
if (USBx_INEP(1)->DIEPINT & USB_OTG_DIEPMSK_ITTXFEMSK) {
#ifdef DEBUG_USB
puts(" IN PACKET QUEUE\n");
#endif
// TODO: always assuming max len, can we get the length?
USB_WritePacket((void *)resp, usb_cb_ep1_in(resp, 0x40, 1), 1);
}
}
break;
}
// clear interrupts
USBx_INEP(0)->DIEPINT = USBx_INEP(0)->DIEPINT;
USBx_INEP(0)->DIEPINT = USBx_INEP(0)->DIEPINT; // Why ep0?
USBx_INEP(1)->DIEPINT = USBx_INEP(1)->DIEPINT;
}
// clear all interrupts we handled
USBx_DEVICE->DAINT = daint;
USBx->GOTGINT = gotgint;

View File

@ -82,25 +82,27 @@ class Panda(object):
def __init__(self, serial=None, claim=True):
if serial == "WIFI":
self.handle = WifiHandle()
self._handle = WifiHandle()
print("opening WIFI device")
else:
context = usb1.USBContext()
self.handle = None
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()
self._handle = device.open()
if claim:
self.handle.claimInterface(0)
self._handle.claimInterface(0)
# TODO: Do we need to cupport claim=False?
self._handle.setInterfaceAltSetting(0,0)
break
assert self.handle != None
assert self._handle != None
def close(self):
self.handle.close()
self._handle.close()
@staticmethod
def list():
@ -116,7 +118,7 @@ class Panda(object):
# ******************* health *******************
def health(self):
dat = self.handle.controlRead(Panda.REQUEST_TYPE, 0xd2, 0, 0, 13)
dat = self._handle.controlRead(Panda.REQUEST_TYPE, 0xd2, 0, 0, 13)
a = struct.unpack("IIBBBBB", dat)
return {"voltage": a[0], "current": a[1],
"started": a[2], "controls_allowed": a[3],
@ -128,38 +130,38 @@ class Panda(object):
def enter_bootloader(self):
try:
self.handle.controlWrite(Panda.REQUEST_TYPE, 0xd1, 0, 0, b'')
self._handle.controlWrite(Panda.REQUEST_TYPE, 0xd1, 0, 0, b'')
except Exception as e:
print(e)
pass
def get_serial(self):
dat = self.handle.controlRead(Panda.REQUEST_TYPE, 0xd0, 0, 0, 0x20)
dat = self._handle.controlRead(Panda.REQUEST_TYPE, 0xd0, 0, 0, 0x20)
hashsig, calc_hash = dat[0x1c:], hashlib.sha1(dat[0:0x1c]).digest()[0:4]
if hashsig != calc_hash:
raise PandaHashMismatchException(calc_hash, hashsig)
return [dat[0:0x10], dat[0x10:0x10+10]]
def get_secret(self):
return self.handle.controlRead(Panda.REQUEST_TYPE, 0xd0, 1, 0, 0x10)
return self._handle.controlRead(Panda.REQUEST_TYPE, 0xd0, 1, 0, 0x10)
# ******************* configuration *******************
def set_controls_allowed(self, on):
self.handle.controlWrite(Panda.REQUEST_TYPE, 0xdc, (0x1337 if on else 0), 0, b'')
self._handle.controlWrite(Panda.REQUEST_TYPE, 0xdc, (0x1337 if on else 0), 0, b'')
def set_gmlan(self, on, bus=2):
self.handle.controlWrite(Panda.REQUEST_TYPE, 0xdb, 1, bus, b'')
self._handle.controlWrite(Panda.REQUEST_TYPE, 0xdb, 1, bus, b'')
def set_uart_baud(self, uart, rate):
self.handle.controlWrite(Panda.REQUEST_TYPE, 0xe1, uart, rate, b'')
self._handle.controlWrite(Panda.REQUEST_TYPE, 0xe1, uart, rate, b'')
def set_uart_parity(self, uart, parity):
# parity, 0=off, 1=even, 2=odd
self.handle.controlWrite(Panda.REQUEST_TYPE, 0xe2, uart, parity, b'')
self._handle.controlWrite(Panda.REQUEST_TYPE, 0xe2, uart, parity, b'')
def set_uart_callback(self, uart, install):
self.handle.controlWrite(Panda.REQUEST_TYPE, 0xe3, uart, int(install), b'')
self._handle.controlWrite(Panda.REQUEST_TYPE, 0xe3, uart, int(install), b'')
# ******************* can *******************
@ -179,7 +181,7 @@ class Panda(object):
while True:
try:
print("DAT: %s"%b''.join(snds).__repr__())
self.handle.bulkWrite(3, b''.join(snds))
self._handle.bulkWrite(3, b''.join(snds))
break
except (usb1.USBErrorIO, usb1.USBErrorOverflow):
print("CAN: BAD SEND MANY, RETRYING")
@ -191,7 +193,7 @@ class Panda(object):
dat = bytearray()
while True:
try:
dat = self.handle.bulkRead(1, 0x10*256)
dat = self._handle.bulkRead(1, 0x10*256)
break
except (usb1.USBErrorIO, usb1.USBErrorOverflow):
print("CAN: BAD RECV, RETRYING")
@ -200,22 +202,22 @@ class Panda(object):
# ******************* serial *******************
def serial_read(self, port_number):
return self.handle.controlRead(Panda.REQUEST_TYPE, 0xe0, port_number, 0, 0x40)
return self._handle.controlRead(Panda.REQUEST_TYPE, 0xe0, port_number, 0, 0x40)
def serial_write(self, port_number, ln):
return self.handle.bulkWrite(2, chr(port_number) + ln)
return self._handle.bulkWrite(2, chr(port_number) + ln)
# ******************* kline *******************
# pulse low for wakeup
def kline_wakeup(self):
self.handle.controlWrite(Panda.REQUEST_TYPE, 0xf0, 0, 0, b'')
self._handle.controlWrite(Panda.REQUEST_TYPE, 0xf0, 0, 0, b'')
def kline_drain(self, bus=2):
# drain buffer
bret = bytearray()
while True:
ret = self.handle.controlRead(Panda.REQUEST_TYPE, 0xe0, bus, 0, 0x40)
ret = self._handle.controlRead(Panda.REQUEST_TYPE, 0xe0, bus, 0, 0x40)
if len(ret) == 0:
break
bret += ret
@ -224,7 +226,7 @@ class Panda(object):
def kline_ll_recv(self, cnt, bus=2):
echo = bytearray()
while len(echo) != cnt:
echo += self.handle.controlRead(Panda.REQUEST_TYPE, 0xe0, bus, 0, cnt-len(echo))
echo += self._handle.controlRead(Panda.REQUEST_TYPE, 0xe0, bus, 0, cnt-len(echo))
return echo
def kline_send(self, x, bus=2, checksum=True):
@ -239,7 +241,7 @@ class Panda(object):
x += get_checksum(x)
for i in range(0, len(x), 0xf):
ts = x[i:i+0xf]
self.handle.bulkWrite(2, chr(bus)+ts)
self._handle.bulkWrite(2, chr(bus)+ts)
echo = self.kline_ll_recv(len(ts), bus=bus)
if echo != ts:
print("**** ECHO ERROR %d ****" % i)