Merge panda subtree

This commit is contained in:
Vehicle Researcher
2019-12-13 13:02:46 -08:00
105 changed files with 2436 additions and 1664 deletions
+180 -134
View File
@@ -5,10 +5,15 @@
#include "config.h"
#include "obj/gitversion.h"
#include "main_declarations.h"
#include "critical.h"
#include "libc.h"
#include "provision.h"
#include "faults.h"
#include "main_declarations.h"
#include "drivers/registers.h"
#include "drivers/interrupts.h"
#include "drivers/llcan.h"
#include "drivers/llgpio.h"
@@ -34,6 +39,28 @@
#include "drivers/can.h"
extern int _app_start[0xc000]; // Only first 3 sectors of size 0x4000 are used
struct __attribute__((packed)) health_t {
uint32_t uptime_pkt;
uint32_t voltage_pkt;
uint32_t current_pkt;
uint32_t can_send_errs_pkt;
uint32_t can_fwd_errs_pkt;
uint32_t gmlan_send_errs_pkt;
uint32_t faults_pkt;
uint8_t ignition_line_pkt;
uint8_t ignition_can_pkt;
uint8_t controls_allowed_pkt;
uint8_t gas_interceptor_detected_pkt;
uint8_t car_harness_status_pkt;
uint8_t usb_power_mode_pkt;
uint8_t safety_mode_pkt;
uint8_t fault_status_pkt;
uint8_t power_save_enabled_pkt;
};
// ********************* Serial debugging *********************
bool check_started(void) {
@@ -45,11 +72,14 @@ void debug_ring_callback(uart_ring *ring) {
while (getc(ring, &rcv)) {
(void)putc(ring, rcv); // misra-c2012-17.7: cast to void is ok: debug function
// jump to DFU flash
if (rcv == 'z') {
enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC;
NVIC_SystemReset();
}
// only allow bootloader entry on debug builds
#ifdef ALLOW_DEBUG
// jump to DFU flash
if (rcv == 'z') {
enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC;
NVIC_SystemReset();
}
#endif
// normal reset
if (rcv == 'x') {
@@ -72,100 +102,65 @@ void debug_ring_callback(uart_ring *ring) {
}
}
// ***************************** started logic *****************************
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
// jenky debounce
delay(100000);
#ifdef EON
// set power savings mode here if on EON build
int power_save_state = check_started() ? POWER_SAVE_STATUS_DISABLED : POWER_SAVE_STATUS_ENABLED;
set_power_save_state(power_save_state);
// set CDP usb power mode everytime that the car starts to make sure EON is charging
if (check_started()) {
current_board->set_usb_power_mode(USB_POWER_CDP);
}
#endif
}
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);
}
// ****************************** 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);
uint16_t mode_copy = mode;
int err = set_safety_hooks(mode_copy, param);
if (err == -1) {
puts("Error: safety set mode failed\n");
} else {
switch (mode) {
case SAFETY_NOOUTPUT:
set_intercept_relay(false);
if(board_has_obd()){
current_board->set_can_mode(CAN_MODE_NORMAL);
}
can_silent = ALL_CAN_SILENT;
break;
case SAFETY_ELM327:
set_intercept_relay(false);
heartbeat_counter = 0U;
if(board_has_obd()){
current_board->set_can_mode(CAN_MODE_OBD_CAN2);
}
can_silent = ALL_CAN_LIVE;
break;
default:
set_intercept_relay(true);
heartbeat_counter = 0U;
if(board_has_obd()){
current_board->set_can_mode(CAN_MODE_NORMAL);
}
can_silent = ALL_CAN_LIVE;
break;
puts("Error: safety set mode failed. Falling back to SILENT\n");
mode_copy = SAFETY_SILENT;
err = set_safety_hooks(mode_copy, 0);
if (err == -1) {
puts("Error: Failed setting SILENT mode. Hanging\n");
while (true) {
// TERMINAL ERROR: we can't continue if SILENT safety mode isn't succesfully set
}
can_init_all();
}
}
switch (mode_copy) {
case SAFETY_SILENT:
set_intercept_relay(false);
if (board_has_obd()) {
current_board->set_can_mode(CAN_MODE_NORMAL);
}
can_silent = ALL_CAN_SILENT;
break;
case SAFETY_NOOUTPUT:
set_intercept_relay(false);
if (board_has_obd()) {
current_board->set_can_mode(CAN_MODE_NORMAL);
}
can_silent = ALL_CAN_LIVE;
break;
case SAFETY_ELM327:
set_intercept_relay(false);
heartbeat_counter = 0U;
if (board_has_obd()) {
current_board->set_can_mode(CAN_MODE_OBD_CAN2);
}
can_silent = ALL_CAN_LIVE;
break;
default:
set_intercept_relay(true);
heartbeat_counter = 0U;
if (board_has_obd()) {
current_board->set_can_mode(CAN_MODE_NORMAL);
}
can_silent = ALL_CAN_LIVE;
break;
}
can_init_all();
}
// ***************************** USB port *****************************
int get_health_pkt(void *dat) {
struct __attribute__((packed)) {
uint32_t voltage_pkt;
uint32_t current_pkt;
uint32_t can_send_errs_pkt;
uint32_t can_fwd_errs_pkt;
uint32_t gmlan_send_errs_pkt;
uint8_t ignition_line_pkt;
uint8_t ignition_can_pkt;
uint8_t controls_allowed_pkt;
uint8_t gas_interceptor_detected_pkt;
uint8_t car_harness_status_pkt;
uint8_t usb_power_mode_pkt;
uint8_t safety_mode_pkt;
} *health = dat;
COMPILE_TIME_ASSERT(sizeof(struct health_t) <= MAX_RESP_LEN);
struct health_t * health = (struct health_t*)dat;
health->uptime_pkt = uptime_cnt;
health->voltage_pkt = adc_get_voltage();
health->current_pkt = current_board->read_current();
@@ -181,6 +176,10 @@ int get_health_pkt(void *dat) {
health->car_harness_status_pkt = car_harness_status;
health->usb_power_mode_pkt = usb_power_mode;
health->safety_mode_pkt = (uint8_t)(current_safety_mode);
health->power_save_enabled_pkt = (uint8_t)(power_save_status == POWER_SAVE_STATUS_ENABLED);
health->fault_status_pkt = fault_status;
health->faults_pkt = faults;
return sizeof(*health);
}
@@ -230,7 +229,7 @@ void usb_cb_ep3_out(void *usbdata, int len, bool hardwired) {
to_push.RIR = d32[dpkt];
uint8_t bus_number = (to_push.RDTR >> 4) & CAN_BUS_NUM_MASK;
can_send(&to_push, bus_number);
can_send(&to_push, bus_number, false);
}
}
@@ -313,6 +312,10 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired)
resp[1] = ((fan_rpm & 0xFF00U) >> 8U);
resp_len = 2;
break;
// **** 0xb3: set phone power
case 0xb3:
current_board->set_phone_power(setup->b.wValue.w > 0U);
break;
// **** 0xc0: get CAN debug info
case 0xc0:
puts("can tx: "); puth(can_tx_cnt);
@@ -366,6 +369,24 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired)
case 0xd2:
resp_len = get_health_pkt(resp);
break;
// **** 0xd3: get first 64 bytes of signature
case 0xd3:
{
resp_len = 64;
char * code = (char*)_app_start;
int code_len = _app_start[0];
(void)memcpy(resp, &code[code_len], resp_len);
}
break;
// **** 0xd4: get second 64 bytes of signature
case 0xd4:
{
resp_len = 64;
char * code = (char*)_app_start;
int code_len = _app_start[0];
(void)memcpy(resp, &code[code_len + 64], resp_len);
}
break;
// **** 0xd6: get version
case 0xd6:
COMPILE_TIME_ASSERT(sizeof(gitversion) <= MAX_RESP_LEN);
@@ -427,8 +448,10 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired)
// **** 0xdc: set safety mode
case 0xdc:
// 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)) {
// Allow SILENT, NOOUTPUT and ELM security mode to be set over wifi.
if (hardwired || (setup->b.wValue.w == SAFETY_SILENT) ||
(setup->b.wValue.w == SAFETY_NOOUTPUT) ||
(setup->b.wValue.w == SAFETY_ELM327)) {
set_safety_mode(setup->b.wValue.w, (uint16_t) setup->b.wIndex.w);
}
break;
@@ -526,6 +549,10 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired)
case 0xe6:
current_board->set_usb_power_mode(setup->b.wValue.w);
break;
// **** 0xe7: set power save state
case 0xe7:
set_power_save_state(setup->b.wValue.w);
break;
// **** 0xf0: do k-line wValue pulse on uart2 for Acura
case 0xf0:
if (setup->b.wValue.w == 1U) {
@@ -640,24 +667,21 @@ void __attribute__ ((noinline)) enable_fpu(void) {
SCB->CPACR |= ((3UL << (10U * 2U)) | (3UL << (11U * 2U)));
}
uint64_t tcnt = 0;
// go into NOOUTPUT when the EON does not send a heartbeat for this amount of seconds.
// go into SILENT when the EON does not send a heartbeat for this amount of seconds.
#define EON_HEARTBEAT_IGNITION_CNT_ON 5U
#define EON_HEARTBEAT_IGNITION_CNT_OFF 2U
// called once per second
// cppcheck-suppress unusedFunction ; used in headers not included in cppcheck
void TIM1_BRK_TIM9_IRQHandler(void) {
void TIM1_BRK_TIM9_IRQ_Handler(void) {
if (TIM9->SR != 0) {
can_live = pending_can_live;
current_board->usb_power_mode_tick(tcnt);
current_board->usb_power_mode_tick(uptime_cnt);
//puth(usart1_dma); puts(" "); puth(DMA2_Stream5->M0AR); puts(" "); puth(DMA2_Stream5->NDTR); puts("\n");
// reset this every 16th pass
if ((tcnt & 0xFU) == 0U) {
if ((uptime_cnt & 0xFU) == 0U) {
pending_can_live = 0;
}
#ifdef DEBUG
@@ -676,30 +700,57 @@ void TIM1_BRK_TIM9_IRQHandler(void) {
// turn off the blue LED, turned on by CAN
// unless we are in power saving mode
current_board->set_led(LED_BLUE, (tcnt & 1U) && (power_save_status == POWER_SAVE_STATUS_ENABLED));
current_board->set_led(LED_BLUE, (uptime_cnt & 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
// check heartbeat counter if we are running EON code.
// if the heartbeat has been gone for a while, go to SILENT safety mode and enter power save
if (heartbeat_counter >= (check_started() ? EON_HEARTBEAT_IGNITION_CNT_ON : EON_HEARTBEAT_IGNITION_CNT_OFF)) {
puts("EON hasn't sent a heartbeat for 0x"); puth(heartbeat_counter); puts(" seconds. Safety is set to NOOUTPUT mode.\n");
if(current_safety_mode != SAFETY_NOOUTPUT){
set_safety_mode(SAFETY_NOOUTPUT, 0U);
puts("EON hasn't sent a heartbeat for 0x");
puth(heartbeat_counter);
puts(" seconds. Safety is set to SILENT mode.\n");
if (current_safety_mode != SAFETY_SILENT) {
set_safety_mode(SAFETY_SILENT, 0U);
}
if (power_save_status != POWER_SAVE_STATUS_ENABLED) {
set_power_save_state(POWER_SAVE_STATUS_ENABLED);
}
}
// enter CDP mode when car starts to ensure we are charging a turned off EON
if (check_started() && (usb_power_mode != USB_POWER_CDP)) {
current_board->set_usb_power_mode(USB_POWER_CDP);
}
#endif
// check registers
check_registers();
// set ignition_can to false after 2s of no CAN seen
if (ignition_can_cnt > 2U) {
ignition_can = false;
};
// on to the next one
tcnt += 1U;
uptime_cnt += 1U;
safety_mode_cnt += 1U;
ignition_can_cnt += 1U;
}
TIM9->SR = 0;
}
int main(void) {
// Init interrupt table
init_interrupts(true);
// 1s timer
REGISTER_INTERRUPT(TIM1_BRK_TIM9_IRQn, TIM1_BRK_TIM9_IRQ_Handler, 2U, FAULT_INTERRUPT_RATE_TIM1)
// shouldn't have interrupts here, but just in case
disable_interrupts();
@@ -760,32 +811,16 @@ int main(void) {
TIM2->EGR = TIM_EGR_UG;
// use TIM2->CNT to read
// 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);
if (err == -1) {
puts("Failed to set safety mode\n");
while (true) {
// if SAFETY_NOOUTPUT isn't succesfully set, we can't continue
}
}
can_silent = ALL_CAN_SILENT;
can_init_all();
// init to SILENT and can silent
set_safety_mode(SAFETY_SILENT, 0);
// enable CAN TXs
current_board->enable_can_transcievers(true);
#ifndef EON
spi_init();
#endif
#ifdef EON
// have to save power
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 (check_started()) {
set_power_save_state(POWER_SAVE_STATUS_ENABLED);
}*/
#endif
// 1hz
timer_init(TIM9, 1464);
NVIC_EnableIRQ(TIM1_BRK_TIM9_IRQn);
@@ -804,19 +839,30 @@ int main(void) {
for (cnt=0;;cnt++) {
if (power_save_status == POWER_SAVE_STATUS_DISABLED) {
int div_mode = ((usb_power_mode == USB_POWER_DCP) ? 4 : 1);
#ifdef DEBUG_FAULTS
if(fault_status == FAULT_STATUS_NONE){
#endif
int div_mode = ((usb_power_mode == USB_POWER_DCP) ? 4 : 1);
// useful for debugging, fade breaks = panda is overloaded
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++) {
current_board->set_led(LED_RED, 1);
if (fade < 512) { delay(fade); } else { delay(1024-fade); }
current_board->set_led(LED_RED, 0);
if (fade < 512) { delay(512-fade); } else { delay(fade-512); }
// useful for debugging, fade breaks = panda is overloaded
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++) {
current_board->set_led(LED_RED, 1);
if (fade < 512) { delay(fade); } else { delay(1024-fade); }
current_board->set_led(LED_RED, 0);
if (fade < 512) { delay(512-fade); } else { delay(fade-512); }
}
}
}
}
#ifdef DEBUG_FAULTS
} else {
current_board->set_led(LED_RED, 1);
delay(512000U);
current_board->set_led(LED_RED, 0);
delay(512000U);
}
#endif
} else {
__WFI();
}