From 59f5813173c9d984d834287491a41741b154f2df Mon Sep 17 00:00:00 2001 From: rbiasini Date: Tue, 23 Jul 2019 15:07:06 -0700 Subject: [PATCH] Black (#254) * late usb * Added type support for black panda * Added harness presence and orientation detection * harness relay driving code * Added intercept support in black panda code. Switched around can0 and can2 * Disable ADCs after orientation detection. Ignition interrupts via harness * WIP: Hardware abstraction layer + black panda bringup * Fixed bootstub build * Fixed bootstub for pedal * Fixed infinite loops * Got CAN buses working on white again * Fixed pedal build and black can interfaces * Got CAN buses working on black panda * Finished loopback test for black panda * Erase all flash sectors on the panda. Increased binary limit. Added extra python functions. * Fixed python * Made new code MISRA compliant * Cleaned up ignition. Fixed build * Fixed health packet * Fixed CAN mode on black bug. Changed OBD to switch on ELM mode * Fixes from Github review * Fixed MISRA issue for pedal * Fixed failing gmlan tests * ELM327 safety: allow diagnostic on all buses * Cleaned up EON relay code * delete only 3 sectors instead of 11 to allow a new build to be flashed. Much faster to flash * Removed CAN only can0 output mode. Does not make sense on black panda due to reversibility issues. * Added heartbeat logic for EON code on panda. Go to NOOUTPUT if EON does not send a heartbeat for 5 seconds. * Remove all CAN buses live on EON startup. Shouldn't be necessary to have this separate case * Formatting * Added file I forgot to push * Added heartbeat to testing code to make sure EON tests don't fail. Should probably find a better way to do this though. Heartbeat thread didn't work, concurrent USB connection issues... * Safety: support black panda for Honda Bosch * Disable OBD2 if setting to NOOUTPUT mode * Run safety tests for all hw_types * Fail test if subtest fails * fix safety tests --- board/board.h | 61 ++++ board/board_declarations.h | 57 ++++ board/boards/black.h | 188 +++++++++++ board/boards/common.h | 82 +++++ board/boards/grey.h | 18 ++ board/boards/pedal.h | 96 ++++++ board/boards/white.h | 306 ++++++++++++++++++ board/bootstub.c | 34 +- board/build.mk | 2 +- board/drivers/can.h | 101 ++++-- board/drivers/harness.h | 130 ++++++++ board/drivers/llgpio.h | 11 + board/gpio.h | 397 +----------------------- board/main.c | 388 +++++++++++------------ board/main_declarations.h | 14 + board/pedal/main.c | 22 +- board/pedal/main_declarations.h | 11 + board/power_saving.h | 24 +- board/safety/safety_elm327.h | 6 - board/safety/safety_honda.h | 13 +- board/spi_flasher.h | 18 +- python/__init__.py | 45 ++- tests/automated/2_usb_to_can.py | 33 ++ tests/automated/4_wifi_functionality.py | 13 + tests/automated/6_two_panda.py | 18 ++ tests/black_loopback_test.py | 137 ++++++++ tests/safety/libpandasafety_py.py | 2 + tests/safety/test.c | 31 ++ tests/safety/test.sh | 17 +- tests/safety/test_honda.py | 4 + tests/safety/test_honda_bosch.py | 14 +- 31 files changed, 1611 insertions(+), 682 deletions(-) create mode 100644 board/board.h create mode 100644 board/board_declarations.h create mode 100644 board/boards/black.h create mode 100644 board/boards/common.h create mode 100644 board/boards/grey.h create mode 100644 board/boards/pedal.h create mode 100644 board/boards/white.h create mode 100644 board/drivers/harness.h create mode 100644 board/main_declarations.h create mode 100644 board/pedal/main_declarations.h create mode 100755 tests/black_loopback_test.py diff --git a/board/board.h b/board/board.h new file mode 100644 index 00000000000000..5379f94643bb04 --- /dev/null +++ b/board/board.h @@ -0,0 +1,61 @@ +// ///////////////////////////////////////////////////////////// // +// Hardware abstraction layer for all different supported boards // +// ///////////////////////////////////////////////////////////// // +#include "board_declarations.h" +#include "boards/common.h" + +// ///// Board definition and detection ///// // +#include "drivers/harness.h" +#ifdef PANDA + #include "boards/white.h" + #include "boards/grey.h" + #include "boards/black.h" +#else + #include "boards/pedal.h" +#endif + +void detect_board_type(void) { + #ifdef PANDA + // SPI lines floating: white (TODO: is this reliable?) + if((detect_with_pull(GPIOA, 4, PULL_DOWN)) || (detect_with_pull(GPIOA, 5, PULL_DOWN)) || (detect_with_pull(GPIOA, 6, PULL_DOWN)) || (detect_with_pull(GPIOA, 7, PULL_DOWN))){ + hw_type = HW_TYPE_WHITE_PANDA; + current_board = &board_white; + } else if(detect_with_pull(GPIOA, 13, PULL_DOWN)) { // Rev AB deprecated, so no pullup means black. In REV C, A13 is pulled up to 5V with a 10K + hw_type = HW_TYPE_GREY_PANDA; + current_board = &board_grey; + } else { + hw_type = HW_TYPE_BLACK_PANDA; + current_board = &board_black; + } + #else + #ifdef PEDAL + hw_type = HW_TYPE_PEDAL; + current_board = &board_pedal; + #else + hw_type = HW_TYPE_UNKNOWN; + puts("Hardware type is UNKNOWN!\n"); + #endif + #endif +} + + +// ///// Configuration detection ///// // +bool has_external_debug_serial = 0; +bool is_entering_bootmode = 0; + +void detect_configuration(void) { + // detect if external serial debugging is present + has_external_debug_serial = detect_with_pull(GPIOA, 3, PULL_DOWN); + + #ifdef PANDA + // check if the ESP is trying to put me in boot mode + is_entering_bootmode = !detect_with_pull(GPIOB, 0, PULL_UP); + #else + is_entering_bootmode = 0; + #endif +} + +// ///// Board functions ///// // +bool board_has_gps(void) { + return ((hw_type == HW_TYPE_GREY_PANDA) || (hw_type == HW_TYPE_BLACK_PANDA)); +} diff --git a/board/board_declarations.h b/board/board_declarations.h new file mode 100644 index 00000000000000..7a44113f613bf2 --- /dev/null +++ b/board/board_declarations.h @@ -0,0 +1,57 @@ +// ******************** Prototypes ******************** +typedef void (*board_init)(void); +typedef void (*board_enable_can_transciever)(uint8_t transciever, bool enabled); +typedef void (*board_enable_can_transcievers)(bool enabled); +typedef void (*board_set_led)(uint8_t color, bool enabled); +typedef void (*board_set_usb_power_mode)(uint8_t mode); +typedef void (*board_set_esp_gps_mode)(uint8_t mode); +typedef void (*board_set_can_mode)(uint8_t mode); +typedef void (*board_usb_power_mode_tick)(uint64_t tcnt); +typedef bool (*board_check_ignition)(void); + +struct board { + const char *board_type; + const harness_configuration *harness_config; + board_init init; + board_enable_can_transciever enable_can_transciever; + board_enable_can_transcievers enable_can_transcievers; + board_set_led set_led; + board_set_usb_power_mode set_usb_power_mode; + board_set_esp_gps_mode set_esp_gps_mode; + board_set_can_mode set_can_mode; + board_usb_power_mode_tick usb_power_mode_tick; + board_check_ignition check_ignition; +}; + +// ******************* Definitions ******************** +// These should match the enum in cereal/log.capnp +#define HW_TYPE_UNKNOWN 0U +#define HW_TYPE_WHITE_PANDA 1U +#define HW_TYPE_GREY_PANDA 2U +#define HW_TYPE_BLACK_PANDA 3U +#define HW_TYPE_PEDAL 4U + +// LED colors +#define LED_RED 0U +#define LED_GREEN 1U +#define LED_BLUE 2U + +// USB power modes +#define USB_POWER_NONE 0U +#define USB_POWER_CLIENT 1U +#define USB_POWER_CDP 2U +#define USB_POWER_DCP 3U + +// ESP modes +#define ESP_GPS_DISABLED 0U +#define ESP_GPS_ENABLED 1U +#define ESP_GPS_BOOTMODE 2U + +// CAN modes +#define CAN_MODE_NORMAL 0U +#define CAN_MODE_GMLAN_CAN2 1U +#define CAN_MODE_GMLAN_CAN3 2U +#define CAN_MODE_OBD_CAN2 3U + +// ********************* Globals ********************** +uint8_t usb_power_mode = USB_POWER_NONE; \ No newline at end of file diff --git a/board/boards/black.h b/board/boards/black.h new file mode 100644 index 00000000000000..0372aa3d079ae2 --- /dev/null +++ b/board/boards/black.h @@ -0,0 +1,188 @@ +// ///////////////////// // +// Black Panda + Harness // +// ///////////////////// // + +void black_enable_can_transciever(uint8_t transciever, bool enabled) { + switch (transciever){ + case 1U: + set_gpio_output(GPIOC, 1, !enabled); + break; + case 2U: + set_gpio_output(GPIOC, 13, !enabled); + break; + case 3U: + set_gpio_output(GPIOA, 0, !enabled); + break; + case 4U: + set_gpio_output(GPIOB, 10, !enabled); + break; + default: + puts("Invalid CAN transciever ("); puth(transciever); puts("): enabling failed\n"); + break; + } +} + +void black_enable_can_transcievers(bool enabled) { + for(uint8_t i=1; i<=4U; i++) + black_enable_can_transciever(i, enabled); +} + +void black_set_led(uint8_t color, bool enabled) { + switch (color){ + case LED_RED: + set_gpio_output(GPIOC, 9, !enabled); + break; + case LED_GREEN: + set_gpio_output(GPIOC, 7, !enabled); + break; + case LED_BLUE: + set_gpio_output(GPIOC, 6, !enabled); + break; + default: + break; + } +} + +void black_set_usb_power_mode(uint8_t mode){ + usb_power_mode = mode; + puts("Trying to set USB power mode on black panda. This is not supported.\n"); +} + +void black_set_esp_gps_mode(uint8_t mode) { + switch (mode) { + case ESP_GPS_DISABLED: + // ESP OFF + set_gpio_output(GPIOC, 14, 0); + set_gpio_output(GPIOC, 5, 0); + break; + case ESP_GPS_ENABLED: + // ESP ON + set_gpio_output(GPIOC, 14, 1); + set_gpio_output(GPIOC, 5, 1); + break; + case ESP_GPS_BOOTMODE: + set_gpio_output(GPIOC, 14, 1); + set_gpio_output(GPIOC, 5, 0); + break; + default: + puts("Invalid ESP/GPS mode\n"); + break; + } +} + +void black_set_can_mode(uint8_t mode){ + switch (mode) { + case CAN_MODE_NORMAL: + case CAN_MODE_OBD_CAN2: + if ((bool)(mode == CAN_MODE_NORMAL) != (bool)(car_harness_status == HARNESS_STATUS_NORMAL)) { + // B12,B13: disable OBD mode + set_gpio_mode(GPIOB, 12, MODE_INPUT); + set_gpio_mode(GPIOB, 13, MODE_INPUT); + + // B5,B6: normal CAN2 mode + set_gpio_alternate(GPIOB, 5, GPIO_AF9_CAN2); + set_gpio_alternate(GPIOB, 6, GPIO_AF9_CAN2); + } else { + // B5,B6: disable normal CAN2 mode + set_gpio_mode(GPIOB, 5, MODE_INPUT); + set_gpio_mode(GPIOB, 6, MODE_INPUT); + + // B12,B13: OBD mode + set_gpio_alternate(GPIOB, 12, GPIO_AF9_CAN2); + set_gpio_alternate(GPIOB, 13, GPIO_AF9_CAN2); + } + break; + default: + puts("Tried to set unsupported CAN mode: "); puth(mode); puts("\n"); + break; + } +} + +void black_usb_power_mode_tick(uint64_t tcnt){ + UNUSED(tcnt); + // Not applicable +} + +bool black_check_ignition(void){ + // ignition is checked through harness + return harness_check_ignition(); +} + +void black_init(void) { + common_init_gpio(); + + // A8,A15: normal CAN3 mode + set_gpio_alternate(GPIOA, 8, GPIO_AF11_CAN3); + set_gpio_alternate(GPIOA, 15, GPIO_AF11_CAN3); + + // C0: OBD_SBU1 (orientation detection) + // C3: OBD_SBU2 (orientation detection) + set_gpio_mode(GPIOC, 0, MODE_ANALOG); + set_gpio_mode(GPIOC, 3, MODE_ANALOG); + + // C10: OBD_SBU1_RELAY (harness relay driving output) + // C11: OBD_SBU2_RELAY (harness relay driving output) + set_gpio_mode(GPIOC, 10, MODE_OUTPUT); + set_gpio_mode(GPIOC, 11, MODE_OUTPUT); + set_gpio_output_type(GPIOC, 10, OUTPUT_TYPE_OPEN_DRAIN); + set_gpio_output_type(GPIOC, 11, OUTPUT_TYPE_OPEN_DRAIN); + set_gpio_output(GPIOC, 10, 1); + set_gpio_output(GPIOC, 11, 1); + + // C8: FAN aka TIM3_CH3 + set_gpio_alternate(GPIOC, 8, GPIO_AF2_TIM3); + + // C12: GPS load switch. Turn on permanently for now + set_gpio_output(GPIOC, 12, true); + //set_gpio_output(GPIOC, 12, false); //TODO: stupid inverted switch on prototype + + // Initialize harness + harness_init(); + + // Enable CAN transcievers + black_enable_can_transcievers(true); + + // Disable LEDs + black_set_led(LED_RED, false); + black_set_led(LED_GREEN, false); + black_set_led(LED_BLUE, false); + + // Set normal CAN mode + black_set_can_mode(CAN_MODE_NORMAL); + + // flip CAN0 and CAN2 if we are flipped + if (car_harness_status == HARNESS_STATUS_NORMAL) { + can_flip_buses(0, 2); + } + + // init multiplexer + can_set_obd(car_harness_status, false); +} + +const harness_configuration black_harness_config = { + .has_harness = true, + .GPIO_SBU1 = GPIOC, + .GPIO_SBU2 = GPIOC, + .GPIO_relay_normal = GPIOC, + .GPIO_relay_flipped = GPIOC, + .pin_SBU1 = 0, + .pin_SBU2 = 3, + .pin_relay_normal = 10, + .pin_relay_flipped = 11, + .adc_channel_SBU1 = 10, + .adc_channel_SBU2 = 13 +}; + +const board board_black = { + .board_type = "Black", + .harness_config = &black_harness_config, + .init = black_init, + .enable_can_transciever = black_enable_can_transciever, + .enable_can_transcievers = black_enable_can_transcievers, + .set_led = black_set_led, + .set_usb_power_mode = black_set_usb_power_mode, + .set_esp_gps_mode = black_set_esp_gps_mode, + .set_can_mode = black_set_can_mode, + .usb_power_mode_tick = black_usb_power_mode_tick, + .check_ignition = black_check_ignition +}; \ No newline at end of file diff --git a/board/boards/common.h b/board/boards/common.h new file mode 100644 index 00000000000000..d176e4eaf561a0 --- /dev/null +++ b/board/boards/common.h @@ -0,0 +1,82 @@ +#ifdef STM32F4 + #include "stm32f4xx_hal_gpio_ex.h" +#else + #include "stm32f2xx_hal_gpio_ex.h" +#endif + +// Common GPIO initialization +void common_init_gpio(void){ + // TODO: Is this block actually doing something??? + // pull low to hold ESP in reset?? + // enable OTG out tied to ground + GPIOA->ODR = 0; + GPIOB->ODR = 0; + GPIOA->PUPDR = 0; + GPIOB->AFR[0] = 0; + GPIOB->AFR[1] = 0; + + // C2: Voltage sense line + set_gpio_mode(GPIOC, 2, MODE_ANALOG); + + // 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; + + // A9,A10: USART 1 for talking to the ESP / GPS + set_gpio_alternate(GPIOA, 9, GPIO_AF7_USART1); + set_gpio_alternate(GPIOA, 10, GPIO_AF7_USART1); + + // B8,B9: CAN 1 + #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 +} + +// Peripheral initialization +void peripherals_init(void){ + // 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_TIM2EN; // main counter + RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // slow loop and pedal + RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; // gmlan_alt + //RCC->APB1ENR |= RCC_APB1ENR_TIM5EN; + //RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; + 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; + RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; +} + +// Detection with internal pullup +#define PULL_EFFECTIVE_DELAY 10 +bool detect_with_pull(GPIO_TypeDef *GPIO, int pin, int mode) { + set_gpio_mode(GPIO, pin, MODE_INPUT); + set_gpio_pullup(GPIO, pin, mode); + for (volatile int i=0; i= CLICKS) { + if (!is_enumerated) { + puts("USBP: didn't enumerate, switching to CDP mode\n"); + // switch to CDP + white_set_usb_power_mode(USB_POWER_CDP); + marker = tcnt; + } + } + // keep resetting the timer if it's enumerated + if (is_enumerated) { + marker = tcnt; + } + break; + case USB_POWER_CDP: + // On the EON, if we get into CDP mode we stay here. No need to go to DCP. + #ifndef EON + // been CLICKS clicks since we switched to CDP + if ((tcnt-marker) >= CLICKS) { + // measure current draw, if positive and no enumeration, switch to DCP + if (!is_enumerated && (current < CURRENT_THRESHOLD)) { + puts("USBP: no enumeration with current draw, switching to DCP mode\n"); + white_set_usb_power_mode(USB_POWER_DCP); + marker = tcnt; + } + } + // keep resetting the timer if there's no current draw in CDP + if (current >= CURRENT_THRESHOLD) { + marker = tcnt; + } + #endif + break; + case USB_POWER_DCP: + // been at least CLICKS clicks since we switched to DCP + if ((tcnt-marker) >= CLICKS) { + // if no current draw, switch back to CDP + if (current >= CURRENT_THRESHOLD) { + puts("USBP: no current draw, switching back to CDP mode\n"); + white_set_usb_power_mode(USB_POWER_CDP); + marker = tcnt; + } + } + // keep resetting the timer if there's current draw in DCP + if (current < CURRENT_THRESHOLD) { + marker = tcnt; + } + break; + default: + puts("USB power mode invalid\n"); // set_usb_power_mode prevents assigning invalid values + break; + } + #else + UNUSED(tcnt); + #endif +} + +bool white_check_ignition(void){ + // ignition is on PA1 + return !get_gpio_input(GPIOA, 1); +} + +void white_init(void) { + common_init_gpio(); + + // C3: current sense + set_gpio_mode(GPIOC, 3, MODE_ANALOG); + + // A1: started_alt + 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); + + // A4, A5, A6, A7: 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); + + // Set USB power mode + white_set_usb_power_mode(USB_POWER_CLIENT); + + // B12: GMLAN, ignition sense, pull up + set_gpio_pullup(GPIOB, 12, PULL_UP); + + /* GMLAN mode pins: + M0(B15) M1(B14) mode + ======================= + 0 0 sleep + 1 0 100kbit + 0 1 high voltage wakeup + 1 1 33kbit (normal) + */ + set_gpio_output(GPIOB, 14, 1); + set_gpio_output(GPIOB, 15, 1); + + // B7: K-line enable + set_gpio_output(GPIOB, 7, 1); + + // C12, D2: Setup K-line (UART5) + 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 (USART3) + set_gpio_alternate(GPIOC, 10, GPIO_AF7_USART3); + set_gpio_alternate(GPIOC, 11, GPIO_AF7_USART3); + set_gpio_pullup(GPIOC, 11, PULL_UP); + + // Enable CAN transcievers + white_enable_can_transcievers(true); + + // Disable LEDs + white_set_led(LED_RED, false); + white_set_led(LED_GREEN, false); + white_set_led(LED_BLUE, false); + + // Set normal CAN mode + white_set_can_mode(CAN_MODE_NORMAL); +} + +const harness_configuration white_harness_config = { + .has_harness = false +}; + +const board board_white = { + .board_type = "White", + .harness_config = &white_harness_config, + .init = white_init, + .enable_can_transciever = white_enable_can_transciever, + .enable_can_transcievers = white_enable_can_transcievers, + .set_led = white_set_led, + .set_usb_power_mode = white_set_usb_power_mode, + .set_esp_gps_mode = white_set_esp_gps_mode, + .set_can_mode = white_set_can_mode, + .usb_power_mode_tick = white_usb_power_mode_tick, + .check_ignition = white_check_ignition +}; \ No newline at end of file diff --git a/board/bootstub.c b/board/bootstub.c index 799c39d059360c..9644326d4d0253 100644 --- a/board/bootstub.c +++ b/board/bootstub.c @@ -12,20 +12,29 @@ #include "stm32f2xx_hal_gpio_ex.h" #endif -// default since there's no serial -void puts(const char *a) { - UNUSED(a); -} - -void puth(unsigned int i) { - UNUSED(i); -} - +// ******************** Prototypes ******************** +void puts(const char *a){ UNUSED(a); } +void puth(unsigned int i){ UNUSED(i); } +void puth2(unsigned int i){ UNUSED(i); } +typedef struct board board; +typedef struct harness_configuration harness_configuration; +// No CAN support on bootloader +void can_flip_buses(uint8_t bus1, uint8_t bus2){UNUSED(bus1); UNUSED(bus2);} +void can_set_obd(int harness_orientation, bool obd){UNUSED(harness_orientation); UNUSED(obd);} + +// ********************* Globals ********************** +int hw_type = 0; +const board *current_board; + +// ********************* Includes ********************* #include "libc.h" #include "provision.h" #include "drivers/clock.h" #include "drivers/llgpio.h" + +#include "board.h" + #include "gpio.h" #include "drivers/spi.h" @@ -56,11 +65,10 @@ extern void *_app_start[]; int main(void) { __disable_irq(); clock_init(); - detect(); + detect_configuration(); + detect_board_type(); - if (revision == PANDA_REV_C) { - set_usb_power_mode(USB_POWER_CLIENT); - } + current_board->set_usb_power_mode(USB_POWER_CLIENT); if (enter_bootloader_mode == ENTER_SOFTLOADER_MAGIC) { enter_bootloader_mode = 0; diff --git a/board/build.mk b/board/build.mk index af2bffeb0a4616..acac03095b334d 100644 --- a/board/build.mk +++ b/board/build.mk @@ -68,7 +68,7 @@ obj/$(PROJ_NAME).bin: obj/$(STARTUP_FILE).o obj/main.$(PROJ_NAME).o $(OBJCOPY) -v -O binary obj/$(PROJ_NAME).elf obj/code.bin SETLEN=1 ../crypto/sign.py obj/code.bin $@ $(CERT) @BINSIZE=$$(du -b "obj/$(PROJ_NAME).bin" | cut -f 1) ; \ - if [ $$BINSIZE -ge 32768 ]; then echo "ERROR obj/$(PROJ_NAME).bin is too big!"; exit 1; fi; + if [ $$BINSIZE -ge 49152 ]; then echo "ERROR obj/$(PROJ_NAME).bin is too big!"; exit 1; fi; obj/bootstub.$(PROJ_NAME).bin: obj/$(STARTUP_FILE).o obj/bootstub.$(PROJ_NAME).o obj/sha.$(PROJ_NAME).o obj/rsa.$(PROJ_NAME).o $(CC) $(CFLAGS) -o obj/bootstub.$(PROJ_NAME).elf $^ diff --git a/board/drivers/can.h b/board/drivers/can.h index 3db2110512fa70..2d77281346332c 100644 --- a/board/drivers/can.h +++ b/board/drivers/can.h @@ -33,7 +33,6 @@ bool can_pop(can_ring *q, CAN_FIFOMailBox_TypeDef *elem); // end API #define ALL_CAN_SILENT 0xFF -#define ALL_CAN_BUT_MAIN_SILENT 0xFE #define ALL_CAN_LIVE 0 int can_live = 0, pending_can_live = 0, can_loopback = 0, can_silent = ALL_CAN_SILENT; @@ -149,7 +148,6 @@ void can_set_speed(uint8_t can_number) { void can_init(uint8_t can_number) { if (can_number != 0xffU) { CAN_TypeDef *CAN = CANIF_FROM_CAN_NUM(can_number); - set_can_enable(CAN, 1); can_set_speed(can_number); llcan_init(CAN); @@ -165,45 +163,86 @@ void can_init_all(void) { } } +void can_flip_buses(uint8_t bus1, uint8_t bus2){ + bus_lookup[bus1] = bus2; + bus_lookup[bus2] = bus1; + can_num_lookup[bus1] = bus2; + can_num_lookup[bus2] = bus1; +} + +// TODO: Cleanup with new abstraction void can_set_gmlan(uint8_t bus) { + if(hw_type != HW_TYPE_BLACK_PANDA){ + // first, disable GMLAN on prev bus + uint8_t prev_bus = can_num_lookup[3]; + if (bus != prev_bus) { + switch (prev_bus) { + case 1: + case 2: + puts("Disable GMLAN on CAN"); + puth(prev_bus + 1U); + puts("\n"); + current_board->set_can_mode(CAN_MODE_NORMAL); + bus_lookup[prev_bus] = prev_bus; + can_num_lookup[prev_bus] = prev_bus; + can_num_lookup[3] = -1; + can_init(prev_bus); + break; + default: + // GMLAN was not set on either BUS 1 or 2 + break; + } + } - // first, disable GMLAN on prev bus - uint8_t prev_bus = can_num_lookup[3]; - if (bus != prev_bus) { - switch (prev_bus) { + // now enable GMLAN on the new bus + switch (bus) { case 1: case 2: - puts("Disable GMLAN on CAN"); - puth(prev_bus + 1U); + puts("Enable GMLAN on CAN"); + puth(bus + 1U); puts("\n"); - set_can_mode(prev_bus, 0); - bus_lookup[prev_bus] = prev_bus; - can_num_lookup[prev_bus] = prev_bus; - can_num_lookup[3] = -1; - can_init(prev_bus); + current_board->set_can_mode((bus == 1U) ? CAN_MODE_GMLAN_CAN2 : CAN_MODE_GMLAN_CAN3); + bus_lookup[bus] = 3; + can_num_lookup[bus] = -1; + can_num_lookup[3] = bus; + can_init(bus); + break; + case 0xFF: //-1 unsigned break; default: - // GMLAN was not set on either BUS 1 or 2 + puts("GMLAN can only be set on CAN2 or CAN3\n"); break; } + } else { + puts("GMLAN not available on black panda\n"); } +} - // now enable GMLAN on the new bus - switch (bus) { - case 1: - case 2: - puts("Enable GMLAN on CAN"); - puth(bus + 1U); - puts("\n"); - set_can_mode(bus, 1); - bus_lookup[bus] = 3; - can_num_lookup[bus] = -1; - can_num_lookup[3] = bus; - can_init(bus); - break; - default: - puts("GMLAN can only be set on CAN2 or CAN3"); - break; +// TODO: remove +void can_set_obd(uint8_t harness_orientation, bool obd){ + if(obd){ + puts("setting CAN2 to be OBD\n"); + } else { + puts("setting CAN2 to be normal\n"); + } + if(hw_type == HW_TYPE_BLACK_PANDA){ + if(obd != (bool)(harness_orientation == HARNESS_STATUS_NORMAL)){ + // B5,B6: disable normal mode + set_gpio_mode(GPIOB, 5, MODE_INPUT); + set_gpio_mode(GPIOB, 6, MODE_INPUT); + // B12,B13: CAN2 mode + set_gpio_alternate(GPIOB, 12, GPIO_AF9_CAN2); + set_gpio_alternate(GPIOB, 13, GPIO_AF9_CAN2); + } else { + // B5,B6: CAN2 mode + set_gpio_alternate(GPIOB, 5, GPIO_AF9_CAN2); + set_gpio_alternate(GPIOB, 6, GPIO_AF9_CAN2); + // B12,B13: disable normal mode + set_gpio_mode(GPIOB, 12, MODE_INPUT); + set_gpio_mode(GPIOB, 13, MODE_INPUT); + } + } else { + puts("OBD CAN not available on non-black panda\n"); } } @@ -326,7 +365,7 @@ void can_rx(uint8_t can_number) { safety_rx_hook(&to_push); - set_led(LED_BLUE, 1); + current_board->set_led(LED_BLUE, true); can_send_errs += !can_push(&can_rx_q, &to_push); // next diff --git a/board/drivers/harness.h b/board/drivers/harness.h new file mode 100644 index 00000000000000..17520a4bab8055 --- /dev/null +++ b/board/drivers/harness.h @@ -0,0 +1,130 @@ +uint8_t car_harness_status = 0U; +#define HARNESS_STATUS_NC 0U +#define HARNESS_STATUS_NORMAL 1U +#define HARNESS_STATUS_FLIPPED 2U + +// Threshold voltage (mV) for either of the SBUs to be below before deciding harness is connected +#define HARNESS_CONNECTED_THRESHOLD 2500U + +struct harness_configuration { + const bool has_harness; + GPIO_TypeDef *GPIO_SBU1; + GPIO_TypeDef *GPIO_SBU2; + GPIO_TypeDef *GPIO_relay_normal; + GPIO_TypeDef *GPIO_relay_flipped; + uint8_t pin_SBU1; + uint8_t pin_SBU2; + uint8_t pin_relay_normal; + uint8_t pin_relay_flipped; + uint8_t adc_channel_SBU1; + uint8_t adc_channel_SBU2; +}; + +// this function will be the API for tici +void set_intercept_relay(bool intercept) { + if (car_harness_status != HARNESS_STATUS_NC) { + if (intercept) { + puts("switching harness to intercept (relay on)\n"); + } else { + puts("switching harness to passthrough (relay off)\n"); + } + + if(car_harness_status == HARNESS_STATUS_NORMAL){ + set_gpio_output(current_board->harness_config->GPIO_relay_normal, current_board->harness_config->pin_relay_normal, !intercept); + } else { + set_gpio_output(current_board->harness_config->GPIO_relay_flipped, current_board->harness_config->pin_relay_flipped, !intercept); + } + } +} + +bool harness_check_ignition(void) { + bool ret = false; + switch(car_harness_status){ + case HARNESS_STATUS_NORMAL: + ret = !get_gpio_input(current_board->harness_config->GPIO_SBU2, current_board->harness_config->pin_SBU2); + break; + case HARNESS_STATUS_FLIPPED: + ret = !get_gpio_input(current_board->harness_config->GPIO_SBU1, current_board->harness_config->pin_SBU1); + break; + default: + break; + } + return ret; +} + +// TODO: refactor to use harness config +void harness_setup_ignition_interrupts(void){ + if(car_harness_status == HARNESS_STATUS_NORMAL){ + SYSCFG->EXTICR[0] = SYSCFG_EXTICR1_EXTI3_PC; + EXTI->IMR |= (1U << 3); + EXTI->RTSR |= (1U << 3); + EXTI->FTSR |= (1U << 3); + puts("setup interrupts: normal\n"); + } else if(car_harness_status == HARNESS_STATUS_FLIPPED) { + SYSCFG->EXTICR[0] = SYSCFG_EXTICR1_EXTI0_PC; + EXTI->IMR |= (1U << 0); + EXTI->RTSR |= (1U << 0); + EXTI->FTSR |= (1U << 0); + NVIC_EnableIRQ(EXTI1_IRQn); + puts("setup interrupts: flipped\n"); + } else { + puts("tried to setup ignition interrupts without harness connected\n"); + } + NVIC_EnableIRQ(EXTI0_IRQn); + NVIC_EnableIRQ(EXTI3_IRQn); +} + +uint8_t harness_detect_orientation(void) { + uint8_t ret = HARNESS_STATUS_NC; + + #ifndef BOOTSTUB + uint32_t sbu1_voltage = adc_get(current_board->harness_config->adc_channel_SBU1); + uint32_t sbu2_voltage = adc_get(current_board->harness_config->adc_channel_SBU2); + + // Detect connection and orientation + if((sbu1_voltage < HARNESS_CONNECTED_THRESHOLD) || (sbu2_voltage < HARNESS_CONNECTED_THRESHOLD)){ + if (sbu1_voltage < sbu2_voltage) { + // orientation normal + ret = HARNESS_STATUS_NORMAL; + } else { + // orientation flipped + ret = HARNESS_STATUS_FLIPPED; + } + } + #endif + + return ret; +} + +void harness_init(void) { + // delay such that the connection is fully made before trying orientation detection + current_board->set_led(LED_BLUE, true); + delay(10000000); + current_board->set_led(LED_BLUE, false); + + // try to detect orientation + uint8_t ret = harness_detect_orientation(); + if (ret != HARNESS_STATUS_NC) { + puts("detected car harness with orientation "); puth2(ret); puts("\n"); + car_harness_status = ret; + + // set the SBU lines to be inputs before using the relay. The lines are not 5V tolerant in ADC mode! + set_gpio_mode(current_board->harness_config->GPIO_SBU1, current_board->harness_config->pin_SBU1, MODE_INPUT); + set_gpio_mode(current_board->harness_config->GPIO_SBU2, current_board->harness_config->pin_SBU2, MODE_INPUT); + + // now we have orientation, set pin ignition detection + if(car_harness_status == HARNESS_STATUS_NORMAL){ + set_gpio_mode(current_board->harness_config->GPIO_SBU2, current_board->harness_config->pin_SBU2, MODE_INPUT); + } else { + set_gpio_mode(current_board->harness_config->GPIO_SBU1, current_board->harness_config->pin_SBU1, MODE_INPUT); + } + + // keep busses connected by default + set_intercept_relay(false); + + // setup ignition interrupts + harness_setup_ignition_interrupts(); + } else { + puts("failed to detect car harness!\n"); + } +} \ No newline at end of file diff --git a/board/drivers/llgpio.h b/board/drivers/llgpio.h index f84ee7f8aed90a..a89c8a8e2d5dcf 100644 --- a/board/drivers/llgpio.h +++ b/board/drivers/llgpio.h @@ -7,6 +7,9 @@ #define PULL_UP 1 #define PULL_DOWN 2 +#define OUTPUT_TYPE_PUSH_PULL 0U +#define OUTPUT_TYPE_OPEN_DRAIN 1U + void set_gpio_mode(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int mode) { uint32_t tmp = GPIO->MODER; tmp &= ~(3U << (pin * 2U)); @@ -23,6 +26,14 @@ void set_gpio_output(GPIO_TypeDef *GPIO, unsigned int pin, bool enabled) { set_gpio_mode(GPIO, pin, MODE_OUTPUT); } +void set_gpio_output_type(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int output_type){ + if(output_type == OUTPUT_TYPE_OPEN_DRAIN) { + GPIO->OTYPER |= (1U << pin); + } else { + GPIO->OTYPER &= ~(1U << pin); + } +} + void set_gpio_alternate(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int mode) { uint32_t tmp = GPIO->AFR[pin >> 3U]; tmp &= ~(0xFU << ((pin & 7U) * 4U)); diff --git a/board/gpio.h b/board/gpio.h index e1936527e2819c..1acf0288ad8d1f 100644 --- a/board/gpio.h +++ b/board/gpio.h @@ -1,383 +1,4 @@ -// this is last place with ifdef PANDA - -#ifdef STM32F4 - #include "stm32f4xx_hal_gpio_ex.h" -#else - #include "stm32f2xx_hal_gpio_ex.h" -#endif - -// ********************* dynamic configuration detection ********************* - -#define PANDA_REV_AB 0 -#define PANDA_REV_C 1 - -#define PULL_EFFECTIVE_DELAY 10 - -void puts(const char *a); - -bool has_external_debug_serial = 0; -bool is_giant_panda = 0; -bool is_entering_bootmode = 0; -int revision = PANDA_REV_AB; -bool is_grey_panda = 0; - -bool detect_with_pull(GPIO_TypeDef *GPIO, int pin, int mode) { - set_gpio_mode(GPIO, pin, MODE_INPUT); - set_gpio_pullup(GPIO, pin, mode); - for (volatile int i=0; iAHB1ENR |= 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_TIM2EN; // main counter - RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // slow loop and pedal - RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; // gmlan_alt - //RCC->APB1ENR |= RCC_APB1ENR_TIM5EN; - //RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; - 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; - RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; -} - -// ********************* setters ********************* - -void set_can_enable(CAN_TypeDef *CAN_obj, bool enabled) { - // enable CAN busses - if (CAN_obj == CAN1) { - #ifdef PANDA - // CAN1_EN - set_gpio_output(GPIOC, 1, !enabled); - #else - #ifdef PEDAL - // CAN1_EN (not flipped) - set_gpio_output(GPIOB, 3, !enabled); - #else - // CAN1_EN - set_gpio_output(GPIOB, 3, enabled); - #endif - #endif - } else if (CAN_obj == 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_obj == CAN3) { - // CAN3_EN - set_gpio_output(GPIOA, 0, !enabled); - #endif - } else { - puts("Invalid CAN: enabling failed\n"); - } -} - -#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) { - #ifdef PANDA - set_gpio_output(GPIOC, led_num, !on); - #else - set_gpio_output(GPIOB, led_num, !on); - #endif - } -} - -void set_can_mode(int can, bool use_gmlan) { - // connects to CAN2 xcvr or GMLAN xcvr - if (use_gmlan) { - if (can == 1) { - // 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); -#ifdef CAN3 - } else if (can == 2) { - // 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); -#endif - } else { - puts("Invalid CAN: mode setting failed\n"); - } - } else { - if (can == 1) { - // 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); -#ifdef CAN3 - } else if (can == 2) { - // 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); -#endif - } else { - puts("Invalid CAN: mode setting failed\n"); - } - } -} - -#define USB_POWER_NONE 0 -#define USB_POWER_CLIENT 1 -#define USB_POWER_CDP 2 -#define USB_POWER_DCP 3 - -int usb_power_mode = USB_POWER_NONE; - -void set_usb_power_mode(int mode) { - bool valid_mode = true; - switch (mode) { - case USB_POWER_CLIENT: - // B2,A13: set client mode - set_gpio_output(GPIOB, 2, 0); - set_gpio_output(GPIOA, 13, 1); - break; - case USB_POWER_CDP: - // B2,A13: set CDP mode - set_gpio_output(GPIOB, 2, 1); - set_gpio_output(GPIOA, 13, 1); - break; - case USB_POWER_DCP: - // B2,A13: set DCP mode on the charger (breaks USB!) - set_gpio_output(GPIOB, 2, 0); - set_gpio_output(GPIOA, 13, 0); - break; - default: - valid_mode = false; - puts("Invalid usb power mode\n"); - break; - } - - if (valid_mode) { - usb_power_mode = mode; - } -} - -#define ESP_DISABLED 0 -#define ESP_ENABLED 1 -#define ESP_BOOTMODE 2 - -void set_esp_mode(int mode) { - switch (mode) { - case ESP_DISABLED: - // ESP OFF - set_gpio_output(GPIOC, 14, 0); - set_gpio_output(GPIOC, 5, 0); - break; - case ESP_ENABLED: - // ESP ON - set_gpio_output(GPIOC, 14, 1); - set_gpio_output(GPIOC, 5, 1); - break; - case ESP_BOOTMODE: - set_gpio_output(GPIOC, 14, 1); - set_gpio_output(GPIOC, 5, 0); - break; - default: - puts("Invalid esp mode\n"); - break; - } -} - -// ********************* big init function ********************* - -// board specific -void gpio_init(void) { - // 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); - -#ifdef PEDAL - // comma pedal has inputs on C0 and C1 - set_gpio_mode(GPIOC, 0, MODE_ANALOG); - set_gpio_mode(GPIOC, 1, MODE_ANALOG); - // DAC outputs on A4 and A5 - // apparently they don't need GPIO setup -#endif - - // 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 -#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 - set_can_enable(CAN1, 1); - - // B5,B6: CAN 2 - set_can_mode(1, 0); - set_can_enable(CAN2, 1); - - // A8,A15: CAN 3 - #ifdef CAN3 - set_can_mode(2, 0); - set_can_enable(CAN3, 1); - #endif - - /* GMLAN mode pins: - M0(B15) M1(B14) mode - ======================= - 0 0 sleep - 1 0 100kbit - 0 1 high voltage wakeup - 1 1 33kbit (normal) - */ - - // put gmlan transceiver in normal mode - set_gpio_output(GPIOB, 14, 1); - set_gpio_output(GPIOB, 15, 1); - - #ifdef PANDA - // K-line enable moved from B4->B7 to make room for GMLAN on CAN3 - set_gpio_output(GPIOB, 7, 1); // REV C - - // 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 - - set_usb_power_mode(USB_POWER_CLIENT); -} - -// ********************* early bringup ********************* - +// Early bringup #define ENTER_BOOTLOADER_MAGIC 0xdeadbeef #define ENTER_SOFTLOADER_MAGIC 0xdeadc0de #define BOOT_NORMAL 0xdeadb111 @@ -429,29 +50,25 @@ void early(void) { GPIOA->ODR = 0; GPIOB->ODR = 0; GPIOC->ODR = 0; GPIOA->PUPDR = 0; GPIOB->PUPDR = 0; GPIOC->PUPDR = 0; - detect(); + detect_configuration(); + detect_board_type(); #ifdef PANDA // enable the ESP, disable ESP boot mode - // unless we are on a giant panda, then there's no ESP // dont disable on grey panda - if (is_giant_panda) { - set_esp_mode(ESP_DISABLED); - } else { - set_esp_mode(ESP_ENABLED); - } + current_board->set_esp_gps_mode(ESP_GPS_ENABLED); #endif if (enter_bootloader_mode == ENTER_BOOTLOADER_MAGIC) { #ifdef PANDA - set_esp_mode(ESP_DISABLED); + current_board->set_esp_gps_mode(ESP_GPS_DISABLED); #endif - set_led(LED_GREEN, 1); + current_board->set_led(LED_GREEN, 1); jump_to_bootloader(); } if (is_entering_bootmode) { enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC; } -} +} \ No newline at end of file diff --git a/board/main.c b/board/main.c index f962169123d7d2..08d05bacdeeeb7 100644 --- a/board/main.c +++ b/board/main.c @@ -1,34 +1,39 @@ -//#define EON +//#define EON +//#define PANDA +// ********************* Includes ********************* #include "config.h" #include "obj/gitversion.h" -// ********************* includes ********************* - - #include "libc.h" #include "provision.h" +#include "main_declarations.h" + #include "drivers/llcan.h" #include "drivers/llgpio.h" -#include "gpio.h" +#include "drivers/adc.h" + +#include "board.h" #include "drivers/uart.h" -#include "drivers/adc.h" #include "drivers/usb.h" #include "drivers/gmlan_alt.h" #include "drivers/timer.h" #include "drivers/clock.h" +#include "gpio.h" + #ifndef EON #include "drivers/spi.h" #endif #include "power_saving.h" #include "safety.h" + #include "drivers/can.h" -// ********************* serial debugging ********************* +// ********************* Serial debugging ********************* void debug_ring_callback(uart_ring *ring) { char rcv; @@ -49,30 +54,23 @@ void debug_ring_callback(uart_ring *ring) { // enable CDP mode if (rcv == 'C') { puts("switching USB to CDP mode\n"); - set_usb_power_mode(USB_POWER_CDP); + current_board->set_usb_power_mode(USB_POWER_CDP); } if (rcv == 'c') { puts("switching USB to client mode\n"); - set_usb_power_mode(USB_POWER_CLIENT); + current_board->set_usb_power_mode(USB_POWER_CLIENT); } if (rcv == 'D') { puts("switching USB to DCP mode\n"); - set_usb_power_mode(USB_POWER_DCP); + current_board->set_usb_power_mode(USB_POWER_DCP); } } } // ***************************** started logic ***************************** - -bool is_gpio_started(void) { - // ignition is on PA1 - return (GPIOA->IDR & (1U << 1)) == 0; -} - -// cppcheck-suppress unusedFunction ; used in headers not included in cppcheck -void EXTI1_IRQHandler(void) { - volatile unsigned int pr = EXTI->PR & (1U << 1); - if ((pr & (1U << 1)) != 0U) { +void started_interrupt_handler(uint8_t interrupt_line) { + volatile unsigned int pr = EXTI->PR & (1U << interrupt_line); + if ((pr & (1U << interrupt_line)) != 0U) { #ifdef DEBUG puts("got started interrupt\n"); #endif @@ -81,10 +79,25 @@ void EXTI1_IRQHandler(void) { delay(100000); // set power savings mode here - int power_save_state = is_gpio_started() ? POWER_SAVE_STATUS_DISABLED : POWER_SAVE_STATUS_ENABLED; + int power_save_state = current_board->check_ignition() ? POWER_SAVE_STATUS_DISABLED : POWER_SAVE_STATUS_ENABLED; set_power_save_state(power_save_state); - EXTI->PR = (1U << 1); } + EXTI->PR = (1U << interrupt_line); +} + +// cppcheck-suppress unusedFunction ; used in headers not included in cppcheck +void EXTI0_IRQHandler(void) { + started_interrupt_handler(0); +} + +// cppcheck-suppress unusedFunction ; used in headers not included in cppcheck +void EXTI1_IRQHandler(void) { + started_interrupt_handler(1); +} + +// cppcheck-suppress unusedFunction ; used in headers not included in cppcheck +void EXTI3_IRQHandler(void) { + started_interrupt_handler(3); } void started_interrupt_init(void) { @@ -95,18 +108,64 @@ void started_interrupt_init(void) { NVIC_EnableIRQ(EXTI1_IRQn); } +// ****************************** safety mode ****************************** + +// this is the only way to leave silent mode +void set_safety_mode(uint16_t mode, int16_t param) { + int err = safety_set_mode(mode, param); + if (err == -1) { + puts("Error: safety set mode failed\n"); + } else { + if (mode == SAFETY_NOOUTPUT) { + can_silent = ALL_CAN_SILENT; + } else { + can_silent = ALL_CAN_LIVE; + } + + switch (mode) { + case SAFETY_NOOUTPUT: + set_intercept_relay(false); + if(hw_type == HW_TYPE_BLACK_PANDA){ + current_board->set_can_mode(CAN_MODE_NORMAL); + } + break; + case SAFETY_ELM327: + set_intercept_relay(false); + if(hw_type == HW_TYPE_BLACK_PANDA){ + current_board->set_can_mode(CAN_MODE_OBD_CAN2); + } + break; + default: + set_intercept_relay(true); + if(hw_type == HW_TYPE_BLACK_PANDA){ + current_board->set_can_mode(CAN_MODE_NORMAL); + } + break; + } + if (safety_ignition_hook() != -1) { + // if the ignition hook depends on something other than the started GPIO + // we have to disable power savings (fix for GM and Tesla) + set_power_save_state(POWER_SAVE_STATUS_DISABLED); + } else { + // power mode is already POWER_SAVE_STATUS_DISABLED and CAN TXs are active + } + can_init_all(); + } +} + // ***************************** USB port ***************************** int get_health_pkt(void *dat) { struct __attribute__((packed)) { uint32_t voltage_pkt; uint32_t current_pkt; - uint8_t started_pkt; - uint8_t controls_allowed_pkt; - uint8_t gas_interceptor_detected_pkt; uint32_t can_send_errs_pkt; uint32_t can_fwd_errs_pkt; uint32_t gmlan_send_errs_pkt; + uint8_t started_pkt; + uint8_t controls_allowed_pkt; + uint8_t gas_interceptor_detected_pkt; + uint8_t car_harness_status_pkt; } *health = dat; //Voltage will be measured in mv. 5000 = 5V @@ -121,11 +180,17 @@ int get_health_pkt(void *dat) { // Avoid needing floating point math health->voltage_pkt = (voltage * 8862U) / 1000U; - health->current_pkt = adc_get(ADCCHAN_CURRENT); + // No current sense on panda black + if(hw_type != HW_TYPE_BLACK_PANDA){ + health->current_pkt = adc_get(ADCCHAN_CURRENT); + } else { + health->current_pkt = 0; + } + int safety_ignition = safety_ignition_hook(); if (safety_ignition < 0) { //Use the GPIO pin to determine ignition - health->started_pkt = is_gpio_started(); + health->started_pkt = (uint8_t)(current_board->check_ignition()); } else { //Current safety hooks want to determine ignition (ex: GM) health->started_pkt = safety_ignition; @@ -136,7 +201,8 @@ int get_health_pkt(void *dat) { health->can_send_errs_pkt = can_send_errs; health->can_fwd_errs_pkt = can_fwd_errs; health->gmlan_send_errs_pkt = gmlan_send_errs; - + health->car_harness_status_pkt = car_harness_status; + return sizeof(*health); } @@ -183,8 +249,6 @@ void usb_cb_ep3_out(void *usbdata, int len, bool hardwired) { } } -bool is_enumerated = 0; - void usb_cb_enumeration_complete() { puts("USB enumeration complete\n"); is_enumerated = 1; @@ -203,9 +267,9 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) puts(" err: "); puth(can_err_cnt); puts("\n"); break; - // **** 0xc1: is grey panda + // **** 0xc1: get hardware type case 0xc1: - resp[0] = is_grey_panda; + resp[0] = hw_type; resp_len = 1; break; // **** 0xd0: fetch serial number @@ -258,73 +322,57 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) // **** 0xd9: set ESP power case 0xd9: if (setup->b.wValue.w == 1U) { - set_esp_mode(ESP_ENABLED); + current_board->set_esp_gps_mode(ESP_GPS_ENABLED); } else if (setup->b.wValue.w == 2U) { - set_esp_mode(ESP_BOOTMODE); + current_board->set_esp_gps_mode(ESP_GPS_BOOTMODE); } else { - set_esp_mode(ESP_DISABLED); + current_board->set_esp_gps_mode(ESP_GPS_DISABLED); } break; // **** 0xda: reset ESP, with optional boot mode case 0xda: - set_esp_mode(ESP_DISABLED); + current_board->set_esp_gps_mode(ESP_GPS_DISABLED); delay(1000000); if (setup->b.wValue.w == 1U) { - set_esp_mode(ESP_BOOTMODE); + current_board->set_esp_gps_mode(ESP_GPS_BOOTMODE); } else { - set_esp_mode(ESP_ENABLED); + current_board->set_esp_gps_mode(ESP_GPS_ENABLED); } delay(1000000); - set_esp_mode(ESP_ENABLED); + current_board->set_esp_gps_mode(ESP_GPS_ENABLED); break; - // **** 0xdb: set GMLAN multiplexing mode + // **** 0xdb: set GMLAN (white/grey) or OBD CAN (black) multiplexing mode case 0xdb: - if (setup->b.wValue.w == 1U) { - // GMLAN ON - if (setup->b.wIndex.w == 1U) { - can_set_gmlan(1); - } else if (setup->b.wIndex.w == 2U) { - can_set_gmlan(2); + if(hw_type == HW_TYPE_BLACK_PANDA){ + if (setup->b.wValue.w == 1U) { + // Enable OBD CAN + current_board->set_can_mode(CAN_MODE_OBD_CAN2); } else { - puts("Invalid bus num for GMLAN CAN set\n"); - } + // Disable OBD CAN + current_board->set_can_mode(CAN_MODE_NORMAL); + } } else { - can_set_gmlan(-1); + if (setup->b.wValue.w == 1U) { + // GMLAN ON + if (setup->b.wIndex.w == 1U) { + can_set_gmlan(1); + } else if (setup->b.wIndex.w == 2U) { + can_set_gmlan(2); + } else { + puts("Invalid bus num for GMLAN CAN set\n"); + } + } else { + can_set_gmlan(-1); + } } break; + // **** 0xdc: set safety mode case 0xdc: - // this is the only way to leave silent mode - // and it's blocked over WiFi - // Allow ELM security mode to be set over wifi. + // Blocked over WiFi. + // Allow NOOUTPUT and ELM security mode to be set over wifi. if (hardwired || (setup->b.wValue.w == SAFETY_NOOUTPUT) || (setup->b.wValue.w == SAFETY_ELM327)) { - int err = safety_set_mode(setup->b.wValue.w, (int16_t)setup->b.wIndex.w); - if (err == -1) { - puts("Error: safety set mode failed\n"); - } else { - #ifndef EON - // always LIVE on EON - switch (setup->b.wValue.w) { - case SAFETY_NOOUTPUT: - can_silent = ALL_CAN_SILENT; - break; - case SAFETY_ELM327: - can_silent = ALL_CAN_BUT_MAIN_SILENT; - break; - default: - can_silent = ALL_CAN_LIVE; - break; - } - #endif - if (safety_ignition_hook() != -1) { - // if the ignition hook depends on something other than the started GPIO - // we have to disable power savings (fix for GM and Tesla) - set_power_save_state(POWER_SAVE_STATUS_DISABLED); - } else { - // power mode is already POWER_SAVE_STATUS_DISABLED and CAN TXs are active - } - can_init_all(); - } + set_safety_mode(setup->b.wValue.w, (uint16_t) setup->b.wIndex.w); } break; // **** 0xdd: enable can forwarding @@ -418,13 +466,13 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) case 0xe6: if (setup->b.wValue.w == 1U) { puts("user setting CDP mode\n"); - set_usb_power_mode(USB_POWER_CDP); + current_board->set_usb_power_mode(USB_POWER_CDP); } else if (setup->b.wValue.w == 2U) { puts("user setting DCP mode\n"); - set_usb_power_mode(USB_POWER_DCP); + current_board->set_usb_power_mode(USB_POWER_DCP); } else { puts("user setting CLIENT mode\n"); - set_usb_power_mode(USB_POWER_CLIENT); + current_board->set_usb_power_mode(USB_POWER_CLIENT); } break; // **** 0xf0: do k-line wValue pulse on uart2 for Acura @@ -482,6 +530,12 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) } break; } + // **** 0xf3: Heartbeat. Resets heartbeat counter. + case 0xf3: + { + heartbeat_counter = 0U; + break; + } default: puts("NO HANDLER "); puth(setup->b.bRequest); @@ -536,95 +590,51 @@ void __attribute__ ((noinline)) enable_fpu(void) { } uint64_t tcnt = 0; -uint64_t marker = 0; + +// go into NOOUTPUT when the EON does not send a heartbeat for this amount of seconds. +#define EON_HEARTBEAT_THRESHOLD 5U // called once per second // cppcheck-suppress unusedFunction ; used in headers not included in cppcheck void TIM3_IRQHandler(void) { - #define CURRENT_THRESHOLD 0xF00U - #define CLICKS 5U // 5 seconds to switch modes - if (TIM3->SR != 0) { can_live = pending_can_live; - //puth(usart1_dma); puts(" "); puth(DMA2_Stream5->M0AR); puts(" "); puth(DMA2_Stream5->NDTR); puts("\n"); + current_board->usb_power_mode_tick(tcnt); - uint32_t current = adc_get(ADCCHAN_CURRENT); - - switch (usb_power_mode) { - case USB_POWER_CLIENT: - if ((tcnt - marker) >= CLICKS) { - if (!is_enumerated) { - puts("USBP: didn't enumerate, switching to CDP mode\n"); - // switch to CDP - set_usb_power_mode(USB_POWER_CDP); - marker = tcnt; - } - } - // keep resetting the timer if it's enumerated - if (is_enumerated) { - marker = tcnt; - } - break; - case USB_POWER_CDP: - // On the EON, if we get into CDP mode we stay here. No need to go to DCP. - #ifndef EON - // been CLICKS clicks since we switched to CDP - if ((tcnt-marker) >= CLICKS) { - // measure current draw, if positive and no enumeration, switch to DCP - if (!is_enumerated && (current < CURRENT_THRESHOLD)) { - puts("USBP: no enumeration with current draw, switching to DCP mode\n"); - set_usb_power_mode(USB_POWER_DCP); - marker = tcnt; - } - } - // keep resetting the timer if there's no current draw in CDP - if (current >= CURRENT_THRESHOLD) { - marker = tcnt; - } - #endif - break; - case USB_POWER_DCP: - // been at least CLICKS clicks since we switched to DCP - if ((tcnt-marker) >= CLICKS) { - // if no current draw, switch back to CDP - if (current >= CURRENT_THRESHOLD) { - puts("USBP: no current draw, switching back to CDP mode\n"); - set_usb_power_mode(USB_POWER_CDP); - marker = tcnt; - } - } - // keep resetting the timer if there's current draw in DCP - if (current < CURRENT_THRESHOLD) { - marker = tcnt; - } - break; - default: - puts("USB power mode invalid\n"); // set_usb_power_mode prevents assigning invalid values - break; - } - - // ~0x9a = 500 ma - /*puth(current); - puts("\n");*/ + //puth(usart1_dma); puts(" "); puth(DMA2_Stream5->M0AR); puts(" "); puth(DMA2_Stream5->NDTR); puts("\n"); // reset this every 16th pass if ((tcnt & 0xFU) == 0U) { 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"); + //TODO: re-enable + //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 // set green LED to be controls allowed - set_led(LED_GREEN, controls_allowed); + current_board->set_led(LED_GREEN, controls_allowed); // turn off the blue LED, turned on by CAN // unless we are in power saving mode - set_led(LED_BLUE, (tcnt & 1U) && (power_save_status == POWER_SAVE_STATUS_ENABLED)); + current_board->set_led(LED_BLUE, (tcnt & 1U) && (power_save_status == POWER_SAVE_STATUS_ENABLED)); + + // increase heartbeat counter and cap it at the uint32 limit + if (heartbeat_counter < __UINT32_MAX__) { + heartbeat_counter += 1U; + } + + // check heartbeat counter if we are running EON code. If the heartbeat has been gone for a while, go to NOOUTPUT safety mode. + #ifdef EON + if (heartbeat_counter >= EON_HEARTBEAT_THRESHOLD) { + puts("EON hasn't sent a heartbeat for 0x"); puth(heartbeat_counter); puts(" seconds. Safety is set to NOOUTPUT mode.\n"); + set_safety_mode(SAFETY_NOOUTPUT, 0U); + } + #endif // on to the next one tcnt += 1U; @@ -638,26 +648,27 @@ int main(void) { // init early devices clock_init(); - periph_init(); - detect(); - + peripherals_init(); + detect_configuration(); + detect_board_type(); + adc_init(); + // print hello puts("\n\n\n************************ MAIN START ************************\n"); - // detect the revision and init the GPIOs - puts("config:\n"); - puts((revision == PANDA_REV_C) ? " panda rev c\n" : " panda rev a or b\n"); - puts(has_external_debug_serial ? " real serial\n" : " USB serial\n"); - puts(is_giant_panda ? " GIANTpanda detected\n" : " not GIANTpanda\n"); - puts(is_grey_panda ? " gray panda detected!\n" : " white panda\n"); - puts(is_entering_bootmode ? " ESP wants bootmode\n" : " no bootmode\n"); - - // non rev c panda are no longer supported - while (revision != PANDA_REV_C) { - // hang + // check for non-supported board types + if(hw_type == HW_TYPE_UNKNOWN){ + puts("Unsupported board type\n"); + while (1) { /* hang */ } } - gpio_init(); + puts("Config:\n"); + puts(" Board type: "); puts(current_board->board_type); puts("\n"); + puts(has_external_debug_serial ? " Real serial\n" : " USB serial\n"); + puts(is_entering_bootmode ? " ESP wants bootmode\n" : " No bootmode\n"); + + // init board + current_board->init(); // panda has an FPU, let's use it! enable_fpu(); @@ -669,18 +680,21 @@ int main(void) { uart_init(USART2, 115200); } - if (is_grey_panda) { + if (board_has_gps()) { uart_init(USART1, 9600); } else { // enable ESP uart uart_init(USART1, 115200); } - // enable LIN - uart_init(UART5, 10400); - UART5->CR2 |= USART_CR2_LINEN; - uart_init(USART3, 10400); - USART3->CR2 |= USART_CR2_LINEN; + // there is no LIN on panda black + if(hw_type != HW_TYPE_BLACK_PANDA){ + // enable LIN + uart_init(UART5, 10400); + UART5->CR2 |= USART_CR2_LINEN; + uart_init(USART3, 10400); + USART3->CR2 |= USART_CR2_LINEN; + } // init microsecond system timer // increments 1000000 times per second @@ -690,9 +704,6 @@ int main(void) { TIM2->EGR = TIM_EGR_UG; // use TIM2->CNT to read - // enable USB - usb_init(); - // default to silent mode to prevent issues with Ford // hardcode a specific safety mode if you want to force the panda to be in a specific mode int err = safety_set_mode(SAFETY_NOOUTPUT, 0); @@ -702,31 +713,27 @@ int main(void) { // if SAFETY_NOOUTPUT isn't succesfully set, we can't continue } } -#ifdef EON - // if we're on an EON, it's fine for CAN to be live for fingerprinting - can_silent = ALL_CAN_LIVE; -#else can_silent = ALL_CAN_SILENT; -#endif can_init_all(); - adc_init(); - #ifndef EON spi_init(); #endif #ifdef EON // have to save power - if (!is_grey_panda) { - set_esp_mode(ESP_DISABLED); + if (hw_type == HW_TYPE_WHITE_PANDA) { + current_board->set_esp_gps_mode(ESP_GPS_DISABLED); } // only enter power save after the first cycle - /*if (is_gpio_started()) { + /*if (current_board->check_ignition()) { set_power_save_state(POWER_SAVE_STATUS_ENABLED); }*/ - // interrupt on started line - started_interrupt_init(); + + if (hw_type != HW_TYPE_BLACK_PANDA) { + // interrupt on started line + started_interrupt_init(); + } #endif // 48mhz / 65536 ~= 732 / 732 = 1 @@ -736,6 +743,8 @@ int main(void) { #ifdef DEBUG puts("DEBUG ENABLED\n"); #endif + // enable USB (right before interrupts or enum can fail!) + usb_init(); puts("**** INTERRUPTS ON ****\n"); enable_interrupts(); @@ -751,9 +760,9 @@ int main(void) { for (int div_mode_loop = 0; div_mode_loop < div_mode; div_mode_loop++) { for (int fade = 0; fade < 1024; fade += 8) { for (int i = 0; i < (128/div_mode); i++) { - set_led(LED_RED, 1); + current_board->set_led(LED_RED, 1); if (fade < 512) { delay(fade); } else { delay(1024-fade); } - set_led(LED_RED, 0); + current_board->set_led(LED_RED, 0); if (fade < 512) { delay(512-fade); } else { delay(fade-512); } } } @@ -765,4 +774,3 @@ int main(void) { return 0; } - diff --git a/board/main_declarations.h b/board/main_declarations.h new file mode 100644 index 00000000000000..8929e9ac0e0cd9 --- /dev/null +++ b/board/main_declarations.h @@ -0,0 +1,14 @@ +// ******************** Prototypes ******************** +void puts(const char *a); +void puth(unsigned int i); +void puth2(unsigned int i); +typedef struct board board; +typedef struct harness_configuration harness_configuration; +void can_flip_buses(uint8_t bus1, uint8_t bus2); +void can_set_obd(uint8_t harness_orientation, bool obd); + +// ********************* Globals ********************** +uint8_t hw_type = 0; +const board *current_board; +bool is_enumerated = 0; +uint32_t heartbeat_counter = 0; \ No newline at end of file diff --git a/board/pedal/main.c b/board/pedal/main.c index 21a3a59fa638de..194370fa389ce1 100644 --- a/board/pedal/main.c +++ b/board/pedal/main.c @@ -1,14 +1,20 @@ +// ********************* Includes ********************* #include "../config.h" +#include "libc.h" + +#include "main_declarations.h" #include "drivers/llcan.h" #include "drivers/llgpio.h" -#include "drivers/clock.h" #include "drivers/adc.h" + +#include "board.h" + +#include "drivers/clock.h" #include "drivers/dac.h" #include "drivers/timer.h" #include "gpio.h" -#include "libc.h" #define CAN CAN1 @@ -25,6 +31,9 @@ void puth(unsigned int i) { UNUSED(i); } + void puth2(unsigned int i) { + UNUSED(i); + } #endif #define ENTER_BOOTLOADER_MAGIC 0xdeadbeef @@ -180,7 +189,7 @@ void CAN1_RX0_IRQHandler(void) { if (((current_index + 1U) & COUNTER_CYCLE) == index) { #ifdef DEBUG puts("setting gas "); - puth(value); + puth(value_0); puts("\n"); #endif if (enable) { @@ -257,7 +266,7 @@ void TIM3_IRQHandler(void) { } // blink the LED - set_led(LED_GREEN, led_value); + current_board->set_led(LED_GREEN, led_value); led_value = !led_value; TIM3->SR = 0; @@ -294,8 +303,9 @@ int main(void) { // init devices clock_init(); - periph_init(); - gpio_init(); + peripherals_init(); + detect_configuration(); + detect_board_type(); #ifdef PEDAL_USB // enable USB diff --git a/board/pedal/main_declarations.h b/board/pedal/main_declarations.h new file mode 100644 index 00000000000000..9a40f8ae3af447 --- /dev/null +++ b/board/pedal/main_declarations.h @@ -0,0 +1,11 @@ +// ******************** Prototypes ******************** +void puts(const char *a); +void puth(unsigned int i); +void puth2(unsigned int i); +typedef struct board board; +typedef struct harness_configuration harness_configuration; + +// ********************* Globals ********************** +uint8_t hw_type = 0; +const board *current_board; +bool is_enumerated = 0; \ No newline at end of file diff --git a/board/power_saving.h b/board/power_saving.h index 3a9ae39e433dc2..94ebbb53cf9a0a 100644 --- a/board/power_saving.h +++ b/board/power_saving.h @@ -10,14 +10,14 @@ void set_power_save_state(int state) { bool enable = false; if (state == POWER_SAVE_STATUS_ENABLED) { puts("enable power savings\n"); - if (is_grey_panda) { + if (board_has_gps()) { char UBLOX_SLEEP_MSG[] = "\xb5\x62\x06\x04\x04\x00\x01\x00\x08\x00\x17\x78"; uart_ring *ur = get_ring_by_number(1); for (unsigned int i = 0; i < sizeof(UBLOX_SLEEP_MSG) - 1U; i++) while (!putc(ur, UBLOX_SLEEP_MSG[i])); } } else { puts("disable power savings\n"); - if (is_grey_panda) { + if (board_has_gps()) { char UBLOX_WAKE_MSG[] = "\xb5\x62\x06\x04\x04\x00\x01\x00\x09\x00\x18\x7a"; uart_ring *ur = get_ring_by_number(1); for (unsigned int i = 0; i < sizeof(UBLOX_WAKE_MSG) - 1U; i++) while (!putc(ur, UBLOX_WAKE_MSG[i])); @@ -25,18 +25,18 @@ void set_power_save_state(int state) { enable = true; } - // turn on can - set_can_enable(CAN1, enable); - set_can_enable(CAN2, enable); - set_can_enable(CAN3, enable); + // Switch CAN transcievers + current_board->enable_can_transcievers(enable); - // turn on GMLAN - set_gpio_output(GPIOB, 14, enable); - set_gpio_output(GPIOB, 15, enable); + if(hw_type != HW_TYPE_BLACK_PANDA){ + // turn on GMLAN + set_gpio_output(GPIOB, 14, enable); + set_gpio_output(GPIOB, 15, enable); - // turn on LIN - set_gpio_output(GPIOB, 7, enable); - set_gpio_output(GPIOA, 14, enable); + // turn on LIN + set_gpio_output(GPIOB, 7, enable); + set_gpio_output(GPIOA, 14, enable); + } power_save_status = state; } diff --git a/board/safety/safety_elm327.h b/board/safety/safety_elm327.h index 1f44e992a0d4e9..bbad909f28cb37 100644 --- a/board/safety/safety_elm327.h +++ b/board/safety/safety_elm327.h @@ -1,15 +1,9 @@ static int elm327_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int tx = 1; - int bus = GET_BUS(to_send); int addr = GET_ADDR(to_send); int len = GET_LEN(to_send); - //All ELM traffic must appear on CAN0 - if (bus != 0) { - tx = 0; - } - //All ISO 15765-4 messages must be 8 bytes long if (len != 8) { tx = 0; diff --git a/board/safety/safety_honda.h b/board/safety/safety_honda.h index 6179a5e37450d5..80237dccbe3611 100644 --- a/board/safety/safety_honda.h +++ b/board/safety/safety_honda.h @@ -136,8 +136,9 @@ static int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { // FORCE CANCEL: safety check only relevant when spamming the cancel button in Bosch HW // ensuring that only the cancel button press is sent (VAL 2) when controls are off. // This avoids unintended engagements while still allowing resume spam + int bus_pt = ((hw_type == HW_TYPE_BLACK_PANDA) && honda_bosch_hardware)? 1 : 0; if ((addr == 0x296) && honda_bosch_hardware && - !current_controls_allowed && (bus == 0)) { + !current_controls_allowed && (bus == bus_pt)) { if (((GET_BYTE(to_send, 0) >> 5) & 0x7) != 2) { tx = 0; } @@ -186,15 +187,17 @@ static int honda_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { static int honda_bosch_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { int bus_fwd = -1; + int bus_rdr_cam = (hw_type == HW_TYPE_BLACK_PANDA) ? 2 : 1; // radar bus, camera side + int bus_rdr_car = (hw_type == HW_TYPE_BLACK_PANDA) ? 0 : 2; // radar bus, car side - if (bus_num == 2) { - bus_fwd = 1; + if (bus_num == bus_rdr_car) { + bus_fwd = bus_rdr_cam; } - if (bus_num == 1) { + if (bus_num == bus_rdr_cam) { int addr = GET_ADDR(to_fwd); int is_lkas_msg = (addr == 0xE4) || (addr == 0x33D); if (!is_lkas_msg) { - bus_fwd = 2; + bus_fwd = bus_rdr_car; } } return bus_fwd; diff --git a/board/spi_flasher.h b/board/spi_flasher.h index aacea822cdfd3e..4eab35671cae10 100644 --- a/board/spi_flasher.h +++ b/board/spi_flasher.h @@ -31,7 +31,7 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) FLASH->KEYR = 0xCDEF89AB; resp[1] = 0xff; } - set_led(LED_GREEN, 1); + current_board->set_led(LED_GREEN, 1); unlocked = 1; prog_ptr = (uint32_t *)0x8004000; break; @@ -112,7 +112,7 @@ void usb_cb_enumeration_complete(void) { void usb_cb_ep2_out(void *usbdata, int len, bool hardwired) { UNUSED(hardwired); - set_led(LED_RED, 0); + current_board->set_led(LED_RED, 0); for (int i = 0; i < len/4; i++) { // program byte 1 FLASH->CR = FLASH_CR_PSIZE_1 | FLASH_CR_PG; @@ -123,7 +123,7 @@ void usb_cb_ep2_out(void *usbdata, int len, bool hardwired) { //*(uint64_t*)(&spi_tx_buf[0x30+(i*4)]) = *prog_ptr; prog_ptr++; } - set_led(LED_RED, 1); + current_board->set_led(LED_RED, 1); } @@ -276,7 +276,7 @@ void soft_flasher_start(void) { // B8,B9: CAN 1 set_gpio_alternate(GPIOB, 8, GPIO_AF9_CAN1); set_gpio_alternate(GPIOB, 9, GPIO_AF9_CAN1); - set_can_enable(CAN1, 1); + current_board->enable_can_transciever(1, true); // init can llcan_set_speed(CAN1, 5000, false, false); @@ -305,7 +305,7 @@ void soft_flasher_start(void) { usb_init(); // green LED on for flashing - set_led(LED_GREEN, 1); + current_board->set_led(LED_GREEN, 1); __enable_irq(); @@ -316,13 +316,13 @@ void soft_flasher_start(void) { // if you are connected through a hub to the phone // you need power to be able to see the device puts("USBP: didn't enumerate, switching to CDP mode\n"); - set_usb_power_mode(USB_POWER_CDP); - set_led(LED_BLUE, 1); + current_board->set_usb_power_mode(USB_POWER_CDP); + current_board->set_led(LED_BLUE, 1); } // blink the green LED fast - set_led(LED_GREEN, 0); + current_board->set_led(LED_GREEN, 0); delay(500000); - set_led(LED_GREEN, 1); + current_board->set_led(LED_GREEN, 1); delay(500000); } } diff --git a/python/__init__.py b/python/__init__.py index bfca642e8256f7..e83a4a16947366 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -16,7 +16,7 @@ from serial import PandaSerial from isotp import isotp_send, isotp_recv -__version__ = '0.0.8' +__version__ = '0.0.9' BASEDIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../") @@ -232,10 +232,10 @@ def flash_static(handle, code): print("flash: unlocking") handle.controlWrite(Panda.REQUEST_IN, 0xb1, 0, 0, b'') - # erase sectors 1 and 2 + # erase sectors 1 through 3 print("flash: erasing") - handle.controlWrite(Panda.REQUEST_IN, 0xb2, 1, 0, b'') - handle.controlWrite(Panda.REQUEST_IN, 0xb2, 2, 0, b'') + for i in range(1, 4): + handle.controlWrite(Panda.REQUEST_IN, 0xb2, i, 0, b'') # flash over EP2 STEP = 0x10 @@ -334,13 +334,19 @@ def call_control_api(self, msg): # ******************* health ******************* def health(self): - dat = self._handle.controlRead(Panda.REQUEST_IN, 0xd2, 0, 0, 13) - a = struct.unpack("IIBBBBB", dat) - return {"voltage": a[0], "current": a[1], - "started": a[2], "controls_allowed": a[3], - "gas_interceptor_detected": a[4], - "started_signal_detected": a[5], - "started_alt": a[6]} + dat = self._handle.controlRead(Panda.REQUEST_IN, 0xd2, 0, 0, 24) + a = struct.unpack("IIIIIBBBB", dat) + return { + "voltage": a[0], + "current": a[1], + "can_send_errs": a[2], + "can_fwd_errs": a[3], + "gmlan_send_errs": a[4], + "started": a[5], + "controls_allowed": a[6], + "gas_interceptor_detected": a[7], + "car_harness_status": a[8] + } # ******************* control ******************* @@ -354,9 +360,14 @@ def enter_bootloader(self): def get_version(self): return self._handle.controlRead(Panda.REQUEST_IN, 0xd6, 0, 0, 0x40) + def get_type(self): + return self._handle.controlRead(Panda.REQUEST_IN, 0xc1, 0, 0, 0x40) + def is_grey(self): - ret = self._handle.controlRead(Panda.REQUEST_IN, 0xc1, 0, 0, 0x40) - return ret == "\x01" + return self.get_type() == "\x02" + + def is_black(self): + return self.get_type() == "\x03" def get_serial(self): dat = self._handle.controlRead(Panda.REQUEST_IN, 0xd0, 0, 0, 0x20) @@ -387,11 +398,16 @@ def set_can_forwarding(self, from_bus, to_bus): self._handle.controlWrite(Panda.REQUEST_OUT, 0xdd, from_bus, to_bus, b'') def set_gmlan(self, bus=2): + # TODO: check panda type if bus is None: self._handle.controlWrite(Panda.REQUEST_OUT, 0xdb, 0, 0, b'') elif bus in [Panda.GMLAN_CAN2, Panda.GMLAN_CAN3]: self._handle.controlWrite(Panda.REQUEST_OUT, 0xdb, 1, bus, b'') + def set_obd(self, obd): + # TODO: check panda type + self._handle.controlWrite(Panda.REQUEST_OUT, 0xdb, int(obd), 0, b'') + def set_can_loopback(self, enable): # set can loopback mode for all buses self._handle.controlWrite(Panda.REQUEST_OUT, 0xe5, int(enable), 0, b'') @@ -559,3 +575,6 @@ def kline_recv(self, bus=2): msg = self.kline_ll_recv(2, bus=bus) msg += self.kline_ll_recv(ord(msg[1])-2, bus=bus) return msg + + def send_heartbeat(self): + self._handle.controlWrite(Panda.REQUEST_OUT, 0xf3, 0, 0, b'') diff --git a/tests/automated/2_usb_to_can.py b/tests/automated/2_usb_to_can.py index 7860d3290fb0e5..9e3e07aa490daa 100644 --- a/tests/automated/2_usb_to_can.py +++ b/tests/automated/2_usb_to_can.py @@ -26,6 +26,9 @@ def test_can_loopback(serial=None): busses = [0,1,2] for bus in busses: + # send heartbeat + p.send_heartbeat() + # set bus 0 speed to 250 p.set_can_speed_kbps(bus, 250) @@ -52,6 +55,9 @@ def test_safety_nooutput(serial=None): # enable output mode p.set_safety_mode(Panda.SAFETY_NOOUTPUT) + # send heartbeat + p.send_heartbeat() + # enable CAN loopback mode p.set_can_loopback(True) @@ -76,11 +82,17 @@ def test_reliability(serial=None): p.set_can_loopback(True) p.set_can_speed_kbps(0, 1000) + # send heartbeat + p.send_heartbeat() + addrs = range(100, 100+MSG_COUNT) ts = [(j, 0, "\xaa"*8, 0) for j in addrs] # 100 loops for i in range(LOOP_COUNT): + # send heartbeat + p.send_heartbeat() + st = time.time() p.can_send_many(ts) @@ -111,6 +123,9 @@ def test_throughput(serial=None): # enable output mode p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) + # send heartbeat + p.send_heartbeat() + # enable CAN loopback mode p.set_can_loopback(True) @@ -119,6 +134,9 @@ def test_throughput(serial=None): p.set_can_speed_kbps(0, speed) time.sleep(0.05) + # send heartbeat + p.send_heartbeat() + comp_kbps = time_many_sends(p, 0) # bit count from https://en.wikipedia.org/wiki/CAN_bus @@ -139,6 +157,9 @@ def test_gmlan(serial=None): # enable output mode p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) + # send heartbeat + p.send_heartbeat() + # enable CAN loopback mode p.set_can_loopback(True) @@ -148,6 +169,9 @@ def test_gmlan(serial=None): # set gmlan on CAN2 for bus in [Panda.GMLAN_CAN2, Panda.GMLAN_CAN3, Panda.GMLAN_CAN2, Panda.GMLAN_CAN3]: + # send heartbeat + p.send_heartbeat() + p.set_gmlan(bus) comp_kbps_gmlan = time_many_sends(p, 3) assert_greater(comp_kbps_gmlan, 0.8 * SPEED_GMLAN) @@ -171,11 +195,17 @@ def test_gmlan_bad_toggle(serial=None): # enable output mode p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) + # send heartbeat + p.send_heartbeat() + # enable CAN loopback mode p.set_can_loopback(True) # GMLAN_CAN2 for bus in [Panda.GMLAN_CAN2, Panda.GMLAN_CAN3]: + # send heartbeat + p.send_heartbeat() + p.set_gmlan(bus) comp_kbps_gmlan = time_many_sends(p, 3) assert_greater(comp_kbps_gmlan, 0.6 * SPEED_GMLAN) @@ -183,6 +213,9 @@ def test_gmlan_bad_toggle(serial=None): # normal for bus in [Panda.GMLAN_CAN2, Panda.GMLAN_CAN3]: + # send heartbeat + p.send_heartbeat() + p.set_gmlan(None) comp_kbps_normal = time_many_sends(p, bus) assert_greater(comp_kbps_normal, 0.6 * SPEED_NORMAL) diff --git a/tests/automated/4_wifi_functionality.py b/tests/automated/4_wifi_functionality.py index 0cf42d1f3fba17..ab9bed70052e41 100644 --- a/tests/automated/4_wifi_functionality.py +++ b/tests/automated/4_wifi_functionality.py @@ -21,12 +21,18 @@ def test_throughput(serial=None): # enable output mode p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) + # send heartbeat + p.send_heartbeat() + # enable CAN loopback mode p.set_can_loopback(True) p = Panda("WIFI") for speed in [100,250,500,750,1000]: + # send heartbeat + p.send_heartbeat() + # set bus 0 speed to speed p.set_can_speed_kbps(0, speed) time.sleep(0.1) @@ -46,11 +52,18 @@ def test_recv_only(serial=None): connect_wifi(serial) p = Panda(serial) p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) + + # send heartbeat + p.send_heartbeat() + p.set_can_loopback(True) pwifi = Panda("WIFI") # TODO: msg_count=1000 drops packets, is this fixable? for msg_count in [10,100,200]: + # send heartbeat + p.send_heartbeat() + speed = 500 p.set_can_speed_kbps(0, speed) comp_kbps = time_many_sends(p, 0, pwifi, msg_count) diff --git a/tests/automated/6_two_panda.py b/tests/automated/6_two_panda.py index 3c29a0e7a1233d..09cf1861f34d95 100644 --- a/tests/automated/6_two_panda.py +++ b/tests/automated/6_two_panda.py @@ -13,6 +13,9 @@ def test_send_recv(serial_sender=None, serial_reciever=None): p_send.set_safety_mode(Panda.SAFETY_ALLOUTPUT) p_send.set_can_loopback(False) + # send heartbeat + p_send.send_heartbeat() + p_recv.set_can_loopback(False) assert not p_send.legacy @@ -27,6 +30,9 @@ def test_send_recv(serial_sender=None, serial_reciever=None): for bus in busses: for speed in [100, 250, 500, 750, 1000]: + # send heartbeat + p_send.send_heartbeat() + p_send.set_can_speed_kbps(bus, speed) p_recv.set_can_speed_kbps(bus, speed) time.sleep(0.05) @@ -45,6 +51,10 @@ def test_latency(serial_sender=None, serial_reciever=None): p_send = Panda(serial_sender) p_recv = Panda(serial_reciever) + # send heartbeat + p_send.send_heartbeat() + p_recv.send_heartbeat() + p_send.set_safety_mode(Panda.SAFETY_ALLOUTPUT) p_send.set_can_loopback(False) @@ -62,10 +72,18 @@ def test_latency(serial_sender=None, serial_reciever=None): p_recv.can_recv() p_send.can_recv() + # send heartbeat + p_send.send_heartbeat() + p_recv.send_heartbeat() + busses = [0,1,2] for bus in busses: for speed in [100, 250, 500, 750, 1000]: + # send heartbeat + p_send.send_heartbeat() + p_recv.send_heartbeat() + p_send.set_can_speed_kbps(bus, speed) p_recv.set_can_speed_kbps(bus, speed) time.sleep(0.1) diff --git a/tests/black_loopback_test.py b/tests/black_loopback_test.py new file mode 100755 index 00000000000000..2e5099a599317c --- /dev/null +++ b/tests/black_loopback_test.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python + +# Loopback test between black panda (+ harness and power) and white/grey panda +# Tests all buses, including OBD CAN, which is on the same bus as CAN0 in this test. +# To be sure, the test should be run with both harness orientations + +from __future__ import print_function +import os +import sys +import time +import random +import argparse + +from hexdump import hexdump +from itertools import permutations + +sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")) +from panda import Panda + +def get_test_string(): + return b"test"+os.urandom(10) + +def run_test(sleep_duration): + pandas = Panda.list() + print(pandas) + + # make sure two pandas are connected + if len(pandas) != 2: + print("Connect white/grey and black panda to run this test!") + assert False + + # connect + pandas[0] = Panda(pandas[0]) + pandas[1] = Panda(pandas[1]) + + # find out which one is black + type0 = pandas[0].get_type() + type1 = pandas[1].get_type() + + black_panda = None + other_panda = None + + if type0 == "\x03" and type1 != "\x03": + black_panda = pandas[0] + other_panda = pandas[1] + elif type0 != "\x03" and type1 == "\x03": + black_panda = pandas[1] + other_panda = pandas[0] + else: + print("Connect white/grey and black panda to run this test!") + assert False + + # disable safety modes + black_panda.set_safety_mode(Panda.SAFETY_ALLOUTPUT) + other_panda.set_safety_mode(Panda.SAFETY_ALLOUTPUT) + + # test health packet + print("black panda health", black_panda.health()) + print("other panda health", other_panda.health()) + + # test black -> other + test_buses(black_panda, other_panda, True, [(0, False, [0]), (1, False, [1]), (2, False, [2]), (1, True, [0])], sleep_duration) + test_buses(black_panda, other_panda, False, [(0, False, [0]), (1, False, [1]), (2, False, [2]), (0, True, [0, 1])], sleep_duration) + + +def test_buses(black_panda, other_panda, direction, test_array, sleep_duration): + if direction: + print("***************** TESTING (BLACK --> OTHER) *****************") + else: + print("***************** TESTING (OTHER --> BLACK) *****************") + + for send_bus, obd, recv_buses in test_array: + print("\ntest can: ", send_bus, " OBD: ", obd) + + # set OBD on black panda + black_panda.set_gmlan(True if obd else None) + + # clear and flush + if direction: + black_panda.can_clear(send_bus) + else: + other_panda.can_clear(send_bus) + + for recv_bus in recv_buses: + if direction: + other_panda.can_clear(recv_bus) + else: + black_panda.can_clear(recv_bus) + + black_panda.can_recv() + other_panda.can_recv() + + # send the characters + at = random.randint(1, 2000) + st = get_test_string()[0:8] + if direction: + black_panda.can_send(at, st, send_bus) + else: + other_panda.can_send(at, st, send_bus) + time.sleep(0.1) + + # check for receive + if direction: + cans_echo = black_panda.can_recv() + cans_loop = other_panda.can_recv() + else: + cans_echo = other_panda.can_recv() + cans_loop = black_panda.can_recv() + + loop_buses = [] + for loop in cans_loop: + print(" Loop on bus", str(loop[3])) + loop_buses.append(loop[3]) + if len(cans_loop) == 0: + print(" No loop") + + # test loop buses + recv_buses.sort() + loop_buses.sort() + assert recv_buses == loop_buses + print(" TEST PASSED") + + time.sleep(sleep_duration) + print("\n") + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("-n", type=int, help="Number of test iterations to run") + parser.add_argument("-sleep", type=int, help="Sleep time between tests", default=0) + args = parser.parse_args() + + if args.n is None: + while True: + run_test(sleep_duration=args.sleep) + else: + for i in range(args.n): + run_test(sleep_duration=args.sleep) diff --git a/tests/safety/libpandasafety_py.py b/tests/safety/libpandasafety_py.py index 1345065cb4d103..888bd36e948758 100644 --- a/tests/safety/libpandasafety_py.py +++ b/tests/safety/libpandasafety_py.py @@ -37,6 +37,7 @@ void set_gas_interceptor_detected(bool c); bool get_gas_interceptor_detetcted(void); int get_gas_interceptor_prev(void); +int get_hw_type(void); void set_timer(uint32_t t); void reset_angle_control(void); @@ -60,6 +61,7 @@ int get_honda_gas_prev(void); void set_honda_alt_brake_msg(bool); void set_honda_bosch_hardware(bool); +int get_honda_bosch_hardware(void); void init_tests_cadillac(void); void set_cadillac_desired_torque_last(int t); diff --git a/tests/safety/test.c b/tests/safety/test.c index dc3de55040b3d6..7cd9b86d86f9a0 100644 --- a/tests/safety/test.c +++ b/tests/safety/test.c @@ -1,5 +1,6 @@ #include #include +#include typedef struct { @@ -51,6 +52,16 @@ TIM_TypeDef *TIM2 = &timer; #define GET_BYTES_04(msg) ((msg)->RDLR) #define GET_BYTES_48(msg) ((msg)->RDHR) +// from board_declarations.h +#define HW_TYPE_UNKNOWN 0U +#define HW_TYPE_WHITE_PANDA 1U +#define HW_TYPE_GREY_PANDA 2U +#define HW_TYPE_BLACK_PANDA 3U +#define HW_TYPE_PEDAL 4U + +// from main_declarations.h +uint8_t hw_type = 0U; + #define UNUSED(x) (void)(x) #define PANDA @@ -90,6 +101,10 @@ int get_gas_interceptor_prev(void){ return gas_interceptor_prev; } +int get_hw_type(void){ + return hw_type; +} + void set_timer(uint32_t t){ timer.CNT = t; } @@ -228,7 +243,17 @@ void set_honda_bosch_hardware(bool c){ honda_bosch_hardware = c; } +int get_honda_bosch_hardware(void) { + return honda_bosch_hardware; +} + +void init_tests(void){ + // get HW_TYPE from env variable set in test.sh + hw_type = atoi(getenv("HW_TYPE")); +} + void init_tests_toyota(void){ + init_tests(); toyota_torque_meas.min = 0; toyota_torque_meas.max = 0; toyota_desired_torque_last = 0; @@ -238,6 +263,7 @@ void init_tests_toyota(void){ } void init_tests_cadillac(void){ + init_tests(); cadillac_torque_driver.min = 0; cadillac_torque_driver.max = 0; for (int i = 0; i < 4; i++) cadillac_desired_torque_last[i] = 0; @@ -247,6 +273,7 @@ void init_tests_cadillac(void){ } void init_tests_gm(void){ + init_tests(); gm_torque_driver.min = 0; gm_torque_driver.max = 0; gm_desired_torque_last = 0; @@ -256,6 +283,7 @@ void init_tests_gm(void){ } void init_tests_hyundai(void){ + init_tests(); hyundai_torque_driver.min = 0; hyundai_torque_driver.max = 0; hyundai_desired_torque_last = 0; @@ -265,6 +293,7 @@ void init_tests_hyundai(void){ } void init_tests_chrysler(void){ + init_tests(); chrysler_torque_meas.min = 0; chrysler_torque_meas.max = 0; chrysler_desired_torque_last = 0; @@ -274,6 +303,7 @@ void init_tests_chrysler(void){ } void init_tests_subaru(void){ + init_tests(); subaru_torque_driver.min = 0; subaru_torque_driver.max = 0; subaru_desired_torque_last = 0; @@ -283,6 +313,7 @@ void init_tests_subaru(void){ } void init_tests_honda(void){ + init_tests(); honda_moving = false; honda_brake_prev = 0; honda_gas_prev = 0; diff --git a/tests/safety/test.sh b/tests/safety/test.sh index 83d8f5b31fa420..2674281addd9f4 100755 --- a/tests/safety/test.sh +++ b/tests/safety/test.sh @@ -1,2 +1,17 @@ #!/usr/bin/env sh -python -m unittest discover . + +# Loop over all hardware types: +# HW_TYPE_UNKNOWN 0U +# HW_TYPE_WHITE_PANDA 1U +# HW_TYPE_GREY_PANDA 2U +# HW_TYPE_BLACK_PANDA 3U +# HW_TYPE_PEDAL 4U + +# Make sure test fails if one HW_TYPE fails +set -e + +for hw_type in 0 1 2 3 4 +do + echo "Testing HW_TYPE: $hw_type" + HW_TYPE=$hw_type python -m unittest discover . +done diff --git a/tests/safety/test_honda.py b/tests/safety/test_honda.py index 5833d96e3f89f0..f16030843c2a35 100755 --- a/tests/safety/test_honda.py +++ b/tests/safety/test_honda.py @@ -33,6 +33,10 @@ def _button_msg(self, buttons, msg): to_send = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *') to_send[0].RIR = msg << 21 to_send[0].RDLR = buttons << 5 + is_panda_black = self.safety.get_hw_type() == 3 # black_panda + honda_bosch_hardware = self.safety.get_honda_bosch_hardware() + bus = 1 if is_panda_black and honda_bosch_hardware else 0 + to_send[0].RDTR = bus << 4 return to_send diff --git a/tests/safety/test_honda_bosch.py b/tests/safety/test_honda_bosch.py index 11c93914039c1d..0d37cbe8072a0b 100755 --- a/tests/safety/test_honda_bosch.py +++ b/tests/safety/test_honda_bosch.py @@ -23,16 +23,20 @@ def _send_msg(self, bus, addr, length): def test_fwd_hook(self): buss = range(0x0, 0x3) msgs = range(0x1, 0x800) + is_panda_black = self.safety.get_hw_type() == 3 # black panda + bus_rdr_cam = 2 if is_panda_black else 1 + bus_rdr_car = 0 if is_panda_black else 2 + bus_pt = 1 if is_panda_black else 0 blocked_msgs = [0xE4, 0x33D] for b in buss: for m in msgs: - if b == 0: + if b == bus_pt: fwd_bus = -1 - elif b == 1: - fwd_bus = -1 if m in blocked_msgs else 2 - elif b == 2: - fwd_bus = 1 + elif b == bus_rdr_cam: + fwd_bus = -1 if m in blocked_msgs else bus_rdr_car + elif b == bus_rdr_car: + fwd_bus = bus_rdr_cam # assume len 8 self.assertEqual(fwd_bus, self.safety.safety_fwd_hook(b, self._send_msg(b, m, 8)))