From 7733b0928873e991efb79c0cf9612f87ef29ca2a Mon Sep 17 00:00:00 2001 From: George Hotz Date: Wed, 12 Jul 2017 11:25:10 -0700 Subject: [PATCH] Revert commits that broke USB for openpilot. Revert "fix openpilot board flashing" This reverts commit 8ff93ad5da39f8dc4bf6fe632f26418b696fd230. Revert "Fixed output_enabled led not turning off when mode changed to no output." This reverts commit 27a8af11075d92d03c389713694a879905877cf0. Revert "Fixed loopback test for new GMLAN 'can4' behavior." This reverts commit 59592f599af01a667b4fd966e613b8f504d62dc2. Revert "GMLAN is now always mapped through CAN4 (index 3)" This reverts commit 329c09102435bfd9b1fbb60694139a5ff7bf4148. Revert "Removed compile time config for CAN loopback, implemented as usb message." This reverts commit e1a4c3298557fccf854ed5cbda448f8c0015b7ea. Revert "Change all output safety mode identifier to prevent user mistakes." This reverts commit 6b363e2e92fcd5e7f25b5458fe9008ff8f9fd664. Revert "untabify" This reverts commit 191f67b083e182323ba956c3ab75df10bec2f863. Revert "Refactor of safety to support more modular additions of safety policies." This reverts commit e5b524eddc82e53587cc47dcf15b22fd35890a92. Revert "Split up some more header files into compilation units." This reverts commit e2a78912f5b649822974fc0e974ec50d9d9c7d10. Revert "Enabled emulated control writes over USB." This reverts commit 133cfe970379d6881de26289616d1d9085bb5986. Revert "Moved CAN and USART code out of main.c and into more appropriate files." This reverts commit daad2dc0620d629e7db0dd68dee5595ed2b57160. Revert "Large Panda CAN cleanup. Restrict GMLAN to valid baud rates." This reverts commit a0616a2bc2ac2bfd99223aaa84912e6f649c9d54. Revert "Panda library now correctly sends USB direction bit." This reverts commit 1712c901d4b46b2726b3165a7cb2e91c281c662b. Revert "Board makefile now automatically calculates header file dependencies." This reverts commit 4a8d4e597b397ca6d68dd5dd2a376c8354dc3422. Revert "Loopback test works over wifi. (Disable trying to send over wifi)" This reverts commit dae636968af482e170aade1d785a1e197e9f3c04. Revert "Fix legacy board build" This reverts commit 62bf4e575686c84c672eb0d341ad41f174141c2d. Revert "Style cop" This reverts commit c439f43726feb30cf2ec486ffcad6ac94ab5e128. Revert "Untabify" This reverts commit 41e5eec6211c23836535af49380f74350a0ceb12. Revert "Fixed disabling gmlan." This reverts commit 5e1e45a4afade384b628e44587dd8e37d3dcd8cd. Revert "Removed dead code, standardized canid in more commands, better erroring behavior." This reverts commit b59aeb6d87ddd85406ec42e4ed8a74a232d506a4. Revert "loopback test works with new CAN bus ids." This reverts commit 75970861cf2b025173afb906e4e243861bed506a. Revert "Large reorganization of code and early integration of can bitrate setting." This reverts commit a1ed7b62ee66ec8f56bba488c38c67b69eead8cf. --- board/Makefile.legacy | 2 +- board/__init__.py | 0 board/adc.h | 1 + board/bootstub.c | 1 + board/build.mk | 21 +- board/can.c | 487 ----------------- board/can.h | 155 +++--- board/config.h | 24 +- board/dac.h | 1 + board/early.c | 8 +- board/early.h | 12 +- board/gpio.c | 144 ----- board/gpio.h | 277 +++++++++- board/{safety_honda.h => honda_safety.h} | 23 +- board/libc.c | 66 --- board/libc.h | 65 ++- board/main.c | 604 +++++++++++++++++---- board/obj/.placeholder | 0 board/panda_safety.h | 13 + board/rev.h | 39 -- board/safety.c | 96 ---- board/safety.h | 27 - board/spi.c | 51 -- board/spi.h | 50 +- board/spi_flasher.h | 2 - board/timer.h | 1 + board/tools/enter_download_mode.py | 9 +- board/uart.c | 209 ------- board/uart.h | 100 ++-- board/usb.c | 661 ----------------------- board/usb.h | 620 ++++++++++++++++++++- drivers/linux/panda.c | 9 +- panda/__init__.py | 56 +- tests/debug_console.py | 4 - tests/loopback_test.py | 95 ++-- tests/standalone_test.py | 2 +- tests/throughput_test.py | 2 +- 37 files changed, 1733 insertions(+), 2204 deletions(-) create mode 100644 board/__init__.py delete mode 100644 board/can.c delete mode 100644 board/gpio.c rename board/{safety_honda.h => honda_safety.h} (81%) delete mode 100644 board/libc.c create mode 100644 board/obj/.placeholder create mode 100644 board/panda_safety.h delete mode 100644 board/rev.h delete mode 100644 board/safety.c delete mode 100644 board/safety.h delete mode 100644 board/spi.c delete mode 100644 board/uart.c delete mode 100644 board/usb.c diff --git a/board/Makefile.legacy b/board/Makefile.legacy index 4d494db..8d1456f 100644 --- a/board/Makefile.legacy +++ b/board/Makefile.legacy @@ -1,6 +1,6 @@ # :set noet PROJ_NAME = comma -CFLAGS = -g -O0 -Wall -std=gnu90 +CFLAGS = -g -O0 -Wall CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m3 CFLAGS += -msoft-float -DSTM32F2 -DSTM32F205xx diff --git a/board/__init__.py b/board/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/board/adc.h b/board/adc.h index 4862b1e..33a0a5d 100644 --- a/board/adc.h +++ b/board/adc.h @@ -36,3 +36,4 @@ uint32_t adc_get(int channel) { return ADC1->JDR1; } + diff --git a/board/bootstub.c b/board/bootstub.c index 0aff07e..6bf6cf8 100644 --- a/board/bootstub.c +++ b/board/bootstub.c @@ -77,3 +77,4 @@ good: ((void(*)()) _app_start[1])(); return 0; } + diff --git a/board/build.mk b/board/build.mk index 6103d81..43b54ee 100644 --- a/board/build.mk +++ b/board/build.mk @@ -1,7 +1,3 @@ -DEPDIR := obj/.d -$(shell mkdir -p $(DEPDIR) >/dev/null) -DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.Td - CFLAGS += -I inc -I ../ -nostdlib -fno-builtin CFLAGS += -Tstm32_flash.ld @@ -11,6 +7,7 @@ OBJDUMP = arm-none-eabi-objdump ifeq ($(RELEASE),1) CERT = ../../pandaextra/certs/release + CFLAGS += "-DPANDA_SAFETY" else CERT = ../certs/debug CFLAGS += "-DALLOW_DEBUG" @@ -71,23 +68,23 @@ obj/cert.h: ../crypto/getcertheader.py ../crypto/getcertheader.py ../certs/debug.pub ../certs/release.pub > $@ obj/%.$(PROJ_NAME).o: %.c obj/cert.h obj/gitversion.h config.h - $(CC) $(DEPFLAGS) $(CFLAGS) -o $@ -c $< + $(CC) $(CFLAGS) -o $@ -c $< obj/%.$(PROJ_NAME).o: ../crypto/%.c - $(CC) $(DEPFLAGS) $(CFLAGS) -o $@ -c $< + $(CC) $(CFLAGS) -o $@ -c $< obj/$(STARTUP_FILE).o: $(STARTUP_FILE).s - $(CC) $(DEPFLAGS) $(CFLAGS) -o $@ -c $< + $(CC) $(CFLAGS) -o $@ -c $< -obj/$(PROJ_NAME).bin: obj/$(STARTUP_FILE).o obj/main.$(PROJ_NAME).o obj/early.$(PROJ_NAME).o obj/llgpio.$(PROJ_NAME).o obj/can.$(PROJ_NAME).o obj/uart.$(PROJ_NAME).o obj/gpio.$(PROJ_NAME).o obj/libc.$(PROJ_NAME).o obj/spi.$(PROJ_NAME).o obj/usb.$(PROJ_NAME).o obj/safety.$(PROJ_NAME).o +obj/$(PROJ_NAME).bin: obj/$(STARTUP_FILE).o obj/main.$(PROJ_NAME).o obj/early.$(PROJ_NAME).o obj/llgpio.$(PROJ_NAME).o # hack - $(CC) $(DEPFLAGS) -Wl,--section-start,.isr_vector=0x8004000 $(CFLAGS) -o obj/$(PROJ_NAME).elf $^ + $(CC) -Wl,--section-start,.isr_vector=0x8004000 $(CFLAGS) -o obj/$(PROJ_NAME).elf $^ $(OBJCOPY) -v -O binary obj/$(PROJ_NAME).elf obj/code.bin SETLEN=1 ../crypto/sign.py obj/code.bin $@ $(CERT) -obj/bootstub.$(PROJ_NAME).bin: obj/$(STARTUP_FILE).o obj/bootstub.$(PROJ_NAME).o obj/sha.$(PROJ_NAME).o obj/rsa.$(PROJ_NAME).o obj/early.$(PROJ_NAME).o obj/llgpio.$(PROJ_NAME).o obj/libc.$(PROJ_NAME).o obj/spi.$(PROJ_NAME).o - $(CC) $(DEPFLAGS) $(CFLAGS) -o obj/bootstub.$(PROJ_NAME).elf $^ +obj/bootstub.$(PROJ_NAME).bin: obj/$(STARTUP_FILE).o obj/bootstub.$(PROJ_NAME).o obj/sha.$(PROJ_NAME).o obj/rsa.$(PROJ_NAME).o obj/early.$(PROJ_NAME).o obj/llgpio.$(PROJ_NAME).o + $(CC) $(CFLAGS) -o obj/bootstub.$(PROJ_NAME).elf $^ $(OBJCOPY) -v -O binary obj/bootstub.$(PROJ_NAME).elf $@ clean: - rm -fr obj + rm -f obj/* diff --git a/board/can.c b/board/can.c deleted file mode 100644 index 14a8147..0000000 --- a/board/can.c +++ /dev/null @@ -1,487 +0,0 @@ -#include -#include "config.h" -#include "can.h" -#include "uart.h" -#include "gpio.h" -#include "llgpio.h" -#include "libc.h" -#include "rev.h" -#include "safety.h" - -bool can_live = false, pending_can_live = false, can_loopback = false; - -#define NO_ACTIVE_GMLAN -1 -int active_gmlan_port_id = NO_ACTIVE_GMLAN; // default disabled - -#define GMLAN_PORT_ID 3 - -// assign CAN numbering -#ifdef PANDA - // ********************* instantiate can queues ********************* - can_buffer(rx_q, 0x1000) - can_buffer(tx1_q, 0x100) - can_buffer(tx2_q, 0x100) - can_buffer(tx3_q, 0x100) - - // panda: CAN1 = 0 CAN2 = 1 CAN3 = 2 - can_port_desc can_ports[] = { - {CAN_PORT_DESC_INITIALIZER, - .CAN = CAN1, - .msg_buff = &can_tx1_q, - .can_pins = {{GPIOB, 8, GPIO_AF8_CAN1}, {GPIOB, 9, GPIO_AF8_CAN1}}, - .enable_pin = {GPIOC, 1, 0}, - .gmlan_support = false, - }, - {CAN_PORT_DESC_INITIALIZER, - .CAN = CAN2, - .msg_buff = &can_tx2_q, - .can_pins = {{GPIOB, 5, GPIO_AF9_CAN2}, {GPIOB, 6, GPIO_AF9_CAN2}}, - .enable_pin = {GPIOC, 13, 0}, - .gmlan_support = true, - .gmlan_pins = {{GPIOB, 12, GPIO_AF9_CAN2}, {GPIOB, 13, GPIO_AF9_CAN2}}, - }, - //TODO Make gmlan support correct for REV B - {CAN_PORT_DESC_INITIALIZER, - .CAN = CAN3, - .msg_buff = &can_tx3_q, - .can_pins = {{GPIOA, 8, GPIO_AF11_CAN3}, {GPIOA, 15, GPIO_AF11_CAN3}}, - .enable_pin = {GPIOA, 0, 0}, - .gmlan_support = true, - .gmlan_pins = {{GPIOB, 3, GPIO_AF11_CAN3}, {GPIOB, 4, GPIO_AF11_CAN3}}, - } - }; -#else - // ********************* instantiate can queues ********************* - can_buffer(rx_q, 0x1000) - can_buffer(tx1_q, 0x100) - can_buffer(tx2_q, 0x100) - // old: CAN1 = 1 CAN2 = 0 - can_port_desc can_ports[] = { - {CAN_PORT_DESC_INITIALIZER, - .CAN = CAN2, - .msg_buff = &can_tx1_q, - .can_pins = {{GPIOB, 5, GPIO_AF9_CAN2}, {GPIOB, 6, GPIO_AF9_CAN2}}, - .enable_pin = {GPIOB, 4, 1}, - .gmlan_support = false, - }, - {CAN_PORT_DESC_INITIALIZER, - .CAN = CAN1, - .msg_buff = &can_tx2_q, - .can_pins = {{GPIOB, 8, GPIO_AF9_CAN1}, {GPIOB, 9, GPIO_AF9_CAN1}}, - .enable_pin = {GPIOB, 3, 1}, - .gmlan_support = false, - } - }; -#endif - -int pop(can_ring *q, CAN_FIFOMailBox_TypeDef *elem) { - if (q->w_ptr != q->r_ptr) { - *elem = q->elems[q->r_ptr]; - if ((q->r_ptr + 1) == q->fifo_size) q->r_ptr = 0; - else q->r_ptr += 1; - return 1; - } - return 0; -} - -int push(can_ring *q, CAN_FIFOMailBox_TypeDef *elem) { - uint32_t next_w_ptr; - if ((q->w_ptr + 1) == q->fifo_size) next_w_ptr = 0; - else next_w_ptr = q->w_ptr + 1; - if (next_w_ptr != q->r_ptr) { - q->elems[q->w_ptr] = *elem; - q->w_ptr = next_w_ptr; - return 1; - } - puts("push failed!\n"); - return 0; -} - -// ********************* CAN Functions ********************* - -void can_init(uint8_t canid) { - int i; - uint32_t bitrate; - CAN_TypeDef *CAN; - uint8_t quanta; - uint16_t prescaler; - uint8_t seq1, seq2; - - can_port_desc *port; - gpio_alt_setting *disable_pins; - gpio_alt_setting *enable_pins; - - puts("Can init: "); - puth(canid); - puts("\n"); - - if(canid >= CAN_MAX) return; - port = &can_ports[canid]; - - //////////// Set MCU pin modes - if (port->gmlan_support) { - disable_pins = port->gmlan ? port->can_pins : port->gmlan_pins; - enable_pins = port->gmlan ? port->gmlan_pins : port->can_pins; - } else { - disable_pins = 0; - enable_pins = port->can_pins; - } - - // Disable output on either CAN or GMLAN pins - if (disable_pins) { - set_gpio_mode(disable_pins[0].port, disable_pins[0].num, MODE_INPUT); - set_gpio_mode(disable_pins[1].port, disable_pins[1].num, MODE_INPUT); - } - - // Enable output on either CAN or GMLAN pins - if (enable_pins) { - set_gpio_alternate(enable_pins[0].port, enable_pins[0].num, enable_pins[0].setting); - set_gpio_alternate(enable_pins[1].port, enable_pins[1].num, enable_pins[1].setting); - } - - /* GMLAN mode pins: - M0(B15) M1(B14) mode - ======================= - 0 0 sleep - 1 0 100kbit - 0 1 high voltage wakeup - 1 1 33kbit (normal) - */ - if (port->gmlan) { - set_gpio_output(GPIOB, 14, 1); - set_gpio_output(GPIOB, 15, 1); - } else { - for (i = 0; i < CAN_MAX; i++) - if (can_ports[i].gmlan) - break; - if (i == CAN_MAX){ - set_gpio_output(GPIOB, 14, 0); - set_gpio_output(GPIOB, 15, 0); - puts("Disabling GMLAN output\n"); - } - } - - //////////// Calculate and set CAN bitrate - if (port->gmlan) { - bitrate = (port->gmlan_bitrate) < 58333 ? 33333 : 83333; - } else { - bitrate = port->bitrate; - if(bitrate > 1000000) //MAX 1 Megabaud - bitrate = 1000000; - } - - //puts(" Speed req: "); - //puth(bitrate); - //puts("\n"); - - //TODO: Try doing both and find the more accurate values. - if(min((FREQ / 2) / bitrate, 16) == 16){ - quanta = 16; - seq1 = 13;//roundf(quanta * 0.875f) - 1; - seq2 = 2;//roundf(quanta * 0.125f); - }else{ - quanta = 8; - seq1 = 6;//roundf(quanta * 0.875f) - 1; - seq2 = 1;//roundf(quanta * 0.125f); - } - - // TODO: Look into better accuracy with rounding. - prescaler = FREQ / quanta / bitrate; - - //Check the prescaler is not larger than max - if(prescaler > 0x3FF) - prescaler = 0x3FF; - - bitrate = FREQ/quanta/prescaler; - if (port->gmlan) { - port->gmlan_bitrate = bitrate; - } else { - port->bitrate = bitrate; - } - - puts(" Speed: "); - puth(bitrate); - puts("\n"); - - if (port->gmlan) - puts(" Type GMLAN\n"); - else - puts(" Type CAN\n"); - - //////////////// Enable CAN port - if (is_output_enabled()) - puts(" Output Enabled\n"); - else - puts(" Output Disabled\n"); - - set_can_enable(canid, 1); - - CAN = port->CAN; - // Move CAN to initialization mode and sync. - CAN->MCR = CAN_MCR_TTCM | CAN_MCR_INRQ; - while((CAN->MSR & CAN_MSR_INAK) != CAN_MSR_INAK); - - // seg 1: 13 time quanta, seg 2: 2 time quanta - CAN->BTR = (CAN_BTR_TS1_0 * (seq1 - 1)) | - (CAN_BTR_TS2_0 * (seq2 - 1)) | - (prescaler - 1); - - // silent loopback mode for debugging - if (can_loopback) { - CAN->BTR |= CAN_BTR_SILM | CAN_BTR_LBKM; - } - - if (!is_output_enabled()) { - CAN->BTR |= CAN_BTR_SILM; - } - - // reset - CAN->MCR = CAN_MCR_TTCM; - - int tmp = 0; - while((CAN->MSR & CAN_MSR_INAK) == CAN_MSR_INAK && tmp < CAN_TIMEOUT) tmp++; - - if (tmp == CAN_TIMEOUT) { - set_led(LED_BLUE, 1); - puts(" init FAILED!!!!!\n"); - } else { - puts(" init SUCCESS\n"); - } - - // accept all filter - CAN->FMR |= CAN_FMR_FINIT; - - // no mask - CAN->sFilterRegister[0].FR1 = 0; - CAN->sFilterRegister[0].FR2 = 0; - CAN->sFilterRegister[14].FR1 = 0; - CAN->sFilterRegister[14].FR2 = 0; - CAN->FA1R |= 1 | (1 << 14); - - CAN->FMR &= ~(CAN_FMR_FINIT); - - // enable all CAN interrupts - CAN->IER = 0xFFFFFFFF; - //CAN->IER = CAN_IER_TMEIE | CAN_IER_FMPIE0 | CAN_IER_FMPIE1; -} - -void set_can_mode(uint16_t canid, bool use_gmlan) { - if (canid >= CAN_MAX) return; - if (!can_ports[canid].gmlan_support) use_gmlan = false; - - if (use_gmlan) { - // If enabling gmlan, and another port is already enabled, disable it. - if(active_gmlan_port_id != NO_ACTIVE_GMLAN && active_gmlan_port_id != canid) - set_can_mode(active_gmlan_port_id, 0); - active_gmlan_port_id = canid; - } else if(active_gmlan_port_id != NO_ACTIVE_GMLAN && active_gmlan_port_id == canid) { - // If disabling gmlan, and this port is gmlan enabled, unregister it. - active_gmlan_port_id = -1; - } - - can_ports[canid].gmlan = use_gmlan; - - can_init(canid); -} - -// CAN error -void can_sce(uint8_t canid) { - CAN_TypeDef *CAN = can_ports[canid].CAN; - #ifdef DEBUG - if (canid==0) puts("CAN1: "); - if (canid==1) puts("CAN2: "); - if (canid==2) puts("CAN3: "); - puts("MSR:"); - puth(CAN->MSR); - puts(" TSR:"); - puth(CAN->TSR); - puts(" RF0R:"); - puth(CAN->RF0R); - puts(" RF1R:"); - puth(CAN->RF1R); - puts(" ESR:"); - puth(CAN->ESR); - puts("\n"); - #endif - - // clear - //CAN->sTxMailBox[0].TIR &= ~(CAN_TI0R_TXRQ); - CAN->TSR |= CAN_TSR_ABRQ0; - //CAN->ESR |= CAN_ESR_LEC; - //CAN->MSR &= ~(CAN_MSR_ERRI); - CAN->MSR = CAN->MSR; -} - -void CAN1_SCE_IRQHandler() { - can_sce(0); -} - -void CAN2_SCE_IRQHandler() { - can_sce(1); -} - -void CAN3_SCE_IRQHandler() { - can_sce(2); -} - -// CAN receive handlers -// blink blue when we are receiving CAN messages -void can_rx(uint8_t canid) { - CAN_TypeDef *CAN = can_ports[canid].CAN; - while (CAN->RF0R & CAN_RF0R_FMP0) { - // can is live - pending_can_live = 1; - - // add to my fifo - CAN_FIFOMailBox_TypeDef to_push; - to_push.RIR = CAN->sFIFOMailBox[0].RIR; - to_push.RDTR = CAN->sFIFOMailBox[0].RDTR; - to_push.RDLR = CAN->sFIFOMailBox[0].RDLR; - to_push.RDHR = CAN->sFIFOMailBox[0].RDHR; - - // forwarding (panda only) - #ifdef PANDA - if (can_ports[canid].forwarding != -1) { - CAN_FIFOMailBox_TypeDef to_send; - to_send.RIR = to_push.RIR | 1; // TXRQ - to_send.RDTR = to_push.RDTR; - to_send.RDLR = to_push.RDLR; - to_send.RDHR = to_push.RDHR; - send_can(&to_send, can_ports[canid].forwarding); - } - #endif - - // modify RDTR for our API - if(canid == active_gmlan_port_id) { - to_push.RDTR = (to_push.RDTR & 0xFFFF000F) | (GMLAN_PORT_ID << 4); - } else { - to_push.RDTR = (to_push.RDTR & 0xFFFF000F) | (canid << 4); - } - - safety_rx_hook(&to_push); - - #ifdef PANDA - set_led(LED_GREEN, 1); - #endif - push(&can_rx_q, &to_push); - - // next - CAN->RF0R |= CAN_RF0R_RFOM0; - } -} - -void CAN1_RX0_IRQHandler() { - can_rx(0); -} - -void CAN2_RX0_IRQHandler() { - can_rx(1); -} - -void CAN3_RX0_IRQHandler() { - can_rx(2); -} - -int can_cksum(uint8_t *dat, int len, int addr, int idx) { - int i; - int s = 0; - for (i = 0; i < len; i++) { - s += (dat[i] >> 4); - s += dat[i] & 0xF; - } - s += (addr>>0)&0xF; - s += (addr>>4)&0xF; - s += (addr>>8)&0xF; - s += idx; - s = 8-s; - return s&0xF; -} - -void process_can(uint8_t canid) { - CAN_TypeDef *CAN; - uint8_t reported_canid = canid; - - #ifdef DEBUG - puts("process CAN TX\n"); - #endif - - // canid of 3 is the virtual GMLAN (CAN4) - if (canid >= CAN_MAX) return; - - // Remap canid to gmlan if port has gmlan enabled - if (canid == active_gmlan_port_id) { - reported_canid = GMLAN_PORT_ID; - } - - CAN = can_ports[canid].CAN; - - // add successfully transmitted message to my fifo - if ((CAN->TSR & CAN_TSR_TXOK0) == CAN_TSR_TXOK0) { - CAN_FIFOMailBox_TypeDef to_push; - to_push.RIR = CAN->sTxMailBox[0].TIR; - to_push.RDTR = (CAN->sTxMailBox[0].TDTR & 0xFFFF000F) | - ((PANDA_CANB_RETURN_FLAG | (reported_canid & 0x7F)) << 4); - - puts("RDTR: "); - puth(to_push.RDTR); - puts("\n"); - - to_push.RDLR = CAN->sTxMailBox[0].TDLR; - to_push.RDHR = CAN->sTxMailBox[0].TDHR; - push(&can_rx_q, &to_push); - } - - // check for empty mailbox - CAN_FIFOMailBox_TypeDef to_send; - if ((CAN->TSR & CAN_TSR_TME0) == CAN_TSR_TME0) { - if (pop(can_ports[canid].msg_buff, &to_send)) { - // only send if we have received a packet - CAN->sTxMailBox[0].TDLR = to_send.RDLR; - CAN->sTxMailBox[0].TDHR = to_send.RDHR; - CAN->sTxMailBox[0].TDTR = to_send.RDTR; - CAN->sTxMailBox[0].TIR = to_send.RIR; - } - } - - // clear interrupt - CAN->TSR |= CAN_TSR_RQCP0; -} - -// send more, possible for these to not trigger? - - -void CAN1_TX_IRQHandler() { - process_can(0); -} - -void CAN2_TX_IRQHandler() { - process_can(1); -} - -void CAN3_TX_IRQHandler() { - process_can(2); -} - -void send_can(CAN_FIFOMailBox_TypeDef *to_push, uint8_t canid) { - // canid of 3 is the virtual GMLAN (CAN4) - if (canid >= CAN_MAX && canid != GMLAN_PORT_ID) return; - - // TODO: Error for using disabled port - if (active_gmlan_port_id == canid) return; - - // Remap gmlan output to real can port - if (canid == GMLAN_PORT_ID) { - if (active_gmlan_port_id == NO_ACTIVE_GMLAN) - return; // No gmlan port enabled - else - canid = active_gmlan_port_id; - } - - // add CAN packet to send queue - // bus number isn't passed through - to_push->RDTR &= 0xF; - push(can_ports[canid].msg_buff, to_push); - - // canid = can_number - process_can(canid); -} diff --git a/board/can.h b/board/can.h index 98ad0a3..f8387db 100644 --- a/board/can.h +++ b/board/can.h @@ -1,88 +1,101 @@ -#ifndef PANDA_CAN_H -#define PANDA_CAN_H +void can_init(CAN_TypeDef *CAN, int silent) { + set_can_enable(CAN, 1); -#include -#include "rev.h" + CAN->MCR = CAN_MCR_TTCM | CAN_MCR_INRQ; + while((CAN->MSR & CAN_MSR_INAK) != CAN_MSR_INAK); -#define CAN_TIMEOUT 1000000 -#define PANDA_CANB_RETURN_FLAG 0x80 + // http://www.bittiming.can-wiki.info/ + // PCLK = 24 MHz + uint32_t pclk = 24000; + uint32_t num_time_quanta = 16; -extern bool can_live, pending_can_live, can_loopback; + // 500 kbps + uint32_t prescaler = pclk / num_time_quanta / 500; -// ********************* queues types ********************* + // seg 1: 13 time quanta, seg 2: 2 time quanta + CAN->BTR = (CAN_BTR_TS1_0 * 12) | + CAN_BTR_TS2_0 | (prescaler - 1); -typedef struct { - uint32_t w_ptr; - uint32_t r_ptr; - uint32_t fifo_size; - CAN_FIFOMailBox_TypeDef *elems; -} can_ring; + // silent loopback mode for debugging + #ifdef CAN_LOOPBACK_MODE + CAN->BTR |= CAN_BTR_SILM | CAN_BTR_LBKM; + #endif -#define can_buffer(x, size) \ - CAN_FIFOMailBox_TypeDef elems_##x[size]; \ - can_ring can_##x = { .w_ptr = 0, .r_ptr = 0, .fifo_size = size, .elems = (CAN_FIFOMailBox_TypeDef *)&elems_##x }; + if (silent) { + CAN->BTR |= CAN_BTR_SILM; + } -extern can_ring can_rx_q; + // reset + CAN->MCR = CAN_MCR_TTCM; -// ********************* port description types ********************* + #define CAN_TIMEOUT 1000000 + int tmp = 0; + while((CAN->MSR & CAN_MSR_INAK) == CAN_MSR_INAK && tmp < CAN_TIMEOUT) tmp++; -#define CAN_PORT_DESC_INITIALIZER \ - .forwarding=-1, \ - .bitrate=CAN_DEFAULT_BITRATE, \ - .bitrate=CAN_DEFAULT_BITRATE, \ - .gmlan=false, \ - .gmlan_bitrate=GMLAN_DEFAULT_BITRATE + if (tmp == CAN_TIMEOUT) { + set_led(LED_BLUE, 1); + puts("CAN init FAILED!!!!!\n"); + } else { + puts("CAN init done\n"); + } -typedef struct { - GPIO_TypeDef* port; - uint8_t num; - bool high_val; -} gpio_pin; + // accept all filter + CAN->FMR |= CAN_FMR_FINIT; -typedef struct { - GPIO_TypeDef* port; - uint8_t num; - uint32_t setting; -} gpio_alt_setting; + // no mask + CAN->sFilterRegister[0].FR1 = 0; + CAN->sFilterRegister[0].FR2 = 0; + CAN->sFilterRegister[14].FR1 = 0; + CAN->sFilterRegister[14].FR2 = 0; + CAN->FA1R |= 1 | (1 << 14); -typedef struct { - CAN_TypeDef *CAN; - int8_t forwarding; - uint32_t bitrate; - bool gmlan; - bool gmlan_support; - uint32_t gmlan_bitrate; - gpio_pin enable_pin; - gpio_alt_setting can_pins[2]; - gpio_alt_setting gmlan_pins[2]; - can_ring *msg_buff; -} can_port_desc; + CAN->FMR &= ~(CAN_FMR_FINIT); -extern can_port_desc can_ports[]; - -#ifdef PANDA - #define CAN_MAX 3 -#else - #define CAN_MAX 2 -#endif - -// ********************* interrupt safe queue ********************* - -int pop(can_ring *q, CAN_FIFOMailBox_TypeDef *elem); - -int push(can_ring *q, CAN_FIFOMailBox_TypeDef *elem); - -// ********************* CAN Functions ********************* - -void can_init(uint8_t canid); - -void set_can_mode(uint16_t can, bool use_gmlan); - -void send_can(CAN_FIFOMailBox_TypeDef *to_push, uint8_t canid); + // enable all CAN interrupts + CAN->IER = 0xFFFFFFFF; + //CAN->IER = CAN_IER_TMEIE | CAN_IER_FMPIE0 | CAN_IER_FMPIE1; +} // CAN error -//void can_sce(uint8_t canid); +void can_sce(CAN_TypeDef *CAN) { + #ifdef DEBUG + if (CAN==CAN1) puts("CAN1: "); + if (CAN==CAN2) puts("CAN2: "); + #ifdef CAN3 + if (CAN==CAN3) puts("CAN3: "); + #endif + puts("MSR:"); + puth(CAN->MSR); + puts(" TSR:"); + puth(CAN->TSR); + puts(" RF0R:"); + puth(CAN->RF0R); + puts(" RF1R:"); + puth(CAN->RF1R); + puts(" ESR:"); + puth(CAN->ESR); + puts("\n"); + #endif -int can_cksum(uint8_t *dat, int len, int addr, int idx); + // clear + //CAN->sTxMailBox[0].TIR &= ~(CAN_TI0R_TXRQ); + CAN->TSR |= CAN_TSR_ABRQ0; + //CAN->ESR |= CAN_ESR_LEC; + //CAN->MSR &= ~(CAN_MSR_ERRI); + CAN->MSR = CAN->MSR; +} -#endif +int can_cksum(uint8_t *dat, int len, int addr, int idx) { + int i; + int s = 0; + for (i = 0; i < len; i++) { + s += (dat[i] >> 4); + s += dat[i] & 0xF; + } + s += (addr>>0)&0xF; + s += (addr>>4)&0xF; + s += (addr>>8)&0xF; + s += idx; + s = 8-s; + return s&0xF; +} diff --git a/board/config.h b/board/config.h index b775f42..d9304bd 100644 --- a/board/config.h +++ b/board/config.h @@ -1,21 +1,23 @@ #ifndef PANDA_CONFIG_H #define PANDA_CONFIG_H -#include "rev.h" - //#define DEBUG //#define DEBUG_USB +//#define CAN_LOOPBACK_MODE + +#ifdef STM32F4 + #define PANDA + #include "stm32f4xx.h" +#else + #include "stm32f2xx.h" +#endif + +#ifdef PANDA + #define ENABLE_CURRENT_SENSOR + #define ENABLE_SPI +#endif #define USB_VID 0xbbaa #define USB_PID 0xddcc -#define CAN_DEFAULT_BITRATE 500000 // 500 khz -#define GMLAN_DEFAULT_BITRATE 33333 // 33.333 khz - -#define FIFO_SIZE 0x100 - -#define NULL ((void*)0) - -#define PANDA_SAFETY - #endif diff --git a/board/dac.h b/board/dac.h index 68d4316..b8833dc 100644 --- a/board/dac.h +++ b/board/dac.h @@ -13,3 +13,4 @@ void dac_set(int channel, uint32_t value) { DAC->DHR12R2 = value; } } + diff --git a/board/early.c b/board/early.c index 65021d3..bac6c6b 100644 --- a/board/early.c +++ b/board/early.c @@ -1,12 +1,10 @@ #include "config.h" #include "early.h" #include "llgpio.h" -#include "uart.h" -#include "rev.h" int has_external_debug_serial = 0; int is_giant_panda = 0; -enum rev revision = REV_A; +int revision = PANDA_REV_AB; void *g_pfnVectors; // must call again from main because BSS is zeroed @@ -34,9 +32,7 @@ void detect() { set_gpio_pullup(GPIOA, 13, PULL_DOWN); for (i=0;iport, pin->num, !(enabled ^ pin->high_val)); -} - -// TODO: does this belong here? -void periph_init() { - // enable GPIOB, UART2, CAN, USB clock - RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; - RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN; - RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN; - RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; - - RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; - RCC->APB1ENR |= RCC_APB1ENR_USART2EN; - RCC->APB1ENR |= RCC_APB1ENR_USART3EN; - #ifdef PANDA - RCC->APB1ENR |= RCC_APB1ENR_UART5EN; - #endif - RCC->APB1ENR |= RCC_APB1ENR_CAN1EN; - RCC->APB1ENR |= RCC_APB1ENR_CAN2EN; - #ifdef CAN3 - RCC->APB1ENR |= RCC_APB1ENR_CAN3EN; - #endif - RCC->APB1ENR |= RCC_APB1ENR_DACEN; - RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; - //RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; - RCC->APB2ENR |= RCC_APB2ENR_USART1EN; - RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN; - RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; - RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; - RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; - - // needed? - RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; -} - -// board specific -void gpio_init() { - // pull low to hold ESP in reset?? - // enable OTG out tied to ground - GPIOA->ODR = 0; - GPIOB->ODR = 0; - GPIOA->PUPDR = 0; - //GPIOC->ODR = 0; - GPIOB->AFR[0] = 0; - GPIOB->AFR[1] = 0; - - // C2,C3: analog mode, voltage and current sense - set_gpio_mode(GPIOC, 2, MODE_ANALOG); - set_gpio_mode(GPIOC, 3, MODE_ANALOG); - - // C8: FAN aka TIM3_CH4 - set_gpio_alternate(GPIOC, 8, GPIO_AF2_TIM3); - - // turn off LEDs and set mode - set_led(LED_RED, 0); - set_led(LED_GREEN, 0); - set_led(LED_BLUE, 0); - - // A11,A12: USB - set_gpio_alternate(GPIOA, 11, GPIO_AF10_OTG_FS); - set_gpio_alternate(GPIOA, 12, GPIO_AF10_OTG_FS); - GPIOA->OSPEEDR = GPIO_OSPEEDER_OSPEEDR11 | GPIO_OSPEEDER_OSPEEDR12; - -#ifdef PANDA - // enable started_alt on the panda - set_gpio_pullup(GPIOA, 1, PULL_UP); - - // A2,A3: USART 2 for debugging - set_gpio_alternate(GPIOA, 2, GPIO_AF7_USART2); - set_gpio_alternate(GPIOA, 3, GPIO_AF7_USART2); - - // A9,A10: USART 1 for talking to the ESP - set_gpio_alternate(GPIOA, 9, GPIO_AF7_USART1); - set_gpio_alternate(GPIOA, 10, GPIO_AF7_USART1); - - // B12: GMLAN, ignition sense, pull up - set_gpio_pullup(GPIOB, 12, PULL_UP); - - // A4,A5,A6,A7: setup SPI - set_gpio_alternate(GPIOA, 4, GPIO_AF5_SPI1); - set_gpio_alternate(GPIOA, 5, GPIO_AF5_SPI1); - set_gpio_alternate(GPIOA, 6, GPIO_AF5_SPI1); - set_gpio_alternate(GPIOA, 7, GPIO_AF5_SPI1); -#endif - - #ifdef PANDA - // K-line enable moved from B4->B7 to make room for GMLAN on CAN3 - if(revision == REV_C) - set_gpio_output(GPIOB, 7, 1); // REV C - else - set_gpio_output(GPIOB, 4, 1); // REV AB - - // C12,D2: K-Line setup on UART 5 - set_gpio_alternate(GPIOC, 12, GPIO_AF8_UART5); - set_gpio_alternate(GPIOD, 2, GPIO_AF8_UART5); - set_gpio_pullup(GPIOD, 2, PULL_UP); - - // L-line enable - set_gpio_output(GPIOA, 14, 1); - - // C10,C11: L-Line setup on USART 3 - set_gpio_alternate(GPIOC, 10, GPIO_AF7_USART3); - set_gpio_alternate(GPIOC, 11, GPIO_AF7_USART3); - set_gpio_pullup(GPIOC, 11, PULL_UP); - #endif - - if(revision == REV_C) { - // B2,A13: set DCP mode on the charger (breaks USB!) - //set_gpio_output(GPIOB, 2, 0); - //set_gpio_output(GPIOA, 13, 0); - - //set_gpio_output(GPIOA, 13, 1); //CTRL 1 - //set_gpio_output(GPIOB, 2, 0); //CTRL 2 - } -} diff --git a/board/gpio.h b/board/gpio.h index 6398fe6..c0910fb 100644 --- a/board/gpio.h +++ b/board/gpio.h @@ -1,9 +1,278 @@ -void set_can_enable(uint8_t canid, int enabled); +#ifdef STM32F4 + #include "stm32f4xx_hal_gpio_ex.h" +#else + #include "stm32f2xx_hal_gpio_ex.h" +#endif + +#include "llgpio.h" + +void set_can_enable(CAN_TypeDef *CAN, int enabled) { + // enable CAN busses + if (CAN == CAN1) { + #ifdef PANDA + // CAN1_EN + set_gpio_output(GPIOC, 1, !enabled); + #else + // CAN1_EN + set_gpio_output(GPIOB, 3, enabled); + #endif + } else if (CAN == CAN2) { + #ifdef PANDA + // CAN2_EN + set_gpio_output(GPIOC, 13, !enabled); + #else + // CAN2_EN + set_gpio_output(GPIOB, 4, enabled); + #endif + #ifdef CAN3 + } else if (CAN == CAN3) { + // CAN3_EN + set_gpio_output(GPIOA, 0, !enabled); + #endif + } +} + +#ifdef PANDA + #define LED_RED 9 + #define LED_GREEN 7 + #define LED_BLUE 6 +#else + #define LED_RED 10 + #define LED_GREEN 11 + #define LED_BLUE -1 +#endif + +void set_led(int led_num, int on) { + if (led_num == -1) return; + + #ifdef PANDA + set_gpio_output(GPIOC, led_num, !on); + #else + set_gpio_output(GPIOB, led_num, !on); + #endif +} -void set_led(int led_num, int on); // TODO: does this belong here? -void periph_init(); +void periph_init() { + // enable GPIOB, UART2, CAN, USB clock + RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; + RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN; + RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN; + RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; + + RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; + RCC->APB1ENR |= RCC_APB1ENR_USART2EN; + RCC->APB1ENR |= RCC_APB1ENR_USART3EN; + #ifdef PANDA + RCC->APB1ENR |= RCC_APB1ENR_UART5EN; + #endif + RCC->APB1ENR |= RCC_APB1ENR_CAN1EN; + RCC->APB1ENR |= RCC_APB1ENR_CAN2EN; + #ifdef CAN3 + RCC->APB1ENR |= RCC_APB1ENR_CAN3EN; + #endif + RCC->APB1ENR |= RCC_APB1ENR_DACEN; + RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; + //RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; + RCC->APB2ENR |= RCC_APB2ENR_USART1EN; + RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN; + RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; + RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; + RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; + + // needed? + RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; +} + +void set_can_mode(int can, int use_gmlan) { + // http://www.bittiming.can-wiki.info/#bxCAN + // 24 MHz, sample point at 87.5% + uint32_t pclk = 24000; + uint32_t num_time_quanta = 16; + uint32_t prescaler; + CAN_TypeDef *CAN = NULL; + if (can == 2) CAN = CAN2; +#ifdef CAN3 + else if (can == 3) CAN = CAN3; +#endif + if (CAN == NULL) return; + + // connects to CAN2 xcvr or GMLAN xcvr + if (use_gmlan) { + if (can == 2) { + // B5,B6: disable normal mode + set_gpio_mode(GPIOB, 5, MODE_INPUT); + set_gpio_mode(GPIOB, 6, MODE_INPUT); + + // B12,B13: gmlan mode + set_gpio_alternate(GPIOB, 12, GPIO_AF9_CAN2); + set_gpio_alternate(GPIOB, 13, GPIO_AF9_CAN2); + + /* GMLAN mode pins: + M0(B15) M1(B14) mode + ======================= + 0 0 sleep + 1 0 100kbit + 0 1 high voltage wakeup + 1 1 33kbit (normal) + */ + + } else if (revision == PANDA_REV_C && can == 3) { + // A8,A15: disable normal mode + set_gpio_mode(GPIOA, 8, MODE_INPUT); + set_gpio_mode(GPIOA, 15, MODE_INPUT); + + // B3,B4: enable gmlan mode + set_gpio_alternate(GPIOB, 3, GPIO_AF11_CAN3); + set_gpio_alternate(GPIOB, 4, GPIO_AF11_CAN3); + } + + // put gmlan transceiver in normal mode + set_gpio_output(GPIOB, 14, 1); + set_gpio_output(GPIOB, 15, 1); + + // 83.3 kbps + // prescaler = pclk / num_time_quanta * 10 / 833; + + // 33.3 kbps + prescaler = pclk / num_time_quanta * 10 / 333; + } else { + if (can == 2) { + // B12,B13: disable gmlan mode + set_gpio_mode(GPIOB, 12, MODE_INPUT); + set_gpio_mode(GPIOB, 13, MODE_INPUT); + + // B5,B6: normal mode + set_gpio_alternate(GPIOB, 5, GPIO_AF9_CAN2); + set_gpio_alternate(GPIOB, 6, GPIO_AF9_CAN2); + } else if (can == 3) { + if(revision == PANDA_REV_C){ + // B3,B4: disable gmlan mode + set_gpio_mode(GPIOB, 3, MODE_INPUT); + set_gpio_mode(GPIOB, 4, MODE_INPUT); + } + + // A8,A15: normal mode + set_gpio_alternate(GPIOA, 8, GPIO_AF11_CAN3); + set_gpio_alternate(GPIOA, 15, GPIO_AF11_CAN3); + } + + // 500 kbps + prescaler = pclk / num_time_quanta / 500; + } + + // init + CAN->MCR = CAN_MCR_TTCM | CAN_MCR_INRQ; + while((CAN->MSR & CAN_MSR_INAK) != CAN_MSR_INAK); + + // set speed + // seg 1: 13 time quanta, seg 2: 2 time quanta + CAN->BTR = (CAN_BTR_TS1_0 * 12) | + CAN_BTR_TS2_0 | (prescaler - 1); + + // running + CAN->MCR = CAN_MCR_TTCM; + while((CAN->MSR & CAN_MSR_INAK) == CAN_MSR_INAK); +} // board specific -void gpio_init(); +void gpio_init() { + // pull low to hold ESP in reset?? + // enable OTG out tied to ground + GPIOA->ODR = 0; + GPIOB->ODR = 0; + GPIOA->PUPDR = 0; + //GPIOC->ODR = 0; + GPIOB->AFR[0] = 0; + GPIOB->AFR[1] = 0; + + // C2,C3: analog mode, voltage and current sense + set_gpio_mode(GPIOC, 2, MODE_ANALOG); + set_gpio_mode(GPIOC, 3, MODE_ANALOG); + + // C8: FAN aka TIM3_CH4 + set_gpio_alternate(GPIOC, 8, GPIO_AF2_TIM3); + + // turn off LEDs and set mode + set_led(LED_RED, 0); + set_led(LED_GREEN, 0); + set_led(LED_BLUE, 0); + + // A11,A12: USB + set_gpio_alternate(GPIOA, 11, GPIO_AF10_OTG_FS); + set_gpio_alternate(GPIOA, 12, GPIO_AF10_OTG_FS); + GPIOA->OSPEEDR = GPIO_OSPEEDER_OSPEEDR11 | GPIO_OSPEEDER_OSPEEDR12; + +#ifdef PANDA + // enable started_alt on the panda + set_gpio_pullup(GPIOA, 1, PULL_UP); + + // A2,A3: USART 2 for debugging + set_gpio_alternate(GPIOA, 2, GPIO_AF7_USART2); + set_gpio_alternate(GPIOA, 3, GPIO_AF7_USART2); + + // A9,A10: USART 1 for talking to the ESP + set_gpio_alternate(GPIOA, 9, GPIO_AF7_USART1); + set_gpio_alternate(GPIOA, 10, GPIO_AF7_USART1); + + // B12: GMLAN, ignition sense, pull up + set_gpio_pullup(GPIOB, 12, PULL_UP); + + // A4,A5,A6,A7: setup SPI + set_gpio_alternate(GPIOA, 4, GPIO_AF5_SPI1); + set_gpio_alternate(GPIOA, 5, GPIO_AF5_SPI1); + set_gpio_alternate(GPIOA, 6, GPIO_AF5_SPI1); + set_gpio_alternate(GPIOA, 7, GPIO_AF5_SPI1); +#endif + + // B8,B9: CAN 1 + set_can_enable(CAN1, 0); +#ifdef STM32F4 + set_gpio_alternate(GPIOB, 8, GPIO_AF8_CAN1); + set_gpio_alternate(GPIOB, 9, GPIO_AF8_CAN1); +#else + set_gpio_alternate(GPIOB, 8, GPIO_AF9_CAN1); + set_gpio_alternate(GPIOB, 9, GPIO_AF9_CAN1); +#endif + + // B5,B6: CAN 2 + set_can_enable(CAN2, 0); + set_can_mode(2, 0); + + // A8,A15: CAN3 + #ifdef CAN3 + set_can_enable(CAN3, 0); + set_can_mode(3, 0); + #endif + + #ifdef PANDA + // K-line enable moved from B4->B7 to make room for GMLAN on CAN3 + if(revision == PANDA_REV_C) + set_gpio_output(GPIOB, 7, 1); // REV C + else + set_gpio_output(GPIOB, 4, 1); // REV AB + + // C12,D2: K-Line setup on UART 5 + set_gpio_alternate(GPIOC, 12, GPIO_AF8_UART5); + set_gpio_alternate(GPIOD, 2, GPIO_AF8_UART5); + set_gpio_pullup(GPIOD, 2, PULL_UP); + + // L-line enable + set_gpio_output(GPIOA, 14, 1); + + // C10,C11: L-Line setup on USART 3 + set_gpio_alternate(GPIOC, 10, GPIO_AF7_USART3); + set_gpio_alternate(GPIOC, 11, GPIO_AF7_USART3); + set_gpio_pullup(GPIOC, 11, PULL_UP); + #endif + + if(revision == PANDA_REV_C) { + // B2,A13: set DCP mode on the charger (breaks USB!) + //set_gpio_output(GPIOB, 2, 0); + //set_gpio_output(GPIOA, 13, 0); + + //set_gpio_output(GPIOA, 13, 1); //CTRL 1 + //set_gpio_output(GPIOB, 2, 0); //CTRL 2 + } +} diff --git a/board/safety_honda.h b/board/honda_safety.h similarity index 81% rename from board/safety_honda.h rename to board/honda_safety.h index 0b74011..99f209a 100644 --- a/board/safety_honda.h +++ b/board/honda_safety.h @@ -4,15 +4,14 @@ // out-state // cancel button -#include "safety.h" -#include "can.h" // all commands: brake and steering // if controls_allowed // allow all commands up to limit // else // block all commands that produce actuation -void honda__rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { + +void safety_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { // state machine to enter and exit controls // 0x1A6 for the ILX, 0x296 for the Civic Touring if ((to_push->RIR>>21) == 0x1A6 || (to_push->RIR>>21) == 0x296) { @@ -51,7 +50,7 @@ void honda__rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { } } -int honda__tx_hook(CAN_FIFOMailBox_TypeDef *to_send, int hardwired) { +int safety_tx_hook(CAN_FIFOMailBox_TypeDef *to_send, int hardwired) { // BRAKE: safety check if ((to_send->RIR>>21) == 0x1FA) { if (controls_allowed) { @@ -68,7 +67,7 @@ int honda__tx_hook(CAN_FIFOMailBox_TypeDef *to_send, int hardwired) { } else { to_send->RDLR &= 0xFFFF0000; } - } + } // GAS: safety check if ((to_send->RIR>>21) == 0x200) { @@ -77,23 +76,13 @@ int honda__tx_hook(CAN_FIFOMailBox_TypeDef *to_send, int hardwired) { } else { to_send->RDLR &= 0xFFFF0000; } - } + } // 1 allows the message through return hardwired; } -int honda__tx_lin_hook(int lin_num, uint8_t *data, int len, int hardwired) { +int safety_tx_lin_hook(int lin_num, uint8_t *data, int len, int hardwired) { return hardwired; } -void honda__init() { - controls_allowed = true; -} - -const safety_hooks honda_hooks = { - .init = honda__init, - .rx = honda__rx_hook, - .tx = honda__tx_hook, - .tx_lin = honda__tx_lin_hook, -}; diff --git a/board/libc.c b/board/libc.c deleted file mode 100644 index b6b3d8e..0000000 --- a/board/libc.c +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include "config.h" -#include "libc.h" - -void clock_init() { - // enable external oscillator - RCC->CR |= RCC_CR_HSEON; - while ((RCC->CR & RCC_CR_HSERDY) == 0); - - // divide shit - RCC->CFGR = RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE2_DIV2 | RCC_CFGR_PPRE1_DIV4; - #ifdef PANDA - RCC->PLLCFGR = RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 | - RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLN_5 | RCC_PLLCFGR_PLLSRC_HSE; - #else - RCC->PLLCFGR = RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 | - RCC_PLLCFGR_PLLN_7 | RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLSRC_HSE; - #endif - - // start PLL - RCC->CR |= RCC_CR_PLLON; - while ((RCC->CR & RCC_CR_PLLRDY) == 0); - - // Configure Flash prefetch, Instruction cache, Data cache and wait state - // *** without this, it breaks *** - FLASH->ACR = FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_5WS; - - // switch to PLL - RCC->CFGR |= RCC_CFGR_SW_PLL; - while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); - - // *** running on PLL *** -} - - -void delay(int a) { - volatile int i; - for (i=0;iCR |= RCC_CR_HSEON; + while ((RCC->CR & RCC_CR_HSERDY) == 0); -void delay(int a); + // divide shit + RCC->CFGR = RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE2_DIV2 | RCC_CFGR_PPRE1_DIV4; + #ifdef PANDA + RCC->PLLCFGR = RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 | + RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLN_5 | RCC_PLLCFGR_PLLSRC_HSE; + #else + RCC->PLLCFGR = RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 | + RCC_PLLCFGR_PLLN_7 | RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLSRC_HSE; + #endif -void *memset(void *str, int c, unsigned int n); + // start PLL + RCC->CR |= RCC_CR_PLLON; + while ((RCC->CR & RCC_CR_PLLRDY) == 0); -void *memcpy(void *dest, const void *src, unsigned int n); + // Configure Flash prefetch, Instruction cache, Data cache and wait state + // *** without this, it breaks *** + FLASH->ACR = FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_5WS; -int memcmp(const void * ptr1, const void * ptr2, unsigned int num); + // switch to PLL + RCC->CFGR |= RCC_CFGR_SW_PLL; + while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); -#endif + // *** running on PLL *** +} + + +void delay(int a) { + volatile int i; + for (i=0;i TO +#define CAN_MAX 3 +int can_forwarding[] = {-1,-1,-1}; + +// *** end config *** + +#include "obj/gitversion.h" + +// debug safety check: is controls allowed? +int controls_allowed = 0; int started = 0; +int can_live = 0, pending_can_live = 0; // optional features +int gas_interceptor_detected = 0; int started_signal_detected = 0; +// detect high on UART +// TODO: check for UART high +int did_usb_enumerate = 0; + +// Declare puts to supress warning +int puts ( const char * str ); + +// ********************* instantiate queues ********************* + +typedef struct { + uint32_t w_ptr; + uint32_t r_ptr; + uint32_t fifo_size; + CAN_FIFOMailBox_TypeDef *elems; +} can_ring; + +#define can_buffer(x, size) \ + CAN_FIFOMailBox_TypeDef elems_##x[size]; \ + can_ring can_##x = { .w_ptr = 0, .r_ptr = 0, .fifo_size = size, .elems = (CAN_FIFOMailBox_TypeDef *)&elems_##x }; + +can_buffer(rx_q, 0x1000) +can_buffer(tx1_q, 0x100) +can_buffer(tx2_q, 0x100) +can_buffer(tx3_q, 0x100) + +// ********************* interrupt safe queue ********************* + +int pop(can_ring *q, CAN_FIFOMailBox_TypeDef *elem) { + if (q->w_ptr != q->r_ptr) { + *elem = q->elems[q->r_ptr]; + if ((q->r_ptr + 1) == q->fifo_size) q->r_ptr = 0; + else q->r_ptr += 1; + return 1; + } + return 0; +} + +int push(can_ring *q, CAN_FIFOMailBox_TypeDef *elem) { + uint32_t next_w_ptr; + if ((q->w_ptr + 1) == q->fifo_size) next_w_ptr = 0; + else next_w_ptr = q->w_ptr + 1; + if (next_w_ptr != q->r_ptr) { + q->elems[q->w_ptr] = *elem; + q->w_ptr = next_w_ptr; + return 1; + } + puts("push failed!\n"); + return 0; +} + +// ***************************** serial port queues ***************************** + +#define FIFO_SIZE 0x100 + +typedef struct uart_ring { + uint8_t w_ptr_tx; + uint8_t r_ptr_tx; + uint8_t elems_tx[FIFO_SIZE]; + uint8_t w_ptr_rx; + uint8_t r_ptr_rx; + uint8_t elems_rx[FIFO_SIZE]; + USART_TypeDef *uart; + void (*callback)(struct uart_ring*); +} uart_ring; + +int getc(uart_ring *q, char *elem); +int putc(uart_ring *q, char elem); + +// esp = USART1 +uart_ring esp_ring = { .w_ptr_tx = 0, .r_ptr_tx = 0, + .w_ptr_rx = 0, .r_ptr_rx = 0, + .uart = USART1 }; + +// lin1, K-LINE = UART5 +// lin2, L-LINE = USART3 +uart_ring lin1_ring = { .w_ptr_tx = 0, .r_ptr_tx = 0, + .w_ptr_rx = 0, .r_ptr_rx = 0, + .uart = UART5 }; +uart_ring lin2_ring = { .w_ptr_tx = 0, .r_ptr_tx = 0, + .w_ptr_rx = 0, .r_ptr_rx = 0, + .uart = USART3 }; + +// debug = USART2 +void debug_ring_callback(uart_ring *ring); +uart_ring debug_ring = { .w_ptr_tx = 0, .r_ptr_tx = 0, + .w_ptr_rx = 0, .r_ptr_rx = 0, + .uart = USART2, + .callback = debug_ring_callback}; + + +uart_ring *get_ring_by_number(int a) { + switch(a) { + case 0: + return &debug_ring; + case 1: + return &esp_ring; + case 2: + return &lin1_ring; + case 3: + return &lin2_ring; + default: + return NULL; + } +} + void accord_framing_callback(uart_ring *q) { uint8_t r_ptr_rx_tmp = q->r_ptr_rx; int sof1 = -1; @@ -77,6 +196,264 @@ void accord_framing_callback(uart_ring *q) { } } +void debug_ring_callback(uart_ring *ring) { + char rcv; + while (getc(ring, &rcv)) { + putc(ring, rcv); + + // jump to DFU flash + if (rcv == 'z') { + enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC; + NVIC_SystemReset(); + } + if (rcv == 'x') { + // normal reset + NVIC_SystemReset(); + } + } +} + +// ***************************** serial port ***************************** + +void uart_ring_process(uart_ring *q) { + // TODO: check if external serial is connected + int sr = q->uart->SR; + + if (q->w_ptr_tx != q->r_ptr_tx) { + if (sr & USART_SR_TXE) { + q->uart->DR = q->elems_tx[q->r_ptr_tx]; + q->r_ptr_tx += 1; + } else { + // push on interrupt later + q->uart->CR1 |= USART_CR1_TXEIE; + } + } else { + // nothing to send + q->uart->CR1 &= ~USART_CR1_TXEIE; + } + + if (sr & USART_SR_RXNE) { + uint8_t c = q->uart->DR; // TODO: can drop packets + uint8_t next_w_ptr = q->w_ptr_rx + 1; + if (next_w_ptr != q->r_ptr_rx) { + q->elems_rx[q->w_ptr_rx] = c; + q->w_ptr_rx = next_w_ptr; + if (q->callback) q->callback(q); + } + } +} + +// interrupt boilerplate + +void USART1_IRQHandler(void) { + NVIC_DisableIRQ(USART1_IRQn); + uart_ring_process(&esp_ring); + NVIC_EnableIRQ(USART1_IRQn); +} + +void USART2_IRQHandler(void) { + NVIC_DisableIRQ(USART2_IRQn); + uart_ring_process(&debug_ring); + NVIC_EnableIRQ(USART2_IRQn); +} + +void USART3_IRQHandler(void) { + NVIC_DisableIRQ(USART3_IRQn); + uart_ring_process(&lin2_ring); + NVIC_EnableIRQ(USART3_IRQn); +} + +void UART5_IRQHandler(void) { + NVIC_DisableIRQ(UART5_IRQn); + uart_ring_process(&lin1_ring); + NVIC_EnableIRQ(UART5_IRQn); +} + +int getc(uart_ring *q, char *elem) { + if (q->w_ptr_rx != q->r_ptr_rx) { + *elem = q->elems_rx[q->r_ptr_rx]; + q->r_ptr_rx += 1; + return 1; + } + return 0; +} + +int injectc(uart_ring *q, char elem) { + uint8_t next_w_ptr = q->w_ptr_rx + 1; + int ret = 0; + if (next_w_ptr != q->r_ptr_rx) { + q->elems_rx[q->w_ptr_rx] = elem; + q->w_ptr_rx = next_w_ptr; + ret = 1; + } + return ret; +} + +int putc(uart_ring *q, char elem) { + uint8_t next_w_ptr = q->w_ptr_tx + 1; + int ret = 0; + if (next_w_ptr != q->r_ptr_tx) { + q->elems_tx[q->w_ptr_tx] = elem; + q->w_ptr_tx = next_w_ptr; + ret = 1; + } + uart_ring_process(q); + return ret; +} + +// ********************* includes ********************* + +#include "libc.h" +#include "gpio.h" +#include "uart.h" +#include "adc.h" +#include "timer.h" +#include "usb.h" +#include "can.h" +#include "spi.h" + +void safety_rx_hook(CAN_FIFOMailBox_TypeDef *to_push); +int safety_tx_hook(CAN_FIFOMailBox_TypeDef *to_send, int hardwired); +int safety_tx_lin_hook(int lin_num, uint8_t *data, int len, int hardwired); + +#ifdef PANDA_SAFETY +#include "panda_safety.h" +#else +#include "honda_safety.h" +#endif + +// ***************************** CAN ***************************** + +void process_can(CAN_TypeDef *CAN, can_ring *can_q, int can_number) { + #ifdef DEBUG + puts("process CAN TX\n"); + #endif + + // add successfully transmitted message to my fifo + if ((CAN->TSR & CAN_TSR_TXOK0) == CAN_TSR_TXOK0) { + CAN_FIFOMailBox_TypeDef to_push; + to_push.RIR = CAN->sTxMailBox[0].TIR; + to_push.RDTR = (CAN->sTxMailBox[0].TDTR & 0xFFFF000F) | ((can_number+2) << 4); + to_push.RDLR = CAN->sTxMailBox[0].TDLR; + to_push.RDHR = CAN->sTxMailBox[0].TDHR; + push(&can_rx_q, &to_push); + } + + // check for empty mailbox + CAN_FIFOMailBox_TypeDef to_send; + if ((CAN->TSR & CAN_TSR_TME0) == CAN_TSR_TME0) { + if (pop(can_q, &to_send)) { + // only send if we have received a packet + CAN->sTxMailBox[0].TDLR = to_send.RDLR; + CAN->sTxMailBox[0].TDHR = to_send.RDHR; + CAN->sTxMailBox[0].TDTR = to_send.RDTR; + CAN->sTxMailBox[0].TIR = to_send.RIR; + } + } + + // clear interrupt + CAN->TSR |= CAN_TSR_RQCP0; +} + +// send more, possible for these to not trigger? + + +void CAN1_TX_IRQHandler() { + process_can(CAN1, &can_tx1_q, can_numbering[0]); +} + +void CAN2_TX_IRQHandler() { + process_can(CAN2, &can_tx2_q, can_numbering[1]); +} + +#ifdef CAN3 +void CAN3_TX_IRQHandler() { + process_can(CAN3, &can_tx3_q, can_numbering[2]); +} +#endif + +void send_can(CAN_FIFOMailBox_TypeDef *to_push, int flags); + +// CAN receive handlers +// blink blue when we are receiving CAN messages +void can_rx(CAN_TypeDef *CAN, int can_index) { + int can_number = can_numbering[can_index]; + while (CAN->RF0R & CAN_RF0R_FMP0) { + // can is live + pending_can_live = 1; + + // add to my fifo + CAN_FIFOMailBox_TypeDef to_push; + to_push.RIR = CAN->sFIFOMailBox[0].RIR; + to_push.RDTR = CAN->sFIFOMailBox[0].RDTR; + to_push.RDLR = CAN->sFIFOMailBox[0].RDLR; + to_push.RDHR = CAN->sFIFOMailBox[0].RDHR; + + // forwarding (panda only) + #ifdef PANDA + if (can_forwarding[can_index] != -1 && can_numbering[can_forwarding[can_index]] != -1) { + CAN_FIFOMailBox_TypeDef to_send; + to_send.RIR = to_push.RIR | 1; // TXRQ + to_send.RDTR = to_push.RDTR; + to_send.RDLR = to_push.RDLR; + to_send.RDHR = to_push.RDHR; + send_can(&to_send, can_numbering[can_forwarding[can_index]]); + } + #endif + + // modify RDTR for our API + to_push.RDTR = (to_push.RDTR & 0xFFFF000F) | (can_number << 4); + + safety_rx_hook(&to_push); + + #ifdef PANDA + set_led(LED_GREEN, 1); + #endif + push(&can_rx_q, &to_push); + + // next + CAN->RF0R |= CAN_RF0R_RFOM0; + } +} + +void CAN1_RX0_IRQHandler() { + //puts("CANRX1"); + //delay(10000); + can_rx(CAN1, 0); +} + +void CAN2_RX0_IRQHandler() { + //puts("CANRX0"); + //delay(10000); + can_rx(CAN2, 1); +} + +#ifdef CAN3 +void CAN3_RX0_IRQHandler() { + //puts("CANRX0"); + //delay(10000); + can_rx(CAN3, 2); +} +#endif + +void CAN1_SCE_IRQHandler() { + //puts("CAN1_SCE\n"); + can_sce(CAN1); +} + +void CAN2_SCE_IRQHandler() { + //puts("CAN2_SCE\n"); + can_sce(CAN2); +} + +#ifdef CAN3 +void CAN3_SCE_IRQHandler() { + //puts("CAN3_SCE\n"); + can_sce(CAN3); +} +#endif + + // ***************************** USB port ***************************** int get_health_pkt(void *dat) { @@ -103,7 +480,7 @@ int get_health_pkt(void *dat) { health->started_alt = 0; #endif - health->controls_allowed = is_output_enabled(); + health->controls_allowed = controls_allowed; health->gas_interceptor_detected = gas_interceptor_detected; health->started_signal_detected = started_signal_detected; @@ -114,20 +491,6 @@ void set_fan_speed(int fan_speed) { TIM3->CCR3 = fan_speed; } -void usb_cb_ep0_out(USB_Setup_TypeDef *setup, uint8_t *usbdata, int hardwired) { - if (setup->b.bRequest == 0xde) { - puts("Setting baud rate from usb\n"); - uint32_t bitrate = *(int*)usbdata; - uint16_t canb_id = setup->b.wValue.w; - - if (can_ports[canb_id].gmlan) - can_ports[canb_id].gmlan_bitrate = bitrate; - else - can_ports[canb_id].bitrate = bitrate; - can_init(canb_id); - } -} - int usb_cb_ep1_in(uint8_t *usbdata, int len, int hardwired) { CAN_FIFOMailBox_TypeDef *reply = (CAN_FIFOMailBox_TypeDef *)usbdata;; @@ -148,9 +511,44 @@ void usb_cb_ep2_out(uint8_t *usbdata, int len, int hardwired) { } } +void send_can(CAN_FIFOMailBox_TypeDef *to_push, int flags) { + int i; + CAN_TypeDef *CAN; + can_ring *can_q; + if (flags == can_numbering[0]) { + CAN = CAN1; + can_q = &can_tx1_q; + } else if (flags == can_numbering[1]) { + CAN = CAN2; + can_q = &can_tx2_q; + #ifdef CAN3 + } else if (flags == can_numbering[2]) { + CAN = CAN3; + can_q = &can_tx3_q; + #endif + } else if (flags == 8 || flags == 9) { + // fake LIN as CAN + uart_ring *lin_ring = (flags == 8) ? &lin1_ring : &lin2_ring; + for (i = 0; i < min(8, to_push->RDTR & 0xF); i++) { + putc(lin_ring, ((uint8_t*)&to_push->RDLR)[i]); + } + return; + } else { + // no crash + return; + } + + // add CAN packet to send queue + // bus number isn't passed through + to_push->RDTR &= 0xF; + push(can_q, to_push); + + // flags = can_number + process_can(CAN, can_q, flags); +} + // send on CAN void usb_cb_ep3_out(uint8_t *usbdata, int len, int hardwired) { - puts("usb_cb_ep3_out called\n"); int dpkt = 0; for (dpkt = 0; dpkt < len; dpkt += 0x10) { uint32_t *tf = (uint32_t*)(&usbdata[dpkt]); @@ -162,13 +560,21 @@ void usb_cb_ep3_out(uint8_t *usbdata, int len, int hardwired) { to_push.RDTR = tf[1]; to_push.RIR = tf[0]; - uint8_t canid = (to_push.RDTR >> 4) & 0xF; + int flags = (to_push.RDTR >> 4) & 0xF; if (safety_tx_hook(&to_push, hardwired)) { - send_can(&to_push, canid); + send_can(&to_push, flags); } } } +void usb_cb_enumeration_complete() { + // power down the ESP + // this doesn't work and makes the board unflashable + // because the ESP spews shit on serial on startup + //GPIOC->ODR &= ~(1 << 14); + did_usb_enumerate = 1; +} + int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) { int resp_len = 0; uart_ring *ur = NULL; @@ -235,75 +641,31 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) { } break; case 0xdb: // toggle GMLAN - puts("Toggle GMLAN canid: "); - puth(setup->b.wValue.w); - - uint16_t canid = setup->b.wValue.w; - bool gmlan_enable = setup->b.wIndex.w; - - puth(canid); - puts(" mode "); - puth(gmlan_enable); - puts("\n"); - - if (canid >= CAN_MAX) { - puts(" !!Out of range!!\n"); - return -1; + if (setup->b.wIndex.w == 3) { + set_can_mode(2, 0); + set_can_mode(3, setup->b.wValue.w); + } else { + set_can_mode(3, 0); + set_can_mode(2, setup->b.wValue.w); } - - can_port_desc *port = &can_ports[canid]; - - //puts(" gmlan_support "); - //puth(port->gmlan_support); - //puts(" mode "); - //puth(gmlan_enable); - //puts("\n"); - - //Fail if canid doesn't support gmlan - if (!port->gmlan_support) { - puts(" !!Unsupported!!\n"); - return -1; - } - - //ACK the USB pipe but don't do anything; nothing to do. - if (port->gmlan == gmlan_enable) { - puts(" ~~Nochange~~.\n"); - break; - } - - // Check to see if anyther canid is acting as gmlan, disable it. - set_can_mode(canid, gmlan_enable); - puts(" Done\n"); break; - case 0xdc: // set controls allowed / safety policy - set_safety_mode(setup->b.wValue.w); - for(i=0; i < CAN_MAX; i++) - can_init(i); + case 0xdc: // set controls allowed + controls_allowed = setup->b.wValue.w == 0x1337; + // take CAN out of SILM, careful with speed! + can_init(CAN1, 0); + can_init(CAN2, 0); + #ifdef CAN3 + can_init(CAN3, 0); + #endif break; case 0xdd: // enable can forwarding - if (setup->b.wValue.w < CAN_MAX) { //Set forwarding - can_ports[setup->b.wValue.w].forwarding = setup->b.wIndex.w; - } else if (setup->b.wValue.w == 0xFF) { //Clear Forwarding - can_ports[setup->b.wValue.w].forwarding = -1; - } else - return -1; - break; - case 0xde: // Set Can bitrate - if (!(setup->b.wValue.w < CAN_MAX && setup->b.wLength.w == 4)) - return -1; - break; - case 0xdf: // Get Can bitrate - if (setup->b.wValue.w < CAN_MAX) { - if(can_ports[setup->b.wValue.w].gmlan){ - memcpy(resp, (void *)&can_ports[setup->b.wValue.w].gmlan_bitrate, 4); - }else{ - memcpy(resp, (void *)&can_ports[setup->b.wValue.w].bitrate, 4); + if (setup->b.wValue.w != 0 && setup->b.wValue.w <= CAN_MAX) { + // 0 sets it to -1 + if (setup->b.wIndex.w <= CAN_MAX) { + can_forwarding[setup->b.wValue.w-1] = setup->b.wIndex.w-1; } - resp_len = 4; - break; } - puts("Invalid num\n"); - return -1; + break; case 0xe0: // uart read ur = get_ring_by_number(setup->b.wValue.w); if (!ur) break; @@ -353,11 +715,6 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) { if (!ur) break; uart_set_baud(ur->uart, (int)setup->b.wIndex.w*300); break; - case 0xe5: // Set CAN loopback (for testing) - can_loopback = (setup->b.wValue.w > 0); - for(i=0; i < CAN_MAX; i++) - can_init(i); - break; case 0xf0: // k-line wValue pulse on uart2 if (setup->b.wValue.w == 1) { GPIOC->ODR &= ~(1 << 10); @@ -394,11 +751,12 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) { puts("NO HANDLER "); puth(setup->b.bRequest); puts("\n"); - return -1; + break; } return resp_len; } + void OTG_FS_IRQHandler(void) { NVIC_DisableIRQ(OTG_FS_IRQn); //__disable_irq(); @@ -419,9 +777,7 @@ int spi_buf_count = 0; int spi_total_count = 0; uint8_t spi_tx_buf[0x44]; -//TODO Jessy: Audit for overflows void handle_spi(uint8_t *data, int len) { - USB_Setup_TypeDef *fake_setup; memset(spi_tx_buf, 0xaa, 0x44); // data[0] = endpoint // data[2] = length @@ -431,11 +787,7 @@ void handle_spi(uint8_t *data, int len) { switch (data[0]) { case 0: // control transfer - fake_setup = (USB_Setup_TypeDef *)(data+4); - *resp_len = usb_cb_control_msg(fake_setup, spi_tx_buf+4, 0); - // Handle CTRL writes with data - if (*resp_len == 0 && (fake_setup->b.bmRequestType & 0x80) == 0 && fake_setup->b.wLength.w) - usb_cb_ep0_out(fake_setup, data+4+sizeof(USB_Setup_TypeDef), 0); + *resp_len = usb_cb_control_msg((USB_Setup_TypeDef *)(data+4), spi_tx_buf+4, 0); break; case 1: // ep 1, read @@ -496,8 +848,6 @@ void __initialize_hardware_early() { } int main() { - int i; - // init devices clock_init(); periph_init(); @@ -517,11 +867,27 @@ int main() { uart_init(USART3, 10400); USART3->CR2 |= USART_CR2_LINEN; + /*puts("EXTERNAL"); + puth(has_external_debug_serial); + puts("\n");*/ + // enable USB usb_init(); - for(i=0; i < CAN_MAX; i++) - can_init(i); + // default to silent mode to prevent issues with Ford +#ifdef PANDA_SAFETY + can_init(CAN1, 1); + can_init(CAN2, 1); + #ifdef CAN3 + can_init(CAN3, 1); + #endif +#else + can_init(CAN1, 0); + can_init(CAN2, 0); + #ifdef CAN3 + can_init(CAN3, 0); + #endif +#endif adc_init(); @@ -544,6 +910,7 @@ int main() { // set PWM set_fan_speed(65535); + puts("**** INTERRUPTS ON ****\n"); __disable_irq(); @@ -594,11 +961,21 @@ int main() { // reset this every 16th pass if ((cnt&0xF) == 0) pending_can_live = 0; + /*#ifdef DEBUG + puts("** blink "); + puth(can_rx_q.r_ptr); puts(" "); puth(can_rx_q.w_ptr); puts(" "); + puth(can_tx1_q.r_ptr); puts(" "); puth(can_tx1_q.w_ptr); puts(" "); + puth(can_tx2_q.r_ptr); puts(" "); puth(can_tx2_q.w_ptr); puts("\n"); + #endif*/ + + /*puts("voltage: "); puth(adc_get(ADCCHAN_VOLTAGE)); puts(" "); + puts("current: "); puth(adc_get(ADCCHAN_CURRENT)); puts("\n");*/ + // set LED to be controls allowed, blue on panda, green on legacy #ifdef PANDA - set_led(LED_BLUE, is_output_enabled()); + set_led(LED_BLUE, controls_allowed); #else - set_led(LED_GREEN, is_output_enabled()); + set_led(LED_GREEN, controls_allowed); #endif // blink the red LED @@ -612,6 +989,13 @@ int main() { set_led(LED_GREEN, 0); #endif + #ifdef ENABLE_SPI + /*if (spi_buf_count > 0) { + hexdump(spi_buf, spi_buf_count); + spi_buf_count = 0; + }*/ + #endif + // started logic #ifdef PANDA int started_signal = (GPIOB->IDR & (1 << 12)) == 0; diff --git a/board/obj/.placeholder b/board/obj/.placeholder new file mode 100644 index 0000000..e69de29 diff --git a/board/panda_safety.h b/board/panda_safety.h new file mode 100644 index 0000000..c6eb36a --- /dev/null +++ b/board/panda_safety.h @@ -0,0 +1,13 @@ +// pandas by default do not allow sending in this firmware + +void safety_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { +} + +int safety_tx_hook(CAN_FIFOMailBox_TypeDef *to_send, int hardwired) { + return hardwired && controls_allowed; +} + +int safety_tx_lin_hook(int lin_num, uint8_t *data, int len, int hardwired) { + return hardwired && controls_allowed; +} + diff --git a/board/rev.h b/board/rev.h deleted file mode 100644 index 16a90a0..0000000 --- a/board/rev.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef PANDA_REV_H -#define PANDA_REV_H - -enum rev { - REV_A, - REV_B, - REV_C -}; - -#ifdef STM32F4 - #define PANDA -#endif - -#ifdef PANDA - #include "stm32f4xx.h" - #include "stm32f4xx_hal_gpio_ex.h" -#else - #include "stm32f2xx.h" - #include "stm32f2xx_hal_gpio_ex.h" -#endif - -#ifdef PANDA - #define ENABLE_CURRENT_SENSOR - #define ENABLE_SPI -#endif - -#ifdef PANDA - #define LED_RED 9 - #define LED_GREEN 7 - #define LED_BLUE 6 -#else - #define LED_RED 10 - #define LED_GREEN 11 - #define LED_BLUE -1 -#endif - -#define FREQ 24000000 // 24 mhz - -#endif diff --git a/board/safety.c b/board/safety.c deleted file mode 100644 index f816c58..0000000 --- a/board/safety.c +++ /dev/null @@ -1,96 +0,0 @@ -#include "safety.h" - -int controls_allowed = 0; - -// Include the actual safety policies. -#include "safety_honda.h" - -//Fields commonly used by various security policies. -int gas_interceptor_detected = 0; - -void default__rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {} - -void nooutput__init() { - controls_allowed = false; -} - -int nooutput__tx_hook(CAN_FIFOMailBox_TypeDef *to_send, int hardwired) { - return false; -} - -int nooutput__tx_lin_hook(int lin_num, uint8_t *data, int len, int hardwired) { - return false; -} - -void alloutput__init() { - controls_allowed = true; -} - -int alloutput__tx_hook(CAN_FIFOMailBox_TypeDef *to_send, int hardwired) { - return hardwired; -} - -int alloutput__tx_lin_hook(int lin_num, uint8_t *data, int len, int hardwired) { - return hardwired; -} - -const safety_hooks nooutput_hooks = { - .init = nooutput__init, - .rx = default__rx_hook, - .tx = alloutput__tx_hook, - .tx_lin = alloutput__tx_lin_hook, -}; - -const safety_hooks alloutput_hooks = { - .init = alloutput__init, - .rx = default__rx_hook, - .tx = alloutput__tx_hook, - .tx_lin = alloutput__tx_lin_hook, -}; - -const safety_hooks *current_hooks = &nooutput_hooks; - -void safety_rx_hook(CAN_FIFOMailBox_TypeDef *to_push){ - current_hooks->rx(to_push); -} - -int safety_tx_hook(CAN_FIFOMailBox_TypeDef *to_send, int hardwired){ - return current_hooks->tx(to_send, hardwired); -} - -int safety_tx_lin_hook(int lin_num, uint8_t *data, int len, int hardwired){ - return current_hooks->tx_lin(lin_num, data, len, hardwired); -} - - -typedef struct { - uint16_t id; - const safety_hooks *hooks; -} safety_hook_config; - -const safety_hook_config safety_hook_registry[] = { - {0x0000, &nooutput_hooks}, - {0x0001, &honda_hooks}, - {0x1337, &alloutput_hooks}, -}; - -#define HOOK_CONFIG_COUNT (sizeof(safety_hook_registry)/sizeof(safety_hook_config)) - -// Accessor method to discourage direct access outside of safety files. -// Should be inlined by compiler. -bool is_output_enabled(){ - return controls_allowed; -} - -int set_safety_mode(uint16_t mode){ - int i; - for(i = 0; i < HOOK_CONFIG_COUNT; i++){ - if(safety_hook_registry[i].id == mode){ - current_hooks = safety_hook_registry[i].hooks; - current_hooks->init(); - return 0; - } - } - - return -1; -} diff --git a/board/safety.h b/board/safety.h deleted file mode 100644 index b01da79..0000000 --- a/board/safety.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef PANDA_SAFETY_H -#define PANDA_SAFETY_H - -#include "can.h" - -void safety_rx_hook(CAN_FIFOMailBox_TypeDef *to_push); -int safety_tx_hook(CAN_FIFOMailBox_TypeDef *to_send, int hardwired); -int safety_tx_lin_hook(int lin_num, uint8_t *data, int len, int hardwired); - -typedef void (*safety_hook_init)(); -typedef void (*rx_hook)(CAN_FIFOMailBox_TypeDef *to_push); -typedef int (*tx_hook)(CAN_FIFOMailBox_TypeDef *to_send, int hardwired); -typedef int (*tx_lin_hook)(int lin_num, uint8_t *data, int len, int hardwired); - -typedef struct { - safety_hook_init init; - rx_hook rx; - tx_hook tx; - tx_lin_hook tx_lin; -} safety_hooks; - -bool is_output_enabled(); -int set_safety_mode(uint16_t mode); - -extern int gas_interceptor_detected; - -#endif diff --git a/board/spi.c b/board/spi.c deleted file mode 100644 index 6a1034e..0000000 --- a/board/spi.c +++ /dev/null @@ -1,51 +0,0 @@ -#include "spi.h" -#include "rev.h" - -void spi_init() { - //puts("SPI init\n"); - SPI1->CR1 = SPI_CR1_SPE; - - // enable SPI interrupts - //SPI1->CR2 = SPI_CR2_RXNEIE | SPI_CR2_ERRIE | SPI_CR2_TXEIE; - SPI1->CR2 = SPI_CR2_RXNEIE; -} - -void spi_tx_dma(void *addr, int len) { - // disable DMA - SPI1->CR2 &= ~SPI_CR2_TXDMAEN; - DMA2_Stream3->CR &= ~DMA_SxCR_EN; - - // DMA2, stream 3, channel 3 - DMA2_Stream3->M0AR = (uint32_t)addr; - DMA2_Stream3->NDTR = len; - DMA2_Stream3->PAR = (uint32_t)&(SPI1->DR); - - // channel3, increment memory, memory -> periph, enable - DMA2_Stream3->CR = DMA_SxCR_CHSEL_1 | DMA_SxCR_CHSEL_0 | - DMA_SxCR_MINC | DMA_SxCR_DIR_0 | DMA_SxCR_EN; - DMA2_Stream3->CR |= DMA_SxCR_TCIE; - - SPI1->CR2 |= SPI_CR2_TXDMAEN; -} - -void spi_rx_dma(void *addr, int len) { - // disable DMA - SPI1->CR2 &= ~SPI_CR2_RXDMAEN; - DMA2_Stream2->CR &= ~DMA_SxCR_EN; - - // drain the bus - uint8_t dat = SPI1->DR; - (void)dat; - - // DMA2, stream 2, channel 3 - DMA2_Stream2->M0AR = (uint32_t)addr; - DMA2_Stream2->NDTR = len; - DMA2_Stream2->PAR = (uint32_t)&(SPI1->DR); - - // channel3, increment memory, periph -> memory, enable - DMA2_Stream2->CR = DMA_SxCR_CHSEL_1 | DMA_SxCR_CHSEL_0 | - DMA_SxCR_MINC | DMA_SxCR_EN; - DMA2_Stream2->CR |= DMA_SxCR_TCIE; - - SPI1->CR2 |= SPI_CR2_RXDMAEN; -} diff --git a/board/spi.h b/board/spi.h index cd12cb6..2b5e4cd 100644 --- a/board/spi.h +++ b/board/spi.h @@ -1,9 +1,47 @@ -#ifndef PANDA_SPI_H -#define PANDA_SPI_H +void spi_init() { + //puts("SPI init\n"); + SPI1->CR1 = SPI_CR1_SPE; -void spi_init(); + // enable SPI interrupts + //SPI1->CR2 = SPI_CR2_RXNEIE | SPI_CR2_ERRIE | SPI_CR2_TXEIE; + SPI1->CR2 = SPI_CR2_RXNEIE; +} -void spi_tx_dma(void *addr, int len); -void spi_rx_dma(void *addr, int len); +void spi_tx_dma(void *addr, int len) { + // disable DMA + SPI1->CR2 &= ~SPI_CR2_TXDMAEN; + DMA2_Stream3->CR &= ~DMA_SxCR_EN; + + // DMA2, stream 3, channel 3 + DMA2_Stream3->M0AR = (uint32_t)addr; + DMA2_Stream3->NDTR = len; + DMA2_Stream3->PAR = (uint32_t)&(SPI1->DR); + + // channel3, increment memory, memory -> periph, enable + DMA2_Stream3->CR = DMA_SxCR_CHSEL_1 | DMA_SxCR_CHSEL_0 | DMA_SxCR_MINC | DMA_SxCR_DIR_0 | DMA_SxCR_EN; + DMA2_Stream3->CR |= DMA_SxCR_TCIE; + + SPI1->CR2 |= SPI_CR2_TXDMAEN; +} + +void spi_rx_dma(void *addr, int len) { + // disable DMA + SPI1->CR2 &= ~SPI_CR2_RXDMAEN; + DMA2_Stream2->CR &= ~DMA_SxCR_EN; + + // drain the bus + uint8_t dat = SPI1->DR; + (void)dat; + + // DMA2, stream 2, channel 3 + DMA2_Stream2->M0AR = (uint32_t)addr; + DMA2_Stream2->NDTR = len; + DMA2_Stream2->PAR = (uint32_t)&(SPI1->DR); + + // channel3, increment memory, periph -> memory, enable + DMA2_Stream2->CR = DMA_SxCR_CHSEL_1 | DMA_SxCR_CHSEL_0 | DMA_SxCR_MINC | DMA_SxCR_EN; + DMA2_Stream2->CR |= DMA_SxCR_TCIE; + + SPI1->CR2 |= SPI_CR2_RXDMAEN; +} -#endif diff --git a/board/spi_flasher.h b/board/spi_flasher.h index ce92014..a26a13c 100644 --- a/board/spi_flasher.h +++ b/board/spi_flasher.h @@ -1,5 +1,3 @@ -#include "libc.h" - /*void lock_bootloader() { if (FLASH->OPTCR & FLASH_OPTCR_nWRP_0) { FLASH->OPTKEYR = 0x08192A3B; diff --git a/board/timer.h b/board/timer.h index e362816..a14b619 100644 --- a/board/timer.h +++ b/board/timer.h @@ -4,3 +4,4 @@ void timer_init(TIM_TypeDef *TIM, int psc) { TIM->CR1 = TIM_CR1_CEN; TIM->SR = 0; } + diff --git a/board/tools/enter_download_mode.py b/board/tools/enter_download_mode.py index 5e5ec08..135ea23 100755 --- a/board/tools/enter_download_mode.py +++ b/board/tools/enter_download_mode.py @@ -11,9 +11,12 @@ def enter_download_mode(device): try: handle.controlWrite(usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE, 0xd1, 0, 0, b'') - except Exception: - pass - time.sleep(1) + except usb1.USBErrorIO as e: + print("Device download mode enabled.") + time.sleep(1) + else: + print("Device failed to enter download mode.") + sys.exit(1) def find_first_panda(context=None): context = context or usb1.USBContext() diff --git a/board/uart.c b/board/uart.c deleted file mode 100644 index ac4a614..0000000 --- a/board/uart.c +++ /dev/null @@ -1,209 +0,0 @@ -#include -#include "config.h" -#include "uart.h" -#include "early.h" - -void debug_ring_callback(uart_ring *ring) { - char rcv; - while (getc(ring, &rcv)) { - putc(ring, rcv); - - // jump to DFU flash - if (rcv == 'z') { - enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC; - NVIC_SystemReset(); - } - if (rcv == 'x') { - // normal reset - NVIC_SystemReset(); - } - } -} - -// ***************************** serial port queues ***************************** - -// debug = USART2 -uart_ring debug_ring = { .w_ptr_tx = 0, .r_ptr_tx = 0, - .w_ptr_rx = 0, .r_ptr_rx = 0, - .uart = USART2, - .callback = debug_ring_callback}; - -// esp = USART1 -uart_ring esp_ring = { .w_ptr_tx = 0, .r_ptr_tx = 0, - .w_ptr_rx = 0, .r_ptr_rx = 0, - .uart = USART1 }; - -// lin1, K-LINE = UART5 -// lin2, L-LINE = USART3 -uart_ring lin1_ring = { .w_ptr_tx = 0, .r_ptr_tx = 0, - .w_ptr_rx = 0, .r_ptr_rx = 0, - .uart = UART5 }; -uart_ring lin2_ring = { .w_ptr_tx = 0, .r_ptr_tx = 0, - .w_ptr_rx = 0, .r_ptr_rx = 0, - .uart = USART3 }; - -uart_ring *get_ring_by_number(int a) { - switch(a) { - case 0: - return &debug_ring; - case 1: - return &esp_ring; - case 2: - return &lin1_ring; - case 3: - return &lin2_ring; - default: - return NULL; - } -} - -void uart_set_baud(USART_TypeDef *u, int baud) { - if (u == USART1) { - // USART1 is on APB2 - u->BRR = __USART_BRR(48000000, baud); - } else { - u->BRR = __USART_BRR(24000000, baud); - } -} - -void uart_init(USART_TypeDef *u, int baud) { - // enable uart and tx+rx mode - u->CR1 = USART_CR1_UE; - uart_set_baud(u, baud); - - u->CR1 |= USART_CR1_TE | USART_CR1_RE; - //u->CR2 = USART_CR2_STOP_0 | USART_CR2_STOP_1; - //u->CR2 = USART_CR2_STOP_0; - // ** UART is ready to work ** - - // enable interrupts - u->CR1 |= USART_CR1_RXNEIE; -} - -void putch(const char a) { - if (has_external_debug_serial) { - putc(&debug_ring, a); - } else { - injectc(&debug_ring, a); - } -} - -int puts(const char *a) { - for (;*a;a++) { - if (*a == '\n') putch('\r'); - putch(*a); - } - return 0; -} - -void puth(unsigned int i) { - int pos; - char c[] = "0123456789abcdef"; - for (pos = 28; pos != -4; pos -= 4) { - putch(c[(i >> pos) & 0xF]); - } -} - -void puth2(unsigned int i) { - int pos; - char c[] = "0123456789abcdef"; - for (pos = 4; pos != -4; pos -= 4) { - putch(c[(i >> pos) & 0xF]); - } -} - -void hexdump(void *a, int l) { - int i; - for (i=0;iw_ptr_rx != q->r_ptr_rx) { - *elem = q->elems_rx[q->r_ptr_rx]; - q->r_ptr_rx += 1; - return 1; - } - return 0; -} - -int putc(uart_ring *q, char elem) { - uint8_t next_w_ptr = q->w_ptr_tx + 1; - int ret = 0; - if (next_w_ptr != q->r_ptr_tx) { - q->elems_tx[q->w_ptr_tx] = elem; - q->w_ptr_tx = next_w_ptr; - ret = 1; - } - uart_ring_process(q); - return ret; -} - -int injectc(uart_ring *q, char elem) { - uint8_t next_w_ptr = q->w_ptr_rx + 1; - int ret = 0; - if (next_w_ptr != q->r_ptr_rx) { - q->elems_rx[q->w_ptr_rx] = elem; - q->w_ptr_rx = next_w_ptr; - ret = 1; - } - return ret; -} - -void uart_ring_process(uart_ring *q) { - // TODO: check if external serial is connected - int sr = q->uart->SR; - - if (q->w_ptr_tx != q->r_ptr_tx) { - if (sr & USART_SR_TXE) { - q->uart->DR = q->elems_tx[q->r_ptr_tx]; - q->r_ptr_tx += 1; - } else { - // push on interrupt later - q->uart->CR1 |= USART_CR1_TXEIE; - } - } else { - // nothing to send - q->uart->CR1 &= ~USART_CR1_TXEIE; - } - - if (sr & USART_SR_RXNE) { - uint8_t c = q->uart->DR; // TODO: can drop packets - uint8_t next_w_ptr = q->w_ptr_rx + 1; - if (next_w_ptr != q->r_ptr_rx) { - q->elems_rx[q->w_ptr_rx] = c; - q->w_ptr_rx = next_w_ptr; - if (q->callback) q->callback(q); - } - } -} - -// interrupt boilerplate - -void USART1_IRQHandler(void) { - NVIC_DisableIRQ(USART1_IRQn); - uart_ring_process(&esp_ring); - NVIC_EnableIRQ(USART1_IRQn); -} - -void USART2_IRQHandler(void) { - NVIC_DisableIRQ(USART2_IRQn); - uart_ring_process(&debug_ring); - NVIC_EnableIRQ(USART2_IRQn); -} - -void USART3_IRQHandler(void) { - NVIC_DisableIRQ(USART3_IRQn); - uart_ring_process(&lin2_ring); - NVIC_EnableIRQ(USART3_IRQn); -} - -void UART5_IRQHandler(void) { - NVIC_DisableIRQ(UART5_IRQn); - uart_ring_process(&lin1_ring); - NVIC_EnableIRQ(UART5_IRQn); -} diff --git a/board/uart.h b/board/uart.h index 38a51f2..0c062aa 100644 --- a/board/uart.h +++ b/board/uart.h @@ -1,48 +1,70 @@ -#ifndef PANDA_UART_H -#define PANDA_UART_H +#define __DIV(_PCLK_, _BAUD_) (((_PCLK_)*25)/(4*(_BAUD_))) +#define __DIVMANT(_PCLK_, _BAUD_) (__DIV((_PCLK_), (_BAUD_))/100) +#define __DIVFRAQ(_PCLK_, _BAUD_) (((__DIV((_PCLK_), (_BAUD_)) - (__DIVMANT((_PCLK_), (_BAUD_)) * 100)) * 16 + 50) / 100) +#define __USART_BRR(_PCLK_, _BAUD_) ((__DIVMANT((_PCLK_), (_BAUD_)) << 4)|(__DIVFRAQ((_PCLK_), (_BAUD_)) & 0x0F)) -#define __DIV(_PCLK_, _BAUD_) (((_PCLK_)*25)/(4*(_BAUD_))) -#define __DIVMANT(_PCLK_, _BAUD_) (__DIV((_PCLK_), (_BAUD_))/100) -#define __DIVFRAQ(_PCLK_, _BAUD_) (((__DIV((_PCLK_), (_BAUD_)) - (__DIVMANT((_PCLK_), (_BAUD_)) * 100)) * 16 + 50) / 100) -#define __USART_BRR(_PCLK_, _BAUD_) ((__DIVMANT((_PCLK_), (_BAUD_)) << 4)|(__DIVFRAQ((_PCLK_), (_BAUD_)) & 0x0F)) +void uart_set_baud(USART_TypeDef *u, int baud) { + if (u == USART1) { + // USART1 is on APB2 + u->BRR = __USART_BRR(48000000, baud); + } else { + u->BRR = __USART_BRR(24000000, baud); + } +} -typedef struct uart_ring { - uint8_t w_ptr_tx; - uint8_t r_ptr_tx; - uint8_t elems_tx[FIFO_SIZE]; - uint8_t w_ptr_rx; - uint8_t r_ptr_rx; - uint8_t elems_rx[FIFO_SIZE]; - USART_TypeDef *uart; - void (*callback)(struct uart_ring*); -} uart_ring; +void uart_init(USART_TypeDef *u, int baud) { + // enable uart and tx+rx mode + u->CR1 = USART_CR1_UE; + uart_set_baud(u, baud); + + u->CR1 |= USART_CR1_TE | USART_CR1_RE; + //u->CR2 = USART_CR2_STOP_0 | USART_CR2_STOP_1; + //u->CR2 = USART_CR2_STOP_0; + // ** UART is ready to work ** -extern int has_external_debug_serial; + // enable interrupts + u->CR1 |= USART_CR1_RXNEIE; +} -extern uart_ring debug_ring; +void putch(const char a) { + if (has_external_debug_serial) { + putc(&debug_ring, a); + } else { + injectc(&debug_ring, a); + } +} -uart_ring *get_ring_by_number(int a); +int puts(const char *a) { + for (;*a;a++) { + if (*a == '\n') putch('\r'); + putch(*a); + } + return 0; +} -void uart_set_baud(USART_TypeDef *u, int baud); +void puth(unsigned int i) { + int pos; + char c[] = "0123456789abcdef"; + for (pos = 28; pos != -4; pos -= 4) { + putch(c[(i >> pos) & 0xF]); + } +} -void uart_init(USART_TypeDef *u, int baud); +void puth2(unsigned int i) { + int pos; + char c[] = "0123456789abcdef"; + for (pos = 4; pos != -4; pos -= 4) { + putch(c[(i >> pos) & 0xF]); + } +} -void putch(const char a); +void hexdump(void *a, int l) { + int i; + for (i=0;iODR &= ~(1 << 14); - did_usb_enumerate = 1; -} - -// packet read and write -void *USB_ReadPacket(void *dest, uint16_t len) { - uint32_t i=0; - uint32_t count32b = (len + 3) / 4; - - for ( i = 0; i < count32b; i++, dest += 4 ) { - // packed? - *(__attribute__((__packed__)) uint32_t *)dest = USBx_DFIFO(0); - } - return ((void *)dest); -} - -void USB_WritePacket(const uint8_t *src, uint16_t len, uint32_t ep) { - #ifdef DEBUG_USB - //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 = ((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 - for (i = 0; i < count32b; i++, src += 4) { - USBx_DFIFO(ep) = *((__attribute__((__packed__)) uint32_t *)src); - } -} - -void USB_Stall_EP0(){ - //TODO: Handle stalling both in and out requests. - //Check why INEP works for both in and out requests. - USBx_INEP(0)->DIEPCTL |= (USB_OTG_DIEPCTL_STALL | USB_OTG_DIEPCTL_EPENA); - - //USBx_OUTEP(0)->DOEPCTL |= (USB_OTG_DOEPCTL_STALL | USB_OTG_DOEPCTL_EPENA); -} - -void usb_reset() { - // unmask endpoint interrupts, so many sets - USBx_DEVICE->DAINT = 0xFFFFFFFF; - USBx_DEVICE->DAINTMSK = 0xFFFFFFFF; - //USBx_DEVICE->DOEPMSK = (USB_OTG_DOEPMSK_STUPM | USB_OTG_DOEPMSK_XFRCM | USB_OTG_DOEPMSK_EPDM); - //USBx_DEVICE->DIEPMSK = (USB_OTG_DIEPMSK_TOM | USB_OTG_DIEPMSK_XFRCM | USB_OTG_DIEPMSK_EPDM | USB_OTG_DIEPMSK_ITTXFEMSK); - //USBx_DEVICE->DIEPMSK = (USB_OTG_DIEPMSK_TOM | USB_OTG_DIEPMSK_XFRCM | USB_OTG_DIEPMSK_EPDM); - - // all interrupts for debugging - USBx_DEVICE->DIEPMSK = 0xFFFFFFFF; - USBx_DEVICE->DOEPMSK = 0xFFFFFFFF; - - // clear interrupts - USBx_INEP(0)->DIEPINT = 0xFF; - USBx_OUTEP(0)->DOEPINT = 0xFF; - - // unset the address - USBx_DEVICE->DCFG &= ~USB_OTG_DCFG_DAD; - - // set up USB FIFOs - // RX start address is fixed to 0 - USBx->GRXFSIZ = 0x40; - - // 0x100 to offset past GRXFSIZ - USBx->DIEPTXF0_HNPTXFSIZ = (0x40 << 16) | 0x40; - - // EP1, massive - USBx->DIEPTXF[0] = (0x40 << 16) | 0x80; - - // flush TX fifo - USBx->GRSTCTL = USB_OTG_GRSTCTL_TXFFLSH | USB_OTG_GRSTCTL_TXFNUM_4; - while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH) == USB_OTG_GRSTCTL_TXFFLSH); - // flush RX FIFO - USBx->GRSTCTL = USB_OTG_GRSTCTL_RXFFLSH; - while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_RXFFLSH) == USB_OTG_GRSTCTL_RXFFLSH); - - // no global NAK - USBx_DEVICE->DCTL |= USB_OTG_DCTL_CGINAK; - - // ready to receive setup packets - USBx_OUTEP(0)->DOEPTSIZ = USB_OTG_DOEPTSIZ_STUPCNT | (USB_OTG_DOEPTSIZ_PKTCNT & (1 << 19)) | (3 * 8); -} - -char to_hex_char(int a) { - if (a < 10) { - return '0' + a; - } else { - return 'a' + (a-10); - } -} - -void usb_setup() { - int i; - int resp_len; - // setup packet is ready - switch (setup.b.bRequest) { - case USB_REQ_SET_CONFIGURATION: - // enable other endpoints, has to be here? - USBx_INEP(1)->DIEPCTL = (0x40 & USB_OTG_DIEPCTL_MPSIZ) | (2 << 18) | (1 << 22) | - USB_OTG_DIEPCTL_SD0PID_SEVNFRM | USB_OTG_DIEPCTL_USBAEP; - USBx_INEP(1)->DIEPINT = 0xFF; - - USBx_OUTEP(2)->DOEPTSIZ = (1 << 19) | 0x40; - USBx_OUTEP(2)->DOEPCTL = (0x40 & USB_OTG_DOEPCTL_MPSIZ) | (2 << 18) | - USB_OTG_DOEPCTL_SD0PID_SEVNFRM | USB_OTG_DOEPCTL_USBAEP; - USBx_OUTEP(2)->DOEPINT = 0xFF; - - USBx_OUTEP(3)->DOEPTSIZ = (1 << 19) | 0x40; - USBx_OUTEP(3)->DOEPCTL = (0x40 & USB_OTG_DOEPCTL_MPSIZ) | (2 << 18) | - USB_OTG_DOEPCTL_SD0PID_SEVNFRM | USB_OTG_DOEPCTL_USBAEP; - USBx_OUTEP(3)->DOEPINT = 0xFF; - - // mark ready to receive - USBx_OUTEP(2)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK; - USBx_OUTEP(3)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK; - - // TODO: is this the right place for this? - usb_cb_enumeration_complete(); - - USB_WritePacket(0, 0, 0); - USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; - break; - case USB_REQ_SET_ADDRESS: - // set now? - USBx_DEVICE->DCFG |= ((setup.b.wValue.w & 0x7f) << 4); - - #ifdef DEBUG_USB - puts(" set address\n"); - #endif - - USB_WritePacket(0, 0, 0); - USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; - - break; - case USB_REQ_GET_DESCRIPTOR: - switch (setup.b.wValue.bw.lsb) { - case USB_DESC_TYPE_DEVICE: - //puts(" writing device descriptor\n"); - - // setup transfer - USB_WritePacket(device_desc, min(sizeof(device_desc), setup.b.wLength.w), 0); - USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; - - //puts("D"); - break; - case USB_DESC_TYPE_CONFIGURATION: - USB_WritePacket(configuration_desc, min(sizeof(configuration_desc), setup.b.wLength.w), 0); - USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; - break; - case USB_DESC_TYPE_STRING: - switch (setup.b.wValue.bw.msb) { - case 0: - USB_WritePacket((uint8_t*)string_0_desc, min(sizeof(string_0_desc), setup.b.wLength.w), 0); - break; - case 1: - USB_WritePacket((uint8_t*)string_1_desc, min(sizeof(string_1_desc), setup.b.wLength.w), 0); - break; - case 2: - USB_WritePacket((uint8_t*)string_2_desc, min(sizeof(string_2_desc), setup.b.wLength.w), 0); - break; - case 3: - #ifdef PANDA - resp[0] = 0x02 + 12*4; - resp[1] = 0x03; - - // 96 bits = 12 bytes - for (i = 0; i < 12; i++){ - uint8_t cc = ((uint8_t *)UID_BASE)[i]; - resp[2 + i*4 + 0] = to_hex_char((cc>>4)&0xF); - resp[2 + i*4 + 1] = '\0'; - resp[2 + i*4 + 2] = to_hex_char((cc>>0)&0xF); - resp[2 + i*4 + 3] = '\0'; - } - - USB_WritePacket(resp, min(resp[0], setup.b.wLength.w), 0); - #else - USB_WritePacket(string_3_desc, min(sizeof(string_3_desc), setup.b.wLength.w), 0); - #endif - break; - default: - // nothing - USB_WritePacket(0, 0, 0); - break; - } - USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; - break; - default: - // nothing here? - USB_WritePacket(0, 0, 0); - USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; - break; - } - break; - case USB_REQ_GET_STATUS: - // empty resp? - resp[0] = 0; - resp[1] = 0; - 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; - //USBx_INEP(0)->DIEPINT = USBx_INEP(0)->DIEPINT - #ifdef DEBUG_USB - puts("Setting Interface Alt: "); - puth(current_int0_alt_setting); - puts("\n"); - #endif - break; - default: - resp_len = usb_cb_control_msg(&setup, resp, 1); - if(resp_len == -1){ - USB_Stall_EP0(); - }else{ - USB_WritePacket(resp, min(resp_len, setup.b.wLength.w), 0); - USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; - } - } -} - -void usb_init() { - // full speed PHY, do reset and remove power down - puth(USBx->GRSTCTL); - puts(" resetting PHY\n"); - while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0); - puts("AHB idle\n"); - - // reset PHY here - USBx->GRSTCTL |= USB_OTG_GRSTCTL_CSRST; - while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_CSRST) == USB_OTG_GRSTCTL_CSRST); - puts("reset done\n"); - - // internal PHY, force device mode - USBx->GUSBCFG = USB_OTG_GUSBCFG_PHYSEL | USB_OTG_GUSBCFG_FDMOD; - - // slowest timings - USBx->GUSBCFG |= (uint32_t)((USBD_FS_TRDT_VALUE << 10) & USB_OTG_GUSBCFG_TRDT); - - // power up the PHY -#ifdef STM32F4 - USBx->GCCFG = USB_OTG_GCCFG_PWRDWN; - - //USBx->GCCFG |= USB_OTG_GCCFG_VBDEN | USB_OTG_GCCFG_SDEN |USB_OTG_GCCFG_PDEN | USB_OTG_GCCFG_DCDEN; - - /* B-peripheral session valid override enable*/ - USBx->GOTGCTL |= USB_OTG_GOTGCTL_BVALOVAL; - USBx->GOTGCTL |= USB_OTG_GOTGCTL_BVALOEN; -#else - USBx->GCCFG = USB_OTG_GCCFG_PWRDWN | USB_OTG_GCCFG_NOVBUSSENS; -#endif - - // be a device, slowest timings - //USBx->GUSBCFG = USB_OTG_GUSBCFG_FDMOD | USB_OTG_GUSBCFG_PHYSEL | USB_OTG_GUSBCFG_TRDT | USB_OTG_GUSBCFG_TOCAL; - //USBx->GUSBCFG |= (uint32_t)((USBD_FS_TRDT_VALUE << 10) & USB_OTG_GUSBCFG_TRDT); - //USBx->GUSBCFG = USB_OTG_GUSBCFG_PHYSEL | USB_OTG_GUSBCFG_TRDT | USB_OTG_GUSBCFG_TOCAL; - - // **** for debugging, doesn't seem to work **** - //USBx->GUSBCFG |= USB_OTG_GUSBCFG_CTXPKT; - - // reset PHY clock - USBx_PCGCCTL = 0; - - // enable the fancy OTG things - // DCFG_FRAME_INTERVAL_80 is 0 - //USBx->GUSBCFG |= USB_OTG_GUSBCFG_HNPCAP | USB_OTG_GUSBCFG_SRPCAP; - USBx_DEVICE->DCFG |= USB_OTG_SPEED_FULL | USB_OTG_DCFG_NZLSOHSK; - - //USBx_DEVICE->DCFG = USB_OTG_DCFG_NZLSOHSK | USB_OTG_DCFG_DSPD; - //USBx_DEVICE->DCFG = USB_OTG_DCFG_DSPD; - - // clear pending interrupts - USBx->GINTSTS = 0xBFFFFFFFU; - - // setup USB interrupts - // all interrupts except TXFIFO EMPTY - //USBx->GINTMSK = 0xFFFFFFFF & ~(USB_OTG_GINTMSK_NPTXFEM | USB_OTG_GINTMSK_PTXFEM | USB_OTG_GINTSTS_SOF | USB_OTG_GINTSTS_EOPF); - //USBx->GINTMSK = 0xFFFFFFFF & ~(USB_OTG_GINTMSK_NPTXFEM | USB_OTG_GINTMSK_PTXFEM); - //SRQ is when a 'session' starts. - USBx->GINTMSK = USB_OTG_GINTMSK_SRQIM | USB_OTG_GINTMSK_CIDSCHGM | USB_OTG_GINTMSK_OEPINT | - USB_OTG_GINTMSK_IEPINT | USB_OTG_GINTMSK_ENUMDNEM | USB_OTG_GINTMSK_USBRST | - USB_OTG_GINTMSK_USBSUSPM | USB_OTG_GINTMSK_GONAKEFFM | USB_OTG_GINTMSK_GINAKEFFM | - USB_OTG_GINTMSK_RXFLVLM | USB_OTG_GINTMSK_OTGINT | USB_OTG_GINTMSK_MMISM; - - USBx->GAHBCFG = USB_OTG_GAHBCFG_GINT; - - // DCTL startup value is 2 on new chip, 0 on old chip - // THIS IS FUCKING BULLSHIT - USBx_DEVICE->DCTL = 0; -} - -// ***************************** USB port ***************************** -void usb_irqhandler(void) { - //USBx->GINTMSK = 0; - - unsigned int gintsts = USBx->GINTSTS; - unsigned int gotgint = USBx->GOTGINT; - unsigned int daint = USBx_DEVICE->DAINT; - - // gintsts SUSPEND? 04008428 - #ifdef DEBUG_USB - puts("USB interrupt (DAINT[EP]:"); - puth(daint); - puts(" GINTSTS:"); - puth(gintsts); - //puts(" GCCFG:"); - //puth(USBx->GCCFG); - //puts(" GOTGINT:"); - //puth(gotgint); - puts(")\n"); - #endif - - if (gintsts & USB_OTG_GINTSTS_CIDSCHG) { - puts("connector ID status change\n"); - } - - if (gintsts & USB_OTG_GINTSTS_ESUSP) { - puts("ESUSP detected\n"); - } - - if (gintsts & USB_OTG_GINTSTS_USBRST) { - puts("USB reset\n"); - usb_reset(); - } - - if (gintsts & USB_OTG_GINTSTS_ENUMDNE) { - puts("enumeration done "); - // Full speed, ENUMSPD - puth(USBx_DEVICE->DSTS); - puts("\n"); - } - - if (gintsts & USB_OTG_GINTSTS_OTGINT) { - puts("OTG int:"); - puth(USBx->GOTGINT); - puts("\n"); - - // getting ADTOCHG - //USBx->GOTGINT = USBx->GOTGINT; - } - - // RX FIFO Has Data (OUT TRANSFER) - if (gintsts & USB_OTG_GINTSTS_RXFLVL) { - // 1. Read the Receive status pop register - volatile unsigned int rxst = USBx->GRXSTSP; - - #ifdef DEBUG_USB - puts(" RX FIFO:"); - puth(rxst); - puts(" status: "); - puth((rxst & USB_OTG_GRXSTSP_PKTSTS) >> 17); - puts(" len: "); - puth((rxst & USB_OTG_GRXSTSP_BCNT) >> 4); - puts("\n"); - #endif - - if (((rxst & USB_OTG_GRXSTSP_PKTSTS) >> 17) == STS_DATA_UPDT) { //OUT DATA PKT RECEIVED - int endpoint = (rxst & USB_OTG_GRXSTSP_EPNUM); - int len = (rxst & USB_OTG_GRXSTSP_BCNT) >> 4; - USB_ReadPacket(&usbdata, len); - #ifdef DEBUG_USB - puts(" data "); - puth(len); - puts("\n"); - hexdump(&usbdata, len); - #endif - - if(endpoint == 0){ - usb_cb_ep0_out(&setup, usbdata, 1); - } - - if (endpoint == 2) { - usb_cb_ep2_out(usbdata, len, 1); - } - - if (endpoint == 3) { - usb_cb_ep3_out(usbdata, len, 1); - } - } else if (((rxst & USB_OTG_GRXSTSP_PKTSTS) >> 17) == STS_SETUP_UPDT) { - USB_ReadPacket(&setup, 8); - #ifdef DEBUG_USB - puts(" setup "); - hexdump(&setup, 8); - puts("\n"); - #endif - } - } - - /*if (gintsts & USB_OTG_GINTSTS_HPRTINT) { - // host - puts("HPRT:"); - puth(USBx_HOST_PORT->HPRT); - puts("\n"); - if (USBx_HOST_PORT->HPRT & USB_OTG_HPRT_PCDET) { - USBx_HOST_PORT->HPRT |= USB_OTG_HPRT_PRST; - USBx_HOST_PORT->HPRT |= USB_OTG_HPRT_PCDET; - } - - }*/ - - if ((gintsts & USB_OTG_GINTSTS_BOUTNAKEFF) || (gintsts & USB_OTG_GINTSTS_GINAKEFF)) { - // no global NAK, why is this getting set? - #ifdef DEBUG_USB - puts("GLOBAL NAK\n"); - #endif - USBx_DEVICE->DCTL |= USB_OTG_DCTL_CGONAK | USB_OTG_DCTL_CGINAK; - } - - if (gintsts & USB_OTG_GINTSTS_SRQINT) { - // we want to do "A-device host negotiation protocol" since we are the A-device - puts("start request\n"); - puth(USBx->GOTGCTL); - puts("\n"); - //USBx->GUSBCFG |= USB_OTG_GUSBCFG_FDMOD; - //USBx_HOST_PORT->HPRT = USB_OTG_HPRT_PPWR | USB_OTG_HPRT_PENA; - //USBx->GOTGCTL |= USB_OTG_GOTGCTL_SRQ; - } - - // out endpoint hit - if (gintsts & USB_OTG_GINTSTS_OEPINT) { - #ifdef DEBUG_USB - puts(" 0:"); - puth(USBx_OUTEP(0)->DOEPINT); - puts(" 2:"); - puth(USBx_OUTEP(2)->DOEPINT); - puts(" 3:"); - puth(USBx_OUTEP(3)->DOEPINT); - puts(" "); - puth(USBx_OUTEP(3)->DOEPCTL); - puts(" 4:"); - puth(USBx_OUTEP(4)->DOEPINT); - puts(" OUT ENDPOINT\n"); - #endif - - if (USBx_OUTEP(2)->DOEPINT & USB_OTG_DOEPINT_XFRC) { - #ifdef DEBUG_USB - puts(" OUT2 PACKET XFRC\n"); - #endif - USBx_OUTEP(2)->DOEPTSIZ = (1 << 19) | 0x40; - USBx_OUTEP(2)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK; - } - - if (USBx_OUTEP(3)->DOEPINT & USB_OTG_DOEPINT_XFRC) { - #ifdef DEBUG_USB - puts(" OUT3 PACKET XFRC\n"); - #endif - USBx_OUTEP(3)->DOEPTSIZ = (1 << 19) | 0x40; - USBx_OUTEP(3)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK; - } else if (USBx_OUTEP(3)->DOEPINT & 0x2000) { - #ifdef DEBUG_USB - puts(" OUT3 PACKET WTF\n"); - #endif - // if NAK was set trigger this, unknown interrupt - USBx_OUTEP(3)->DOEPTSIZ = (1 << 19) | 0x40; - USBx_OUTEP(3)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; - } else if (USBx_OUTEP(3)->DOEPINT) { - puts("OUTEP3 error "); - puth(USBx_OUTEP(3)->DOEPINT); - puts("\n"); - } - - if (USBx_OUTEP(0)->DOEPINT & USB_OTG_DIEPINT_XFRC) { - // ready for next packet - USBx_OUTEP(0)->DOEPTSIZ = USB_OTG_DOEPTSIZ_STUPCNT | (USB_OTG_DOEPTSIZ_PKTCNT & (1 << 19)) | (1 * 8); - } - - // respond to setup packets - if (USBx_OUTEP(0)->DOEPINT & USB_OTG_DOEPINT_STUP) { - #ifdef DEBUG_USB - puts("Processing SETUP\n"); - #endif - usb_setup(); - } - - USBx_OUTEP(0)->DOEPINT = USBx_OUTEP(0)->DOEPINT; - USBx_OUTEP(2)->DOEPINT = USBx_OUTEP(2)->DOEPINT; - USBx_OUTEP(3)->DOEPINT = USBx_OUTEP(3)->DOEPINT; - } - - // interrupt endpoint hit (Page 1221) - if (gintsts & USB_OTG_GINTSTS_IEPINT) { - #ifdef DEBUG_USB - puts(" "); - puth(USBx_INEP(0)->DIEPINT); - puts(" "); - puth(USBx_INEP(1)->DIEPINT); - puts(" IN ENDPOINT\n"); - #endif - - // Should likely check the EP of the IN request even if there is - // only one IN endpoint. - - // 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) { - if (can_rx_q.w_ptr != can_rx_q.r_ptr) - puts("Rx CAN bulk: There is CAN data to send.\n"); - else - puts("Rx CAN bulk: No can data\n"); - - #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; - - 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; // Why ep0? - USBx_INEP(1)->DIEPINT = USBx_INEP(1)->DIEPINT; - } - - // clear all interrupts we handled - USBx_DEVICE->DAINT = daint; - USBx->GOTGINT = gotgint; - USBx->GINTSTS = gintsts; - - //USBx->GINTMSK = 0xFFFFFFFF & ~(USB_OTG_GINTMSK_NPTXFEM | USB_OTG_GINTMSK_PTXFEM | USB_OTG_GINTSTS_SOF | USB_OTG_GINTSTS_EOPF); -} diff --git a/board/usb.h b/board/usb.h index 7d01a4b..c8f7689 100644 --- a/board/usb.h +++ b/board/usb.h @@ -1,6 +1,3 @@ -#ifndef PANDA_USB_H -#define PANDA_USB_H - // **** supporting defines **** typedef struct @@ -9,7 +6,8 @@ typedef struct } USB_OTG_HostPortTypeDef; -#define USBx USB_OTG_FS +USB_OTG_GlobalTypeDef *USBx = USB_OTG_FS; + #define USBx_HOST ((USB_OTG_HostTypeDef *)((uint32_t)USBx + USB_OTG_HOST_BASE)) #define USBx_HOST_PORT ((USB_OTG_HostPortTypeDef *)((uint32_t)USBx + USB_OTG_HOST_PORT_BASE)) #define USBx_DEVICE ((USB_OTG_DeviceTypeDef *)((uint32_t)USBx + USB_OTG_DEVICE_BASE)) @@ -80,14 +78,12 @@ typedef union _USB_Setup USB_Setup_TypeDef; // interfaces +void usb_cb_enumeration_complete(); int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *usbdata, int hardwired); -void usb_cb_ep0_out(USB_Setup_TypeDef *setup, uint8_t *usbdata, int hardwired); int usb_cb_ep1_in(uint8_t *usbdata, int len, int hardwired); void usb_cb_ep2_out(uint8_t *usbdata, int len, int hardwired); void usb_cb_ep3_out(uint8_t *usbdata, int len, int hardwired); -extern int did_usb_enumerate; - // descriptor types // same as setupdat.h #define DSCR_DEVICE_TYPE 1 @@ -113,33 +109,619 @@ extern int did_usb_enumerate; #define TOUSBORDER(num)\ (num&0xFF), ((num>>8)&0xFF) +uint8_t device_desc[] = { + DSCR_DEVICE_LEN, DSCR_DEVICE_TYPE, 0x00, 0x01, //Length, Type, bcdUSB + 0xFF, 0xFF, 0xFF, 0x40, // Class, Subclass, Protocol, Max Packet Size + TOUSBORDER(USB_VID), // idVendor + TOUSBORDER(USB_PID), // idProduct +#ifdef STM32F4 + 0x00, 0x23, // bcdDevice +#else + 0x00, 0x22, // bcdDevice +#endif + 0x01, 0x02, // Manufacturer, Product + 0x03, 0x01 // Serial Number, Num Configurations +}; + #define ENDPOINT_RCV 0x80 #define ENDPOINT_SND 0x00 +uint8_t configuration_desc[] = { + DSCR_CONFIG_LEN, DSCR_CONFIG_TYPE, // Length, Type, + TOUSBORDER(0x0045), // Total Len (uint16) + 0x01, 0x01, 0x00, // Num Interface, Config Value, Configuration + 0xc0, 0x32, // Attributes, Max Power + // 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 + 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 (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[] = { + 0x04, DSCR_STRING_TYPE, 0x09, 0x04 +}; + +uint16_t string_1_desc[] = { + 0x0312, + 'c', 'o', 'm', 'm', 'a', '.', 'a', 'i' +}; + +#ifdef PANDA +uint16_t string_2_desc[] = { + 0x030c, + 'p', 'a', 'n', 'd', 'a' +}; +#else +uint16_t string_2_desc[] = { + 0x030c, + 'N', 'E', 'O', 'v', '1' +}; +#endif + +uint16_t string_3_desc[] = { + 0x030a, + 'n', 'o', 'n', 'e' +}; + // current packet -extern USB_Setup_TypeDef setup; -extern uint8_t usbdata[0x100]; +USB_Setup_TypeDef setup; +uint8_t usbdata[0x100]; // Store the current interface alt setting. -extern int current_int0_alt_setting; +int current_int0_alt_setting = 0; // packet read and write -void *USB_ReadPacket(void *dest, uint16_t len); +void *USB_ReadPacket(void *dest, uint16_t len) { + uint32_t i=0; + uint32_t count32b = (len + 3) / 4; -void USB_WritePacket(const uint8_t *src, uint16_t len, uint32_t ep); + for ( i = 0; i < count32b; i++, dest += 4 ) { + // packed? + *(__attribute__((__packed__)) uint32_t *)dest = USBx_DFIFO(0); + } + return ((void *)dest); +} -void USB_Stall_EP0(); +void USB_WritePacket(const uint8_t *src, uint16_t len, uint32_t ep) { + #ifdef DEBUG_USB + puts("writing "); + hexdump(src, len); + #endif -void usb_reset(); + uint8_t numpacket = (len+(MAX_RESP_LEN-1))/MAX_RESP_LEN; + uint32_t count32b = 0, i = 0; + count32b = (len + 3) / 4; -char to_hex_char(int a); + // bullshit + 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); -void usb_setup(); + // load the FIFO + for (i = 0; i < count32b; i++, src += 4) { + USBx_DFIFO(ep) = *((__attribute__((__packed__)) uint32_t *)src); + } +} -void usb_init(); +void usb_reset() { + // unmask endpoint interrupts, so many sets + USBx_DEVICE->DAINT = 0xFFFFFFFF; + USBx_DEVICE->DAINTMSK = 0xFFFFFFFF; + //USBx_DEVICE->DOEPMSK = (USB_OTG_DOEPMSK_STUPM | USB_OTG_DOEPMSK_XFRCM | USB_OTG_DOEPMSK_EPDM); + //USBx_DEVICE->DIEPMSK = (USB_OTG_DIEPMSK_TOM | USB_OTG_DIEPMSK_XFRCM | USB_OTG_DIEPMSK_EPDM | USB_OTG_DIEPMSK_ITTXFEMSK); + //USBx_DEVICE->DIEPMSK = (USB_OTG_DIEPMSK_TOM | USB_OTG_DIEPMSK_XFRCM | USB_OTG_DIEPMSK_EPDM); + + // all interrupts for debugging + USBx_DEVICE->DIEPMSK = 0xFFFFFFFF; + USBx_DEVICE->DOEPMSK = 0xFFFFFFFF; + + // clear interrupts + USBx_INEP(0)->DIEPINT = 0xFF; + USBx_OUTEP(0)->DOEPINT = 0xFF; + + // unset the address + USBx_DEVICE->DCFG &= ~USB_OTG_DCFG_DAD; + + // set up USB FIFOs + // RX start address is fixed to 0 + USBx->GRXFSIZ = 0x40; + + // 0x100 to offset past GRXFSIZ + USBx->DIEPTXF0_HNPTXFSIZ = (0x40 << 16) | 0x40; + + // EP1, massive + USBx->DIEPTXF[0] = (0x40 << 16) | 0x80; + + // flush TX fifo + USBx->GRSTCTL = USB_OTG_GRSTCTL_TXFFLSH | USB_OTG_GRSTCTL_TXFNUM_4; + while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH) == USB_OTG_GRSTCTL_TXFFLSH); + // flush RX FIFO + USBx->GRSTCTL = USB_OTG_GRSTCTL_RXFFLSH; + while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_RXFFLSH) == USB_OTG_GRSTCTL_RXFFLSH); + + // no global NAK + USBx_DEVICE->DCTL |= USB_OTG_DCTL_CGINAK; + + // ready to receive setup packets + USBx_OUTEP(0)->DOEPTSIZ = USB_OTG_DOEPTSIZ_STUPCNT | (USB_OTG_DOEPTSIZ_PKTCNT & (1 << 19)) | (3 * 8); +} + +char to_hex_char(int a) { + if (a < 10) { + return '0' + a; + } else { + return 'a' + (a-10); + } +} + +void usb_setup() { + int i; + int resp_len; + // setup packet is ready + switch (setup.b.bRequest) { + case USB_REQ_SET_CONFIGURATION: + // enable other endpoints, has to be here? + USBx_INEP(1)->DIEPCTL = (0x40 & USB_OTG_DIEPCTL_MPSIZ) | (2 << 18) | (1 << 22) | + USB_OTG_DIEPCTL_SD0PID_SEVNFRM | USB_OTG_DIEPCTL_USBAEP; + USBx_INEP(1)->DIEPINT = 0xFF; + + USBx_OUTEP(2)->DOEPTSIZ = (1 << 19) | 0x40; + USBx_OUTEP(2)->DOEPCTL = (0x40 & USB_OTG_DOEPCTL_MPSIZ) | (2 << 18) | + USB_OTG_DOEPCTL_SD0PID_SEVNFRM | USB_OTG_DOEPCTL_USBAEP; + USBx_OUTEP(2)->DOEPINT = 0xFF; + + USBx_OUTEP(3)->DOEPTSIZ = (1 << 19) | 0x40; + USBx_OUTEP(3)->DOEPCTL = (0x40 & USB_OTG_DOEPCTL_MPSIZ) | (2 << 18) | + USB_OTG_DOEPCTL_SD0PID_SEVNFRM | USB_OTG_DOEPCTL_USBAEP; + USBx_OUTEP(3)->DOEPINT = 0xFF; + + // mark ready to receive + USBx_OUTEP(2)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK; + USBx_OUTEP(3)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK; + + // TODO: is this the right place for this? + usb_cb_enumeration_complete(); + + USB_WritePacket(0, 0, 0); + USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; + break; + case USB_REQ_SET_ADDRESS: + // set now? + USBx_DEVICE->DCFG |= ((setup.b.wValue.w & 0x7f) << 4); + + #ifdef DEBUG_USB + puts(" set address\n"); + #endif + + USB_WritePacket(0, 0, 0); + USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; + + break; + case USB_REQ_GET_DESCRIPTOR: + switch (setup.b.wValue.bw.lsb) { + case USB_DESC_TYPE_DEVICE: + //puts(" writing device descriptor\n"); + + // setup transfer + USB_WritePacket(device_desc, min(sizeof(device_desc), setup.b.wLength.w), 0); + USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; + + //puts("D"); + break; + case USB_DESC_TYPE_CONFIGURATION: + USB_WritePacket(configuration_desc, min(sizeof(configuration_desc), setup.b.wLength.w), 0); + USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; + break; + case USB_DESC_TYPE_STRING: + switch (setup.b.wValue.bw.msb) { + case 0: + USB_WritePacket((uint8_t*)string_0_desc, min(sizeof(string_0_desc), setup.b.wLength.w), 0); + break; + case 1: + USB_WritePacket((uint8_t*)string_1_desc, min(sizeof(string_1_desc), setup.b.wLength.w), 0); + break; + case 2: + USB_WritePacket((uint8_t*)string_2_desc, min(sizeof(string_2_desc), setup.b.wLength.w), 0); + break; + case 3: + #ifdef PANDA + resp[0] = 0x02 + 12*4; + resp[1] = 0x03; + + // 96 bits = 12 bytes + for (i = 0; i < 12; i++){ + uint8_t cc = ((uint8_t *)UID_BASE)[i]; + resp[2 + i*4 + 0] = to_hex_char((cc>>4)&0xF); + resp[2 + i*4 + 1] = '\0'; + resp[2 + i*4 + 2] = to_hex_char((cc>>0)&0xF); + resp[2 + i*4 + 3] = '\0'; + } + + USB_WritePacket(resp, min(resp[0], setup.b.wLength.w), 0); + #else + USB_WritePacket(string_3_desc, min(sizeof(string_3_desc), setup.b.wLength.w), 0); + #endif + break; + default: + // nothing + USB_WritePacket(0, 0, 0); + break; + } + USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; + break; + default: + // nothing here? + USB_WritePacket(0, 0, 0); + USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; + break; + } + break; + case USB_REQ_GET_STATUS: + // empty resp? + resp[0] = 0; + resp[1] = 0; + 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); + USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; + } +} + +void usb_init() { + // full speed PHY, do reset and remove power down + puth(USBx->GRSTCTL); + puts(" resetting PHY\n"); + while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0); + puts("AHB idle\n"); + + // reset PHY here + USBx->GRSTCTL |= USB_OTG_GRSTCTL_CSRST; + while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_CSRST) == USB_OTG_GRSTCTL_CSRST); + puts("reset done\n"); + + // internal PHY, force device mode + USBx->GUSBCFG = USB_OTG_GUSBCFG_PHYSEL | USB_OTG_GUSBCFG_FDMOD; + + // slowest timings + USBx->GUSBCFG |= (uint32_t)((USBD_FS_TRDT_VALUE << 10) & USB_OTG_GUSBCFG_TRDT); + + // power up the PHY +#ifdef STM32F4 + USBx->GCCFG = USB_OTG_GCCFG_PWRDWN; + + //USBx->GCCFG |= USB_OTG_GCCFG_VBDEN | USB_OTG_GCCFG_SDEN |USB_OTG_GCCFG_PDEN | USB_OTG_GCCFG_DCDEN; + + /* B-peripheral session valid override enable*/ + USBx->GOTGCTL |= USB_OTG_GOTGCTL_BVALOVAL; + USBx->GOTGCTL |= USB_OTG_GOTGCTL_BVALOEN; +#else + USBx->GCCFG = USB_OTG_GCCFG_PWRDWN | USB_OTG_GCCFG_NOVBUSSENS; +#endif + + // be a device, slowest timings + //USBx->GUSBCFG = USB_OTG_GUSBCFG_FDMOD | USB_OTG_GUSBCFG_PHYSEL | USB_OTG_GUSBCFG_TRDT | USB_OTG_GUSBCFG_TOCAL; + //USBx->GUSBCFG |= (uint32_t)((USBD_FS_TRDT_VALUE << 10) & USB_OTG_GUSBCFG_TRDT); + //USBx->GUSBCFG = USB_OTG_GUSBCFG_PHYSEL | USB_OTG_GUSBCFG_TRDT | USB_OTG_GUSBCFG_TOCAL; + + // **** for debugging, doesn't seem to work **** + //USBx->GUSBCFG |= USB_OTG_GUSBCFG_CTXPKT; + + // reset PHY clock + USBx_PCGCCTL = 0; + + // enable the fancy OTG things + // DCFG_FRAME_INTERVAL_80 is 0 + //USBx->GUSBCFG |= USB_OTG_GUSBCFG_HNPCAP | USB_OTG_GUSBCFG_SRPCAP; + USBx_DEVICE->DCFG |= USB_OTG_SPEED_FULL | USB_OTG_DCFG_NZLSOHSK; + + //USBx_DEVICE->DCFG = USB_OTG_DCFG_NZLSOHSK | USB_OTG_DCFG_DSPD; + //USBx_DEVICE->DCFG = USB_OTG_DCFG_DSPD; + + // clear pending interrupts + USBx->GINTSTS = 0xBFFFFFFFU; + + // setup USB interrupts + // all interrupts except TXFIFO EMPTY + //USBx->GINTMSK = 0xFFFFFFFF & ~(USB_OTG_GINTMSK_NPTXFEM | USB_OTG_GINTMSK_PTXFEM | USB_OTG_GINTSTS_SOF | USB_OTG_GINTSTS_EOPF); + //USBx->GINTMSK = 0xFFFFFFFF & ~(USB_OTG_GINTMSK_NPTXFEM | USB_OTG_GINTMSK_PTXFEM); + USBx->GINTMSK = USB_OTG_GINTMSK_USBRST | USB_OTG_GINTMSK_ENUMDNEM | USB_OTG_GINTMSK_OTGINT | + USB_OTG_GINTMSK_RXFLVLM | USB_OTG_GINTMSK_GONAKEFFM | USB_OTG_GINTMSK_GINAKEFFM | + USB_OTG_GINTMSK_OEPINT | USB_OTG_GINTMSK_IEPINT | USB_OTG_GINTMSK_USBSUSPM | + USB_OTG_GINTMSK_CIDSCHGM | USB_OTG_GINTMSK_SRQIM | USB_OTG_GINTMSK_MMISM; + + USBx->GAHBCFG = USB_OTG_GAHBCFG_GINT; + + // DCTL startup value is 2 on new chip, 0 on old chip + // THIS IS FUCKING BULLSHIT + USBx_DEVICE->DCTL = 0; +} // ***************************** USB port ***************************** -void usb_irqhandler(void); -#endif +void usb_irqhandler(void) { + //USBx->GINTMSK = 0; + + unsigned int gintsts = USBx->GINTSTS; + unsigned int gotgint = USBx->GOTGINT; + unsigned int daint = USBx_DEVICE->DAINT; + + // gintsts SUSPEND? 04008428 + #ifdef DEBUG_USB + puth(gintsts); + puts(" "); + /*puth(USBx->GCCFG); + puts(" ");*/ + puth(gotgint); + puts(" ep "); + puth(daint); + puts(" USB interrupt!\n"); + #endif + + if (gintsts & USB_OTG_GINTSTS_CIDSCHG) { + puts("connector ID status change\n"); + } + + if (gintsts & USB_OTG_GINTSTS_ESUSP) { + puts("ESUSP detected\n"); + } + + if (gintsts & USB_OTG_GINTSTS_USBRST) { + puts("USB reset\n"); + usb_reset(); + } + + if (gintsts & USB_OTG_GINTSTS_ENUMDNE) { + puts("enumeration done "); + // Full speed, ENUMSPD + puth(USBx_DEVICE->DSTS); + puts("\n"); + } + + if (gintsts & USB_OTG_GINTSTS_OTGINT) { + puts("OTG int:"); + puth(USBx->GOTGINT); + puts("\n"); + + // getting ADTOCHG + //USBx->GOTGINT = USBx->GOTGINT; + } + + // RX FIFO first + if (gintsts & USB_OTG_GINTSTS_RXFLVL) { + // 1. Read the Receive status pop register + volatile unsigned int rxst = USBx->GRXSTSP; + + #ifdef DEBUG_USB + puts(" RX FIFO:"); + puth(rxst); + puts(" status: "); + puth((rxst & USB_OTG_GRXSTSP_PKTSTS) >> 17); + puts(" len: "); + puth((rxst & USB_OTG_GRXSTSP_BCNT) >> 4); + 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; + USB_ReadPacket(&usbdata, len); + #ifdef DEBUG_USB + puts(" data "); + puth(len); + puts("\n"); + hexdump(&usbdata, len); + #endif + + if (endpoint == 2) { + usb_cb_ep2_out(usbdata, len, 1); + } + + if (endpoint == 3) { + usb_cb_ep3_out(usbdata, len, 1); + } + } else if (((rxst & USB_OTG_GRXSTSP_PKTSTS) >> 17) == STS_SETUP_UPDT) { + USB_ReadPacket(&setup, 8); + #ifdef DEBUG_USB + puts(" setup "); + hexdump(&setup, 8); + puts("\n"); + #endif + } + } + + /*if (gintsts & USB_OTG_GINTSTS_HPRTINT) { + // host + puts("HPRT:"); + puth(USBx_HOST_PORT->HPRT); + puts("\n"); + if (USBx_HOST_PORT->HPRT & USB_OTG_HPRT_PCDET) { + USBx_HOST_PORT->HPRT |= USB_OTG_HPRT_PRST; + USBx_HOST_PORT->HPRT |= USB_OTG_HPRT_PCDET; + } + + }*/ + + if ((gintsts & USB_OTG_GINTSTS_BOUTNAKEFF) || (gintsts & USB_OTG_GINTSTS_GINAKEFF)) { + // no global NAK, why is this getting set? + #ifdef DEBUG_USB + puts("GLOBAL NAK\n"); + #endif + USBx_DEVICE->DCTL |= USB_OTG_DCTL_CGONAK | USB_OTG_DCTL_CGINAK; + } + + if (gintsts & USB_OTG_GINTSTS_SRQINT) { + // we want to do "A-device host negotiation protocol" since we are the A-device + puts("start request\n"); + puth(USBx->GOTGCTL); + puts("\n"); + //USBx->GUSBCFG |= USB_OTG_GUSBCFG_FDMOD; + //USBx_HOST_PORT->HPRT = USB_OTG_HPRT_PPWR | USB_OTG_HPRT_PENA; + //USBx->GOTGCTL |= USB_OTG_GOTGCTL_SRQ; + } + + // out endpoint hit + if (gintsts & USB_OTG_GINTSTS_OEPINT) { + #ifdef DEBUG_USB + puts(" 0:"); + puth(USBx_OUTEP(0)->DOEPINT); + puts(" 2:"); + puth(USBx_OUTEP(2)->DOEPINT); + puts(" 3:"); + puth(USBx_OUTEP(3)->DOEPINT); + puts(" "); + puth(USBx_OUTEP(3)->DOEPCTL); + puts(" 4:"); + puth(USBx_OUTEP(4)->DOEPINT); + puts(" OUT ENDPOINT\n"); + #endif + + if (USBx_OUTEP(2)->DOEPINT & USB_OTG_DOEPINT_XFRC) { + #ifdef DEBUG_USB + puts(" OUT2 PACKET XFRC\n"); + #endif + USBx_OUTEP(2)->DOEPTSIZ = (1 << 19) | 0x40; + USBx_OUTEP(2)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK; + } + + if (USBx_OUTEP(3)->DOEPINT & USB_OTG_DOEPINT_XFRC) { + #ifdef DEBUG_USB + puts(" OUT3 PACKET XFRC\n"); + #endif + USBx_OUTEP(3)->DOEPTSIZ = (1 << 19) | 0x40; + USBx_OUTEP(3)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK; + } else if (USBx_OUTEP(3)->DOEPINT & 0x2000) { + #ifdef DEBUG_USB + puts(" OUT3 PACKET WTF\n"); + #endif + // if NAK was set trigger this, unknown interrupt + USBx_OUTEP(3)->DOEPTSIZ = (1 << 19) | 0x40; + USBx_OUTEP(3)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; + } else if (USBx_OUTEP(3)->DOEPINT) { + puts("OUTEP3 error "); + puth(USBx_OUTEP(3)->DOEPINT); + puts("\n"); + } + + if (USBx_OUTEP(0)->DOEPINT & USB_OTG_DIEPINT_XFRC) { + // ready for next packet + USBx_OUTEP(0)->DOEPTSIZ = USB_OTG_DOEPTSIZ_STUPCNT | (USB_OTG_DOEPTSIZ_PKTCNT & (1 << 19)) | (1 * 8); + } + + // respond to setup packets + if (USBx_OUTEP(0)->DOEPINT & USB_OTG_DOEPINT_STUP) { + usb_setup(); + } + + USBx_OUTEP(0)->DOEPINT = USBx_OUTEP(0)->DOEPINT; + USBx_OUTEP(2)->DOEPINT = USBx_OUTEP(2)->DOEPINT; + USBx_OUTEP(3)->DOEPINT = USBx_OUTEP(3)->DOEPINT; + } + + // interrupt endpoint hit (Page 1221) + if (gintsts & USB_OTG_GINTSTS_IEPINT) { + #ifdef DEBUG_USB + puts(" "); + puth(USBx_INEP(0)->DIEPINT); + puts(" "); + puth(USBx_INEP(1)->DIEPINT); + puts(" IN ENDPOINT\n"); + #endif + + // Should likely check the EP of the IN request even if there is + // only one IN endpoint. + + // 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); + } + 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; // Why ep0? + USBx_INEP(1)->DIEPINT = USBx_INEP(1)->DIEPINT; + } + + // clear all interrupts we handled + USBx_DEVICE->DAINT = daint; + USBx->GOTGINT = gotgint; + USBx->GINTSTS = gintsts; + + //USBx->GINTMSK = 0xFFFFFFFF & ~(USB_OTG_GINTMSK_NPTXFEM | USB_OTG_GINTMSK_PTXFEM | USB_OTG_GINTSTS_SOF | USB_OTG_GINTSTS_EOPF); +} diff --git a/drivers/linux/panda.c b/drivers/linux/panda.c index cb8c0e5..4c5980a 100644 --- a/drivers/linux/panda.c +++ b/drivers/linux/panda.c @@ -152,16 +152,11 @@ static void panda_urb_unlink(struct panda_inf_priv *priv) usb_kill_anchored_urbs(&priv->tx_submitted); } -#define SAFETY_NOOUTPUT 0 -#define SAFETY_HONDA 1 -#define SAFETY_ALLOUTPUT 0x1337 - -static int panda_set_output_mode(struct panda_inf_priv* priv, bool enable){ +static int panda_set_output_enable(struct panda_inf_priv* priv, bool enable){ return usb_control_msg(priv->priv_dev->udev, usb_sndctrlpipe(priv->priv_dev->udev, 0), 0xDC, USB_TYPE_VENDOR | USB_RECIP_DEVICE, - enable ? SAFETY_ALLOUTPUT : SAFETY_NOOUTPUT, 0, NULL, - 0, USB_CTRL_SET_TIMEOUT); + enable ? 0x1337 : 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); } static void panda_usb_write_bulk_callback(struct urb *urb) diff --git a/panda/__init__.py b/panda/__init__.py index f088fa4..ad69014 100644 --- a/panda/__init__.py +++ b/panda/__init__.py @@ -24,7 +24,7 @@ def parse_can_buffer(dat): address = f1 >> 3 else: address = f1 >> 21 - ret.append((address, f2>>16, ddat[8:8+(f2&0xF)], (f2>>4)&0xFFF)) + ret.append((address, f2>>16, ddat[8:8+(f2&0xF)], (f2>>4)&0xf)) return ret class PandaWifiStreaming(object): @@ -57,11 +57,8 @@ class WifiHandle(object): return ret[4:4+length] def controlWrite(self, request_type, request, value, index, data, timeout=0): - self.sock.send( - struct.pack("HHBBHHH", 0, 0, request_type, request, value, index, len(data)) + data - ) - retdata = self.__recv() - assert len(retdata) == 0 + # ignore data in reply, panda doesn't use it + return self.controlRead(request_type, request, value, index, 0, timeout) def controlRead(self, request_type, request, value, index, length, timeout=0): self.sock.send(struct.pack("HHBBHHH", 0, 0, request_type, request, value, index, length)) @@ -80,16 +77,10 @@ class WifiHandle(object): def close(self): self.sock.close() -SAFETY_NOOUTPUT = 0 -SAFETY_HONDA = 1 -SAFETY_ALLOUTPUT = 0x1337 - class Panda(object): - REQUEST_IN = usb1.ENDPOINT_IN | usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE - REQUEST_OUT = usb1.ENDPOINT_OUT | usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE + REQUEST_TYPE = usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE def __init__(self, serial=None, claim=True): - self._serial = serial if serial == "WIFI": self._handle = WifiHandle() print("opening WIFI device") @@ -104,7 +95,7 @@ class Panda(object): self._handle = device.open() if claim: self._handle.claimInterface(0) - #self._handle.setInterfaceAltSetting(0, 0) + self._handle.setInterfaceAltSetting(0, 0) break assert self._handle != None @@ -126,7 +117,7 @@ class Panda(object): # ******************* health ******************* def health(self): - dat = self._handle.controlRead(Panda.REQUEST_IN, 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], @@ -138,45 +129,38 @@ class Panda(object): def enter_bootloader(self): try: - self._handle.controlWrite(Panda.REQUEST_OUT, 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_IN, 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_IN, 0xd0, 1, 0, 0x10) + return self._handle.controlRead(Panda.REQUEST_TYPE, 0xd0, 1, 0, 0x10) # ******************* configuration ******************* - def set_controls_mode(self, mode=SAFETY_ALLOUTPUT): - self._handle.controlWrite(Panda.REQUEST_OUT, 0xdc, mode, 0, b'') + def set_controls_allowed(self, on): + self._handle.controlWrite(Panda.REQUEST_TYPE, 0xdc, (0x1337 if on else 0), 0, b'') - def set_can_baud(self, bus, baud): - self._handle.controlWrite(Panda.REQUEST_OUT, 0xde, bus, 0, struct.pack('I', baud)) - return self.get_can_baud(bus) - - def get_can_baud(self, bus): - return struct.unpack("I", self._handle.controlRead(Panda.REQUEST_IN, 0xdf, bus, 0, 4))[0] - - def set_gmlan(self, bus, on): - self._handle.controlWrite(Panda.REQUEST_OUT, 0xdb, bus, bool(on), b'') + def set_gmlan(self, on, bus=2): + self._handle.controlWrite(Panda.REQUEST_TYPE, 0xdb, 1, bus, b'') def set_uart_baud(self, uart, rate): - self._handle.controlWrite(Panda.REQUEST_OUT, 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_OUT, 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_OUT, 0xe3, uart, int(install), b'') + self._handle.controlWrite(Panda.REQUEST_TYPE, 0xe3, uart, int(install), b'') # ******************* can ******************* @@ -218,7 +202,7 @@ class Panda(object): # ******************* serial ******************* def serial_read(self, port_number): - return self._handle.controlRead(Panda.REQUEST_IN, 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) @@ -227,13 +211,13 @@ class Panda(object): # pulse low for wakeup def kline_wakeup(self): - self._handle.controlWrite(Panda.REQUEST_OUT, 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_IN, 0xe0, bus, 0, 0x40) + ret = self._handle.controlRead(Panda.REQUEST_TYPE, 0xe0, bus, 0, 0x40) if len(ret) == 0: break bret += ret @@ -242,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_IN, 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): diff --git a/tests/debug_console.py b/tests/debug_console.py index 8df86ac..94a6416 100755 --- a/tests/debug_console.py +++ b/tests/debug_console.py @@ -19,10 +19,6 @@ if __name__ == "__main__": serials = filter(lambda x: x==os.getenv("SERIAL"), serials) pandas = list(map(lambda x: Panda(x, False), serials)) - - for i, p in enumerate(pandas): - print("%s Panda %s%s" % (setcolor[i], p._serial, unsetcolor)) - while True: for i, panda in enumerate(pandas): while True: diff --git a/tests/loopback_test.py b/tests/loopback_test.py index 4592fe7..0b66a1e 100755 --- a/tests/loopback_test.py +++ b/tests/loopback_test.py @@ -4,7 +4,6 @@ import os import sys import time import random -import argparse from hexdump import hexdump from itertools import permutations @@ -15,7 +14,7 @@ from panda import Panda def get_test_string(): return b"test"+os.urandom(10) -def run_test(can_speeds, gmlan_speeds, sleep_duration=0): +def run_test(): pandas = Panda.list() print(pandas) @@ -26,42 +25,34 @@ def run_test(can_speeds, gmlan_speeds, sleep_duration=0): if len(pandas) == 1: # if we only have one on USB, assume the other is on wifi pandas.append("WIFI") - run_test_w_pandas(pandas, can_speeds, gmlan_speeds, sleep_duration) + run_test_w_pandas(pandas) -GMLAN_BUS = 3 # Virtual 'CAN 4' - -def run_test_w_pandas(pandas, can_speeds, gmlan_speeds, sleep_duration=0): +def run_test_w_pandas(pandas): h = list(map(lambda x: Panda(x), pandas)) print("H", h) for hh in h: - hh.set_controls_mode() + hh.set_controls_allowed(True) # test both directions for ho in permutations(range(len(h)), r=2): print("***************** TESTING", ho) - panda_snd, panda_rcv = h[ho[0]], h[ho[1]] - - if(panda_snd._serial == "WIFI"): - print(" *** Can not send can data over wifi panda. Skipping! ***") - continue - # **** test health packet **** - print("health", ho[0], panda_snd.health()) + print("health", ho[0], h[ho[0]].health()) # **** test K/L line loopback **** for bus in [2,3]: # flush the output - panda_rcv.kline_drain(bus=bus) + h[ho[1]].kline_drain(bus=bus) # send the characters st = get_test_string() st = b"\xaa"+chr(len(st)+3).encode()+st - panda_snd.kline_send(st, bus=bus, checksum=False) + h[ho[0]].kline_send(st, bus=bus, checksum=False) # check for receive - ret = panda_rcv.kline_drain(bus=bus) + ret = h[ho[1]].kline_drain(bus=bus) print("ST Data:") hexdump(st) @@ -69,41 +60,40 @@ def run_test_w_pandas(pandas, can_speeds, gmlan_speeds, sleep_duration=0): hexdump(ret) assert st == ret print("K/L pass", bus, ho, "\n") - time.sleep(sleep_duration) # **** test can line loopback **** - for bus, gmlan in [(0, None), (1, False), (2, False), (1, True), (2, True)]: - print("\ntest can", bus, "gmlan" if gmlan else "") + for bus in [0,1,4,5,6]: + panda0 = h[ho[0]] + panda1 = h[ho[1]] + print("\ntest can", bus) # flush - cans_echo = panda_snd.can_recv() - cans_loop = panda_rcv.can_recv() + cans_echo = panda0.can_recv() + cans_loop = panda1.can_recv() # set GMLAN mode - if(gmlan is not None): - panda_snd.set_gmlan(bus, gmlan) - panda_rcv.set_gmlan(bus, gmlan) - - if gmlan: - print("Setting GMLAN %d Speed to %d" % (bus, gmlan_speeds[bus])) - panda_snd.set_can_baud(bus, gmlan_speeds[bus]) - panda_rcv.set_can_baud(bus, gmlan_speeds[bus]) - bus = GMLAN_BUS + if bus == 5: + panda0.set_gmlan(True,2) + panda1.set_gmlan(True,2) + bus = 1 # GMLAN is multiplexed with CAN2 + elif bus == 6: + # on REV B panda, this just retests CAN2 GMLAN + panda0.set_gmlan(True,3) + panda1.set_gmlan(True,3) + bus = 4 # GMLAN is also multiplexed with CAN3 else: - print("bus", bus) - print("Setting CanBus %d Speed to %d" % (bus, can_speeds[bus])) - panda_snd.set_can_baud(bus, can_speeds[bus]) - panda_rcv.set_can_baud(bus, can_speeds[bus]) + panda0.set_gmlan(False) + panda1.set_gmlan(False) # send the characters # pick addresses high enough to not conflict with honda code at = random.randint(1024, 2000) st = get_test_string()[0:8] - panda_snd.can_send(at, st, bus) + panda0.can_send(at, st, bus) time.sleep(0.1) # check for receive - cans_echo = panda_snd.can_recv() - cans_loop = panda_rcv.can_recv() + cans_echo = panda0.can_recv() + cans_loop = panda1.can_recv() print("Bus", bus, "echo", cans_echo, "loop", cans_loop) @@ -116,31 +106,20 @@ def run_test_w_pandas(pandas, can_speeds, gmlan_speeds, sleep_duration=0): assert cans_echo[0][2] == st assert cans_loop[0][2] == st - assert cans_echo[0][3] == 0x80 | bus + assert cans_echo[0][3] == bus+2 if cans_loop[0][3] != bus: print("EXPECTED %d GOT %d" % (bus, cans_loop[0][3])) assert cans_loop[0][3] == bus - time.sleep(sleep_duration) print("CAN pass", bus, ho) if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument("-n", type=int, help="Number of test iterations to run") - parser.add_argument("-can1baud", type=int, help="Baud Rate of CAN1", default=500000) - parser.add_argument("-can2baud", type=int, help="Baud Rate of CAN2", default=500000) - parser.add_argument("-can3baud", type=int, help="Baud Rate of CAN3", default=500000) - parser.add_argument("-gmlan2baud", type=int, help="Baud Rate of GMLAN2", default=33333) - parser.add_argument("-gmlan3baud", type=int, help="Baud Rate of GMLAN3", default=33333) - parser.add_argument("-sleep", type=int, help="Sleep time between tests", default=0) - args = parser.parse_args() - - can_speeds = (args.can1baud, args.can2baud, args.can3baud) - gmlan_speeds = (None, args.gmlan2baud, args.gmlan2baud) - - if args.n is None: + if len(sys.argv) > 1: + for i in range(int(sys.argv[1])): + run_test() + else : + i = 0 while True: - run_test(can_speeds, gmlan_speeds, sleep_duration=args.sleep) - else: - for i in range(args.n): - run_test(can_speeds, gmlan_speeds, sleep_duration=args.sleep) + print("************* testing %d" % i) + run_test() + i += 1 diff --git a/tests/standalone_test.py b/tests/standalone_test.py index 9008bf8..76df023 100755 --- a/tests/standalone_test.py +++ b/tests/standalone_test.py @@ -21,7 +21,7 @@ if __name__ == "__main__": t2 = time.time() print("100 requests took %.2f ms" % ((t2-t1)*1000)) - p.set_controls_mode() + p.set_controls_allowed(True) a = 0 while True: diff --git a/tests/throughput_test.py b/tests/throughput_test.py index cc2bb57..5812ce4 100755 --- a/tests/throughput_test.py +++ b/tests/throughput_test.py @@ -25,7 +25,7 @@ if __name__ == "__main__": # p_in.can_recv() #sys.exit(0) - p_out.set_controls_mode() + p_out.set_controls_allowed(True) set_out, set_in = set(), set()