519e39e49 Changed heartbeat timeout to be 2 seconds on no ignition
996dc4049 Added heartbeat to black loopback testing
79b44cb7e bump version
59f581317 Black (#254)
096486693 no need to store safety only misra output anymore
git-subtree-dir: panda
git-subtree-split: 519e39e494c0b3dd0cf38581302788b779a03c7b
old-commit-hash: 30bb73d527
commatwo_master
parent
1b8e5096c2
commit
ae3c66c783
33 changed files with 1615 additions and 690 deletions
@ -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)); |
||||||
|
} |
@ -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; |
@ -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 |
||||||
|
}; |
@ -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<PULL_EFFECTIVE_DELAY; i++); |
||||||
|
bool ret = get_gpio_input(GPIO, pin); |
||||||
|
set_gpio_pullup(GPIO, pin, PULL_NONE); |
||||||
|
return ret; |
||||||
|
} |
@ -0,0 +1,18 @@ |
|||||||
|
// ////////// //
|
||||||
|
// Grey Panda //
|
||||||
|
// ////////// //
|
||||||
|
|
||||||
|
// Most hardware functionality is similar to white panda
|
||||||
|
const board board_grey = { |
||||||
|
.board_type = "Grey", |
||||||
|
.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 |
||||||
|
}; |
@ -0,0 +1,96 @@ |
|||||||
|
// ///// //
|
||||||
|
// Pedal //
|
||||||
|
// ///// //
|
||||||
|
|
||||||
|
void pedal_enable_can_transciever(uint8_t transciever, bool enabled) { |
||||||
|
switch (transciever){ |
||||||
|
case 1: |
||||||
|
set_gpio_output(GPIOB, 3, !enabled); |
||||||
|
break; |
||||||
|
default: |
||||||
|
puts("Invalid CAN transciever ("); puth(transciever); puts("): enabling failed\n"); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void pedal_enable_can_transcievers(bool enabled) { |
||||||
|
pedal_enable_can_transciever(1U, enabled); |
||||||
|
} |
||||||
|
|
||||||
|
void pedal_set_led(uint8_t color, bool enabled) { |
||||||
|
switch (color){ |
||||||
|
case LED_RED: |
||||||
|
set_gpio_output(GPIOB, 10, !enabled); |
||||||
|
break; |
||||||
|
case LED_GREEN: |
||||||
|
set_gpio_output(GPIOB, 11, !enabled); |
||||||
|
break; |
||||||
|
default: |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void pedal_set_usb_power_mode(uint8_t mode){ |
||||||
|
usb_power_mode = mode; |
||||||
|
puts("Trying to set USB power mode on pedal. This is not supported.\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void pedal_set_esp_gps_mode(uint8_t mode) { |
||||||
|
UNUSED(mode); |
||||||
|
puts("Trying to set ESP/GPS mode on pedal. This is not supported.\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void pedal_set_can_mode(uint8_t mode){ |
||||||
|
switch (mode) { |
||||||
|
case CAN_MODE_NORMAL: |
||||||
|
break; |
||||||
|
default: |
||||||
|
puts("Tried to set unsupported CAN mode: "); puth(mode); puts("\n"); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void pedal_usb_power_mode_tick(uint64_t tcnt){ |
||||||
|
UNUSED(tcnt); |
||||||
|
// Not applicable
|
||||||
|
} |
||||||
|
|
||||||
|
bool pedal_check_ignition(void){ |
||||||
|
// not supported on pedal
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
void pedal_init(void) { |
||||||
|
common_init_gpio(); |
||||||
|
|
||||||
|
// C0, C1: Throttle inputs
|
||||||
|
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
|
||||||
|
|
||||||
|
// Enable transciever
|
||||||
|
pedal_enable_can_transcievers(true); |
||||||
|
|
||||||
|
// Disable LEDs
|
||||||
|
pedal_set_led(LED_RED, false); |
||||||
|
pedal_set_led(LED_GREEN, false); |
||||||
|
} |
||||||
|
|
||||||
|
const harness_configuration pedal_harness_config = { |
||||||
|
.has_harness = false |
||||||
|
}; |
||||||
|
|
||||||
|
const board board_pedal = { |
||||||
|
.board_type = "Pedal", |
||||||
|
.harness_config = &pedal_harness_config, |
||||||
|
.init = pedal_init, |
||||||
|
.enable_can_transciever = pedal_enable_can_transciever, |
||||||
|
.enable_can_transcievers = pedal_enable_can_transcievers, |
||||||
|
.set_led = pedal_set_led, |
||||||
|
.set_usb_power_mode = pedal_set_usb_power_mode, |
||||||
|
.set_esp_gps_mode = pedal_set_esp_gps_mode, |
||||||
|
.set_can_mode = pedal_set_can_mode, |
||||||
|
.usb_power_mode_tick = pedal_usb_power_mode_tick, |
||||||
|
.check_ignition = pedal_check_ignition, |
||||||
|
}; |
@ -0,0 +1,306 @@ |
|||||||
|
// /////////// //
|
||||||
|
// White Panda //
|
||||||
|
// /////////// //
|
||||||
|
|
||||||
|
void white_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; |
||||||
|
default: |
||||||
|
puts("Invalid CAN transciever ("); puth(transciever); puts("): enabling failed\n"); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void white_enable_can_transcievers(bool enabled) { |
||||||
|
for(uint8_t i=1; i<=3U; i++) |
||||||
|
white_enable_can_transciever(i, enabled); |
||||||
|
} |
||||||
|
|
||||||
|
void white_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 white_set_usb_power_mode(uint8_t 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; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void white_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 white_set_can_mode(uint8_t mode){ |
||||||
|
switch (mode) { |
||||||
|
case CAN_MODE_NORMAL: |
||||||
|
// B12,B13: disable GMLAN mode
|
||||||
|
set_gpio_mode(GPIOB, 12, MODE_INPUT); |
||||||
|
set_gpio_mode(GPIOB, 13, MODE_INPUT); |
||||||
|
|
||||||
|
// B3,B4: disable GMLAN mode
|
||||||
|
set_gpio_mode(GPIOB, 3, MODE_INPUT); |
||||||
|
set_gpio_mode(GPIOB, 4, MODE_INPUT); |
||||||
|
|
||||||
|
// B5,B6: normal CAN2 mode
|
||||||
|
set_gpio_alternate(GPIOB, 5, GPIO_AF9_CAN2); |
||||||
|
set_gpio_alternate(GPIOB, 6, GPIO_AF9_CAN2); |
||||||
|
|
||||||
|
// A8,A15: normal CAN3 mode
|
||||||
|
set_gpio_alternate(GPIOA, 8, GPIO_AF11_CAN3); |
||||||
|
set_gpio_alternate(GPIOA, 15, GPIO_AF11_CAN3); |
||||||
|
break; |
||||||
|
case CAN_MODE_GMLAN_CAN2: |
||||||
|
// B5,B6: disable CAN2 mode
|
||||||
|
set_gpio_mode(GPIOB, 5, MODE_INPUT); |
||||||
|
set_gpio_mode(GPIOB, 6, MODE_INPUT); |
||||||
|
|
||||||
|
// B3,B4: disable GMLAN mode
|
||||||
|
set_gpio_mode(GPIOB, 3, MODE_INPUT); |
||||||
|
set_gpio_mode(GPIOB, 4, MODE_INPUT); |
||||||
|
|
||||||
|
// B12,B13: GMLAN mode
|
||||||
|
set_gpio_alternate(GPIOB, 12, GPIO_AF9_CAN2); |
||||||
|
set_gpio_alternate(GPIOB, 13, GPIO_AF9_CAN2); |
||||||
|
|
||||||
|
// A8,A15: normal CAN3 mode
|
||||||
|
set_gpio_alternate(GPIOA, 8, GPIO_AF11_CAN3); |
||||||
|
set_gpio_alternate(GPIOA, 15, GPIO_AF11_CAN3);
|
||||||
|
break; |
||||||
|
case CAN_MODE_GMLAN_CAN3: |
||||||
|
// A8,A15: disable CAN3 mode
|
||||||
|
set_gpio_mode(GPIOA, 8, MODE_INPUT); |
||||||
|
set_gpio_mode(GPIOA, 15, MODE_INPUT); |
||||||
|
|
||||||
|
// B12,B13: disable GMLAN mode
|
||||||
|
set_gpio_mode(GPIOB, 12, MODE_INPUT); |
||||||
|
set_gpio_mode(GPIOB, 13, MODE_INPUT); |
||||||
|
|
||||||
|
// B3,B4: GMLAN mode
|
||||||
|
set_gpio_alternate(GPIOB, 3, GPIO_AF11_CAN3); |
||||||
|
set_gpio_alternate(GPIOB, 4, GPIO_AF11_CAN3); |
||||||
|
|
||||||
|
// B5,B6: normal CAN2 mode
|
||||||
|
set_gpio_alternate(GPIOB, 5, GPIO_AF9_CAN2); |
||||||
|
set_gpio_alternate(GPIOB, 6, GPIO_AF9_CAN2); |
||||||
|
break;
|
||||||
|
default: |
||||||
|
puts("Tried to set unsupported CAN mode: "); puth(mode); puts("\n"); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
uint64_t marker = 0; |
||||||
|
void white_usb_power_mode_tick(uint64_t tcnt){ |
||||||
|
#ifndef BOOTSTUB |
||||||
|
#define CURRENT_THRESHOLD 0xF00U |
||||||
|
#define CLICKS 5U // 5 seconds to switch modes
|
||||||
|
|
||||||
|
uint32_t current = adc_get(ADCCHAN_CURRENT); |
||||||
|
|
||||||
|
// ~0x9a = 500 ma
|
||||||
|
// puth(current); puts("\n");
|
||||||
|
|
||||||
|
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
|
||||||
|
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 |
||||||
|
}; |
@ -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"); |
||||||
|
} |
||||||
|
} |
@ -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; |
@ -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; |
@ -0,0 +1,139 @@ |
|||||||
|
#!/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: |
||||||
|
black_panda.send_heartbeat() |
||||||
|
other_panda.send_heartbeat() |
||||||
|
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) |
@ -1,2 +1,17 @@ |
|||||||
#!/usr/bin/env sh |
#!/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 |
||||||
|
Loading…
Reference in new issue