|
|
@ -33,7 +33,7 @@ |
|
|
|
void debug_ring_callback(uart_ring *ring) { |
|
|
|
void debug_ring_callback(uart_ring *ring) { |
|
|
|
char rcv; |
|
|
|
char rcv; |
|
|
|
while (getc(ring, &rcv)) { |
|
|
|
while (getc(ring, &rcv)) { |
|
|
|
putc(ring, rcv); |
|
|
|
(void)putc(ring, rcv); // misra-c2012-17.7: cast to void is ok: debug function
|
|
|
|
|
|
|
|
|
|
|
|
// jump to DFU flash
|
|
|
|
// jump to DFU flash
|
|
|
|
if (rcv == 'z') { |
|
|
|
if (rcv == 'z') { |
|
|
@ -69,9 +69,10 @@ bool is_gpio_started(void) { |
|
|
|
return (GPIOA->IDR & (1U << 1)) == 0; |
|
|
|
return (GPIOA->IDR & (1U << 1)) == 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// cppcheck-suppress unusedFunction ; used in headers not included in cppcheck
|
|
|
|
void EXTI1_IRQHandler(void) { |
|
|
|
void EXTI1_IRQHandler(void) { |
|
|
|
volatile int pr = EXTI->PR & (1U << 1); |
|
|
|
volatile unsigned int pr = EXTI->PR & (1U << 1); |
|
|
|
if ((pr & (1U << 1)) != 0) { |
|
|
|
if ((pr & (1U << 1)) != 0U) { |
|
|
|
#ifdef DEBUG |
|
|
|
#ifdef DEBUG |
|
|
|
puts("got started interrupt\n"); |
|
|
|
puts("got started interrupt\n"); |
|
|
|
#endif |
|
|
|
#endif |
|
|
@ -98,13 +99,14 @@ void started_interrupt_init(void) { |
|
|
|
|
|
|
|
|
|
|
|
int get_health_pkt(void *dat) { |
|
|
|
int get_health_pkt(void *dat) { |
|
|
|
struct __attribute__((packed)) { |
|
|
|
struct __attribute__((packed)) { |
|
|
|
uint32_t voltage; |
|
|
|
uint32_t voltage_pkt; |
|
|
|
uint32_t current; |
|
|
|
uint32_t current_pkt; |
|
|
|
uint8_t started; |
|
|
|
uint8_t started_pkt; |
|
|
|
uint8_t controls_allowed; |
|
|
|
uint8_t controls_allowed_pkt; |
|
|
|
uint8_t gas_interceptor_detected; |
|
|
|
uint8_t gas_interceptor_detected_pkt; |
|
|
|
uint8_t started_signal_detected; |
|
|
|
uint32_t can_send_errs_pkt; |
|
|
|
uint8_t started_alt; |
|
|
|
uint32_t can_fwd_errs_pkt; |
|
|
|
|
|
|
|
uint32_t gmlan_send_errs_pkt; |
|
|
|
} *health = dat; |
|
|
|
} *health = dat; |
|
|
|
|
|
|
|
|
|
|
|
//Voltage will be measured in mv. 5000 = 5V
|
|
|
|
//Voltage will be measured in mv. 5000 = 5V
|
|
|
@ -117,29 +119,28 @@ int get_health_pkt(void *dat) { |
|
|
|
// s = 1000/((4095/3.3)*(1/11)) = 8.8623046875
|
|
|
|
// s = 1000/((4095/3.3)*(1/11)) = 8.8623046875
|
|
|
|
|
|
|
|
|
|
|
|
// Avoid needing floating point math
|
|
|
|
// Avoid needing floating point math
|
|
|
|
health->voltage = (voltage * 8862) / 1000; |
|
|
|
health->voltage_pkt = (voltage * 8862U) / 1000U; |
|
|
|
|
|
|
|
|
|
|
|
health->current = adc_get(ADCCHAN_CURRENT); |
|
|
|
health->current_pkt = adc_get(ADCCHAN_CURRENT); |
|
|
|
int safety_ignition = safety_ignition_hook(); |
|
|
|
int safety_ignition = safety_ignition_hook(); |
|
|
|
if (safety_ignition < 0) { |
|
|
|
if (safety_ignition < 0) { |
|
|
|
//Use the GPIO pin to determine ignition
|
|
|
|
//Use the GPIO pin to determine ignition
|
|
|
|
health->started = is_gpio_started(); |
|
|
|
health->started_pkt = is_gpio_started(); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
//Current safety hooks want to determine ignition (ex: GM)
|
|
|
|
//Current safety hooks want to determine ignition (ex: GM)
|
|
|
|
health->started = safety_ignition; |
|
|
|
health->started_pkt = safety_ignition; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
health->controls_allowed = controls_allowed; |
|
|
|
health->controls_allowed_pkt = controls_allowed; |
|
|
|
health->gas_interceptor_detected = gas_interceptor_detected; |
|
|
|
health->gas_interceptor_detected_pkt = gas_interceptor_detected; |
|
|
|
|
|
|
|
health->can_send_errs_pkt = can_send_errs; |
|
|
|
// DEPRECATED
|
|
|
|
health->can_fwd_errs_pkt = can_fwd_errs; |
|
|
|
health->started_alt = 0; |
|
|
|
health->gmlan_send_errs_pkt = gmlan_send_errs; |
|
|
|
health->started_signal_detected = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return sizeof(*health); |
|
|
|
return sizeof(*health); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int usb_cb_ep1_in(uint8_t *usbdata, int len, bool hardwired) { |
|
|
|
int usb_cb_ep1_in(void *usbdata, int len, bool hardwired) { |
|
|
|
UNUSED(hardwired); |
|
|
|
UNUSED(hardwired); |
|
|
|
CAN_FIFOMailBox_TypeDef *reply = (CAN_FIFOMailBox_TypeDef *)usbdata; |
|
|
|
CAN_FIFOMailBox_TypeDef *reply = (CAN_FIFOMailBox_TypeDef *)usbdata; |
|
|
|
int ilen = 0; |
|
|
|
int ilen = 0; |
|
|
@ -150,13 +151,14 @@ int usb_cb_ep1_in(uint8_t *usbdata, int len, bool hardwired) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// send on serial, first byte to select the ring
|
|
|
|
// send on serial, first byte to select the ring
|
|
|
|
void usb_cb_ep2_out(uint8_t *usbdata, int len, bool hardwired) { |
|
|
|
void usb_cb_ep2_out(void *usbdata, int len, bool hardwired) { |
|
|
|
UNUSED(hardwired); |
|
|
|
UNUSED(hardwired); |
|
|
|
uart_ring *ur = get_ring_by_number(usbdata[0]); |
|
|
|
uint8_t *usbdata8 = (uint8_t *)usbdata; |
|
|
|
|
|
|
|
uart_ring *ur = get_ring_by_number(usbdata8[0]); |
|
|
|
if ((len != 0) && (ur != NULL)) { |
|
|
|
if ((len != 0) && (ur != NULL)) { |
|
|
|
if ((usbdata[0] < 2) || safety_tx_lin_hook(usbdata[0]-2, usbdata+1, len-1)) { |
|
|
|
if ((usbdata8[0] < 2U) || safety_tx_lin_hook(usbdata8[0] - 2U, usbdata8 + 1, len - 1)) { |
|
|
|
for (int i = 1; i < len; i++) { |
|
|
|
for (int i = 1; i < len; i++) { |
|
|
|
while (!putc(ur, usbdata[i])) { |
|
|
|
while (!putc(ur, usbdata8[i])) { |
|
|
|
// wait
|
|
|
|
// wait
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -165,18 +167,16 @@ void usb_cb_ep2_out(uint8_t *usbdata, int len, bool hardwired) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// send on CAN
|
|
|
|
// send on CAN
|
|
|
|
void usb_cb_ep3_out(uint8_t *usbdata, int len, bool hardwired) { |
|
|
|
void usb_cb_ep3_out(void *usbdata, int len, bool hardwired) { |
|
|
|
UNUSED(hardwired); |
|
|
|
UNUSED(hardwired); |
|
|
|
int dpkt = 0; |
|
|
|
int dpkt = 0; |
|
|
|
for (dpkt = 0; dpkt < len; dpkt += 0x10) { |
|
|
|
uint32_t *d32 = (uint32_t *)usbdata; |
|
|
|
uint32_t *tf = (uint32_t*)(&usbdata[dpkt]); |
|
|
|
for (dpkt = 0; dpkt < (len / 4); dpkt += 4) { |
|
|
|
|
|
|
|
|
|
|
|
// make a copy
|
|
|
|
|
|
|
|
CAN_FIFOMailBox_TypeDef to_push; |
|
|
|
CAN_FIFOMailBox_TypeDef to_push; |
|
|
|
to_push.RDHR = tf[3]; |
|
|
|
to_push.RDHR = d32[dpkt + 3]; |
|
|
|
to_push.RDLR = tf[2]; |
|
|
|
to_push.RDLR = d32[dpkt + 2]; |
|
|
|
to_push.RDTR = tf[1]; |
|
|
|
to_push.RDTR = d32[dpkt + 1]; |
|
|
|
to_push.RIR = tf[0]; |
|
|
|
to_push.RIR = d32[dpkt]; |
|
|
|
|
|
|
|
|
|
|
|
uint8_t bus_number = (to_push.RDTR >> 4) & CAN_BUS_NUM_MASK; |
|
|
|
uint8_t bus_number = (to_push.RDTR >> 4) & CAN_BUS_NUM_MASK; |
|
|
|
can_send(&to_push, bus_number); |
|
|
|
can_send(&to_push, bus_number); |
|
|
@ -191,7 +191,7 @@ void usb_cb_enumeration_complete() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) { |
|
|
|
int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) { |
|
|
|
int resp_len = 0; |
|
|
|
unsigned int resp_len = 0; |
|
|
|
uart_ring *ur = NULL; |
|
|
|
uart_ring *ur = NULL; |
|
|
|
int i; |
|
|
|
int i; |
|
|
|
switch (setup->b.bRequest) { |
|
|
|
switch (setup->b.bRequest) { |
|
|
@ -211,8 +211,8 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) |
|
|
|
// **** 0xd0: fetch serial number
|
|
|
|
// **** 0xd0: fetch serial number
|
|
|
|
case 0xd0: |
|
|
|
case 0xd0: |
|
|
|
// addresses are OTP
|
|
|
|
// addresses are OTP
|
|
|
|
if (setup->b.wValue.w == 1) { |
|
|
|
if (setup->b.wValue.w == 1U) { |
|
|
|
memcpy(resp, (void *)0x1fff79c0, 0x10); |
|
|
|
(void)memcpy(resp, (uint8_t *)0x1fff79c0, 0x10); |
|
|
|
resp_len = 0x10; |
|
|
|
resp_len = 0x10; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
get_provision_chunk(resp); |
|
|
|
get_provision_chunk(resp); |
|
|
@ -248,8 +248,8 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) |
|
|
|
// **** 0xd6: get version
|
|
|
|
// **** 0xd6: get version
|
|
|
|
case 0xd6: |
|
|
|
case 0xd6: |
|
|
|
COMPILE_TIME_ASSERT(sizeof(gitversion) <= MAX_RESP_LEN); |
|
|
|
COMPILE_TIME_ASSERT(sizeof(gitversion) <= MAX_RESP_LEN); |
|
|
|
memcpy(resp, gitversion, sizeof(gitversion)); |
|
|
|
(void)memcpy(resp, gitversion, sizeof(gitversion)); |
|
|
|
resp_len = sizeof(gitversion)-1; |
|
|
|
resp_len = sizeof(gitversion) - 1U; |
|
|
|
break; |
|
|
|
break; |
|
|
|
// **** 0xd8: reset ST
|
|
|
|
// **** 0xd8: reset ST
|
|
|
|
case 0xd8: |
|
|
|
case 0xd8: |
|
|
@ -257,9 +257,9 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) |
|
|
|
break; |
|
|
|
break; |
|
|
|
// **** 0xd9: set ESP power
|
|
|
|
// **** 0xd9: set ESP power
|
|
|
|
case 0xd9: |
|
|
|
case 0xd9: |
|
|
|
if (setup->b.wValue.w == 1) { |
|
|
|
if (setup->b.wValue.w == 1U) { |
|
|
|
set_esp_mode(ESP_ENABLED); |
|
|
|
set_esp_mode(ESP_ENABLED); |
|
|
|
} else if (setup->b.wValue.w == 2) { |
|
|
|
} else if (setup->b.wValue.w == 2U) { |
|
|
|
set_esp_mode(ESP_BOOTMODE); |
|
|
|
set_esp_mode(ESP_BOOTMODE); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
set_esp_mode(ESP_DISABLED); |
|
|
|
set_esp_mode(ESP_DISABLED); |
|
|
@ -269,7 +269,7 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) |
|
|
|
case 0xda: |
|
|
|
case 0xda: |
|
|
|
set_esp_mode(ESP_DISABLED); |
|
|
|
set_esp_mode(ESP_DISABLED); |
|
|
|
delay(1000000); |
|
|
|
delay(1000000); |
|
|
|
if (setup->b.wValue.w == 1) { |
|
|
|
if (setup->b.wValue.w == 1U) { |
|
|
|
set_esp_mode(ESP_BOOTMODE); |
|
|
|
set_esp_mode(ESP_BOOTMODE); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
set_esp_mode(ESP_ENABLED); |
|
|
|
set_esp_mode(ESP_ENABLED); |
|
|
@ -279,12 +279,14 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) |
|
|
|
break; |
|
|
|
break; |
|
|
|
// **** 0xdb: set GMLAN multiplexing mode
|
|
|
|
// **** 0xdb: set GMLAN multiplexing mode
|
|
|
|
case 0xdb: |
|
|
|
case 0xdb: |
|
|
|
if (setup->b.wValue.w == 1) { |
|
|
|
if (setup->b.wValue.w == 1U) { |
|
|
|
// GMLAN ON
|
|
|
|
// GMLAN ON
|
|
|
|
if (setup->b.wIndex.w == 1) { |
|
|
|
if (setup->b.wIndex.w == 1U) { |
|
|
|
can_set_gmlan(1); |
|
|
|
can_set_gmlan(1); |
|
|
|
} else if (setup->b.wIndex.w == 2) { |
|
|
|
} else if (setup->b.wIndex.w == 2U) { |
|
|
|
can_set_gmlan(2); |
|
|
|
can_set_gmlan(2); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
puts("Invalid bus num for GMLAN CAN set\n"); |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
can_set_gmlan(-1); |
|
|
|
can_set_gmlan(-1); |
|
|
@ -296,27 +298,33 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) |
|
|
|
// and it's blocked over WiFi
|
|
|
|
// and it's blocked over WiFi
|
|
|
|
// Allow ELM security mode to be set over wifi.
|
|
|
|
// Allow ELM security mode to be set over wifi.
|
|
|
|
if (hardwired || (setup->b.wValue.w == SAFETY_NOOUTPUT) || (setup->b.wValue.w == SAFETY_ELM327)) { |
|
|
|
if (hardwired || (setup->b.wValue.w == SAFETY_NOOUTPUT) || (setup->b.wValue.w == SAFETY_ELM327)) { |
|
|
|
safety_set_mode(setup->b.wValue.w, (int16_t)setup->b.wIndex.w); |
|
|
|
int err = safety_set_mode(setup->b.wValue.w, (int16_t)setup->b.wIndex.w); |
|
|
|
if (safety_ignition_hook() != -1) { |
|
|
|
if (err == -1) { |
|
|
|
// if the ignition hook depends on something other than the started GPIO
|
|
|
|
puts("Error: safety set mode failed\n"); |
|
|
|
// we have to disable power savings (fix for GM and Tesla)
|
|
|
|
} else { |
|
|
|
set_power_save_state(POWER_SAVE_STATUS_DISABLED); |
|
|
|
#ifndef EON |
|
|
|
} |
|
|
|
// always LIVE on EON
|
|
|
|
#ifndef EON |
|
|
|
switch (setup->b.wValue.w) { |
|
|
|
// always LIVE on EON
|
|
|
|
case SAFETY_NOOUTPUT: |
|
|
|
switch (setup->b.wValue.w) { |
|
|
|
can_silent = ALL_CAN_SILENT; |
|
|
|
case SAFETY_NOOUTPUT: |
|
|
|
break; |
|
|
|
can_silent = ALL_CAN_SILENT; |
|
|
|
case SAFETY_ELM327: |
|
|
|
break; |
|
|
|
can_silent = ALL_CAN_BUT_MAIN_SILENT; |
|
|
|
case SAFETY_ELM327: |
|
|
|
break; |
|
|
|
can_silent = ALL_CAN_BUT_MAIN_SILENT; |
|
|
|
default: |
|
|
|
break; |
|
|
|
can_silent = ALL_CAN_LIVE; |
|
|
|
default: |
|
|
|
break; |
|
|
|
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
|
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
can_init_all(); |
|
|
|
can_init_all(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
break; |
|
|
|
// **** 0xdd: enable can forwarding
|
|
|
|
// **** 0xdd: enable can forwarding
|
|
|
@ -326,8 +334,10 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) |
|
|
|
if ((setup->b.wValue.w < BUS_MAX) && (setup->b.wIndex.w < BUS_MAX) && |
|
|
|
if ((setup->b.wValue.w < BUS_MAX) && (setup->b.wIndex.w < BUS_MAX) && |
|
|
|
(setup->b.wValue.w != setup->b.wIndex.w)) { // set forwarding
|
|
|
|
(setup->b.wValue.w != setup->b.wIndex.w)) { // set forwarding
|
|
|
|
can_set_forwarding(setup->b.wValue.w, setup->b.wIndex.w & CAN_BUS_NUM_MASK); |
|
|
|
can_set_forwarding(setup->b.wValue.w, setup->b.wIndex.w & CAN_BUS_NUM_MASK); |
|
|
|
} else if((setup->b.wValue.w < BUS_MAX) && (setup->b.wIndex.w == 0xFF)){ //Clear Forwarding
|
|
|
|
} else if((setup->b.wValue.w < BUS_MAX) && (setup->b.wIndex.w == 0xFFU)){ //Clear Forwarding
|
|
|
|
can_set_forwarding(setup->b.wValue.w, -1); |
|
|
|
can_set_forwarding(setup->b.wValue.w, -1); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
puts("Invalid CAN bus forwarding\n"); |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
break; |
|
|
|
// **** 0xde: set can bitrate
|
|
|
|
// **** 0xde: set can bitrate
|
|
|
@ -340,7 +350,7 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) |
|
|
|
// **** 0xdf: set long controls allowed
|
|
|
|
// **** 0xdf: set long controls allowed
|
|
|
|
case 0xdf: |
|
|
|
case 0xdf: |
|
|
|
if (hardwired) { |
|
|
|
if (hardwired) { |
|
|
|
long_controls_allowed = setup->b.wValue.w & 1; |
|
|
|
long_controls_allowed = setup->b.wValue.w & 1U; |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
break; |
|
|
|
// **** 0xe0: uart read
|
|
|
|
// **** 0xe0: uart read
|
|
|
@ -401,15 +411,15 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) |
|
|
|
break; |
|
|
|
break; |
|
|
|
// **** 0xe5: set CAN loopback (for testing)
|
|
|
|
// **** 0xe5: set CAN loopback (for testing)
|
|
|
|
case 0xe5: |
|
|
|
case 0xe5: |
|
|
|
can_loopback = (setup->b.wValue.w > 0); |
|
|
|
can_loopback = (setup->b.wValue.w > 0U); |
|
|
|
can_init_all(); |
|
|
|
can_init_all(); |
|
|
|
break; |
|
|
|
break; |
|
|
|
// **** 0xe6: set USB power
|
|
|
|
// **** 0xe6: set USB power
|
|
|
|
case 0xe6: |
|
|
|
case 0xe6: |
|
|
|
if (setup->b.wValue.w == 1) { |
|
|
|
if (setup->b.wValue.w == 1U) { |
|
|
|
puts("user setting CDP mode\n"); |
|
|
|
puts("user setting CDP mode\n"); |
|
|
|
set_usb_power_mode(USB_POWER_CDP); |
|
|
|
set_usb_power_mode(USB_POWER_CDP); |
|
|
|
} else if (setup->b.wValue.w == 2) { |
|
|
|
} else if (setup->b.wValue.w == 2U) { |
|
|
|
puts("user setting DCP mode\n"); |
|
|
|
puts("user setting DCP mode\n"); |
|
|
|
set_usb_power_mode(USB_POWER_DCP); |
|
|
|
set_usb_power_mode(USB_POWER_DCP); |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -419,7 +429,7 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) |
|
|
|
break; |
|
|
|
break; |
|
|
|
// **** 0xf0: do k-line wValue pulse on uart2 for Acura
|
|
|
|
// **** 0xf0: do k-line wValue pulse on uart2 for Acura
|
|
|
|
case 0xf0: |
|
|
|
case 0xf0: |
|
|
|
if (setup->b.wValue.w == 1) { |
|
|
|
if (setup->b.wValue.w == 1U) { |
|
|
|
GPIOC->ODR &= ~(1U << 10); |
|
|
|
GPIOC->ODR &= ~(1U << 10); |
|
|
|
GPIOC->MODER &= ~GPIO_MODER_MODER10_1; |
|
|
|
GPIOC->MODER &= ~GPIO_MODER_MODER10_1; |
|
|
|
GPIOC->MODER |= GPIO_MODER_MODER10_0; |
|
|
|
GPIOC->MODER |= GPIO_MODER_MODER10_0; |
|
|
@ -431,7 +441,7 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) |
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 80; i++) { |
|
|
|
for (i = 0; i < 80; i++) { |
|
|
|
delay(8000); |
|
|
|
delay(8000); |
|
|
|
if (setup->b.wValue.w == 1) { |
|
|
|
if (setup->b.wValue.w == 1U) { |
|
|
|
GPIOC->ODR |= (1U << 10); |
|
|
|
GPIOC->ODR |= (1U << 10); |
|
|
|
GPIOC->ODR &= ~(1U << 10); |
|
|
|
GPIOC->ODR &= ~(1U << 10); |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -440,7 +450,7 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (setup->b.wValue.w == 1) { |
|
|
|
if (setup->b.wValue.w == 1U) { |
|
|
|
GPIOC->MODER &= ~GPIO_MODER_MODER10_0; |
|
|
|
GPIOC->MODER &= ~GPIO_MODER_MODER10_0; |
|
|
|
GPIOC->MODER |= GPIO_MODER_MODER10_1; |
|
|
|
GPIOC->MODER |= GPIO_MODER_MODER10_1; |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -452,12 +462,14 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) |
|
|
|
break; |
|
|
|
break; |
|
|
|
// **** 0xf1: Clear CAN ring buffer.
|
|
|
|
// **** 0xf1: Clear CAN ring buffer.
|
|
|
|
case 0xf1: |
|
|
|
case 0xf1: |
|
|
|
if (setup->b.wValue.w == 0xFFFF) { |
|
|
|
if (setup->b.wValue.w == 0xFFFFU) { |
|
|
|
puts("Clearing CAN Rx queue\n"); |
|
|
|
puts("Clearing CAN Rx queue\n"); |
|
|
|
can_clear(&can_rx_q); |
|
|
|
can_clear(&can_rx_q); |
|
|
|
} else if (setup->b.wValue.w < BUS_MAX) { |
|
|
|
} else if (setup->b.wValue.w < BUS_MAX) { |
|
|
|
puts("Clearing CAN Tx queue\n"); |
|
|
|
puts("Clearing CAN Tx queue\n"); |
|
|
|
can_clear(can_queues[setup->b.wValue.w]); |
|
|
|
can_clear(can_queues[setup->b.wValue.w]); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
puts("Clearing CAN CAN ring buffer failed: wrong bus number\n"); |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
break; |
|
|
|
// **** 0xf2: Clear UART ring buffer.
|
|
|
|
// **** 0xf2: Clear UART ring buffer.
|
|
|
@ -479,6 +491,7 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) |
|
|
|
return resp_len; |
|
|
|
return resp_len; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef EON |
|
|
|
int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) { |
|
|
|
int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) { |
|
|
|
// data[0] = endpoint
|
|
|
|
// data[0] = endpoint
|
|
|
|
// data[2] = length
|
|
|
|
// data[2] = length
|
|
|
@ -508,26 +521,28 @@ int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) { |
|
|
|
} |
|
|
|
} |
|
|
|
return resp_len; |
|
|
|
return resp_len; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
// ***************************** main code *****************************
|
|
|
|
// ***************************** main code *****************************
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// cppcheck-suppress unusedFunction ; used in headers not included in cppcheck
|
|
|
|
void __initialize_hardware_early(void) { |
|
|
|
void __initialize_hardware_early(void) { |
|
|
|
early(); |
|
|
|
early(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void __attribute__ ((noinline)) enable_fpu(void) { |
|
|
|
void __attribute__ ((noinline)) enable_fpu(void) { |
|
|
|
// enable the FPU
|
|
|
|
// enable the FPU
|
|
|
|
SCB->CPACR |= ((3UL << (10U * 2)) | (3UL << (11U * 2))); |
|
|
|
SCB->CPACR |= ((3UL << (10U * 2U)) | (3UL << (11U * 2U))); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
uint64_t tcnt = 0; |
|
|
|
uint64_t tcnt = 0; |
|
|
|
uint64_t marker = 0; |
|
|
|
uint64_t marker = 0; |
|
|
|
|
|
|
|
|
|
|
|
// called once per second
|
|
|
|
// called once per second
|
|
|
|
|
|
|
|
// cppcheck-suppress unusedFunction ; used in headers not included in cppcheck
|
|
|
|
void TIM3_IRQHandler(void) { |
|
|
|
void TIM3_IRQHandler(void) { |
|
|
|
#define CURRENT_THRESHOLD 0xF00 |
|
|
|
#define CURRENT_THRESHOLD 0xF00U |
|
|
|
#define CLICKS 5 // 5 seconds to switch modes
|
|
|
|
#define CLICKS 5U // 5 seconds to switch modes
|
|
|
|
|
|
|
|
|
|
|
|
if (TIM3->SR != 0) { |
|
|
|
if (TIM3->SR != 0) { |
|
|
|
can_live = pending_can_live; |
|
|
|
can_live = pending_can_live; |
|
|
@ -538,7 +553,7 @@ void TIM3_IRQHandler(void) { |
|
|
|
|
|
|
|
|
|
|
|
switch (usb_power_mode) { |
|
|
|
switch (usb_power_mode) { |
|
|
|
case USB_POWER_CLIENT: |
|
|
|
case USB_POWER_CLIENT: |
|
|
|
if ((tcnt-marker) >= CLICKS) { |
|
|
|
if ((tcnt - marker) >= CLICKS) { |
|
|
|
if (!is_enumerated) { |
|
|
|
if (!is_enumerated) { |
|
|
|
puts("USBP: didn't enumerate, switching to CDP mode\n"); |
|
|
|
puts("USBP: didn't enumerate, switching to CDP mode\n"); |
|
|
|
// switch to CDP
|
|
|
|
// switch to CDP
|
|
|
@ -594,7 +609,7 @@ void TIM3_IRQHandler(void) { |
|
|
|
puts("\n");*/ |
|
|
|
puts("\n");*/ |
|
|
|
|
|
|
|
|
|
|
|
// reset this every 16th pass
|
|
|
|
// reset this every 16th pass
|
|
|
|
if ((tcnt&0xF) == 0) { |
|
|
|
if ((tcnt & 0xFU) == 0U) { |
|
|
|
pending_can_live = 0; |
|
|
|
pending_can_live = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
#ifdef DEBUG |
|
|
|
#ifdef DEBUG |
|
|
@ -609,10 +624,10 @@ void TIM3_IRQHandler(void) { |
|
|
|
|
|
|
|
|
|
|
|
// turn off the blue LED, turned on by CAN
|
|
|
|
// turn off the blue LED, turned on by CAN
|
|
|
|
// unless we are in power saving mode
|
|
|
|
// unless we are in power saving mode
|
|
|
|
set_led(LED_BLUE, (tcnt & 1) && (power_save_status == POWER_SAVE_STATUS_ENABLED)); |
|
|
|
set_led(LED_BLUE, (tcnt & 1U) && (power_save_status == POWER_SAVE_STATUS_ENABLED)); |
|
|
|
|
|
|
|
|
|
|
|
// on to the next one
|
|
|
|
// on to the next one
|
|
|
|
tcnt += 1; |
|
|
|
tcnt += 1U; |
|
|
|
} |
|
|
|
} |
|
|
|
TIM3->SR = 0; |
|
|
|
TIM3->SR = 0; |
|
|
|
} |
|
|
|
} |
|
|
@ -680,7 +695,13 @@ int main(void) { |
|
|
|
|
|
|
|
|
|
|
|
// default to silent mode to prevent issues with Ford
|
|
|
|
// 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
|
|
|
|
// hardcode a specific safety mode if you want to force the panda to be in a specific mode
|
|
|
|
safety_set_mode(SAFETY_NOOUTPUT, 0); |
|
|
|
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
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
#ifdef EON |
|
|
|
#ifdef EON |
|
|
|
// if we're on an EON, it's fine for CAN to be live for fingerprinting
|
|
|
|
// if we're on an EON, it's fine for CAN to be live for fingerprinting
|
|
|
|
can_silent = ALL_CAN_LIVE; |
|
|
|
can_silent = ALL_CAN_LIVE; |
|
|
|