//#define EON
//#define PANDA
// ********************* Includes *********************
# include "config.h"
# include "obj/gitversion.h"
# include "main_declarations.h"
# include "critical.h"
# include "libc.h"
# include "provision.h"
# include "faults.h"
# include "drivers/registers.h"
# include "drivers/interrupts.h"
# include "drivers/llcan.h"
# include "drivers/llgpio.h"
# include "drivers/adc.h"
# include "drivers/pwm.h"
# include "board.h"
# include "drivers/uart.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"
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 ) {
return current_board - > check_ignition ( ) | | ignition_can ;
}
void debug_ring_callback ( uart_ring * ring ) {
char rcv ;
while ( getc ( ring , & rcv ) ) {
( void ) putc ( ring , rcv ) ; // misra-c2012-17.7: cast to void is ok: debug function
// 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 ' ) {
NVIC_SystemReset ( ) ;
}
// enable CDP mode
if ( rcv = = ' C ' ) {
puts ( " switching USB to CDP mode \n " ) ;
current_board - > set_usb_power_mode ( USB_POWER_CDP ) ;
}
if ( rcv = = ' c ' ) {
puts ( " switching USB to client mode \n " ) ;
current_board - > set_usb_power_mode ( USB_POWER_CLIENT ) ;
}
if ( rcv = = ' D ' ) {
puts ( " switching USB to DCP mode \n " ) ;
current_board - > set_usb_power_mode ( USB_POWER_DCP ) ;
}
}
}
// ****************************** safety mode ******************************
// this is the only way to leave silent mode
void set_safety_mode ( uint16_t mode , int16_t param ) {
uint16_t mode_copy = mode ;
int err = set_safety_hooks ( mode_copy , param ) ;
if ( err = = - 1 ) {
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
}
}
}
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 ) {
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 ( ) ;
//Use the GPIO pin to determine ignition or use a CAN based logic
health - > ignition_line_pkt = ( uint8_t ) ( current_board - > check_ignition ( ) ) ;
health - > ignition_can_pkt = ( uint8_t ) ( ignition_can ) ;
health - > controls_allowed_pkt = controls_allowed ;
health - > gas_interceptor_detected_pkt = gas_interceptor_detected ;
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 ;
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 ) ;
}
int get_rtc_pkt ( void * dat ) {
timestamp_t t = rtc_get_time ( ) ;
( void ) memcpy ( dat , & t , sizeof ( t ) ) ;
return sizeof ( t ) ;
}
int usb_cb_ep1_in ( void * usbdata , int len , bool hardwired ) {
UNUSED ( hardwired ) ;
CAN_FIFOMailBox_TypeDef * reply = ( CAN_FIFOMailBox_TypeDef * ) usbdata ;
int ilen = 0 ;
while ( ilen < MIN ( len / 0x10 , 4 ) & & can_pop ( & can_rx_q , & reply [ ilen ] ) ) {
ilen + + ;
}
return ilen * 0x10 ;
}
// send on serial, first byte to select the ring
void usb_cb_ep2_out ( void * usbdata , int len , bool hardwired ) {
UNUSED ( hardwired ) ;
uint8_t * usbdata8 = ( uint8_t * ) usbdata ;
uart_ring * ur = get_ring_by_number ( usbdata8 [ 0 ] ) ;
if ( ( len ! = 0 ) & & ( ur ! = NULL ) ) {
if ( ( usbdata8 [ 0 ] < 2U ) | | safety_tx_lin_hook ( usbdata8 [ 0 ] - 2U , & usbdata8 [ 1 ] , len - 1 ) ) {
for ( int i = 1 ; i < len ; i + + ) {
while ( ! putc ( ur , usbdata8 [ i ] ) ) {
// wait
}
}
}
}
}
// send on CAN
void usb_cb_ep3_out ( void * usbdata , int len , bool hardwired ) {
UNUSED ( hardwired ) ;
int dpkt = 0 ;
uint32_t * d32 = ( uint32_t * ) usbdata ;
for ( dpkt = 0 ; dpkt < ( len / 4 ) ; dpkt + = 4 ) {
CAN_FIFOMailBox_TypeDef to_push ;
to_push . RDHR = d32 [ dpkt + 3 ] ;
to_push . RDLR = d32 [ dpkt + 2 ] ;
to_push . RDTR = d32 [ dpkt + 1 ] ;
to_push . RIR = d32 [ dpkt ] ;
uint8_t bus_number = ( to_push . RDTR > > 4 ) & CAN_BUS_NUM_MASK ;
can_send ( & to_push , bus_number , false ) ;
}
}
void usb_cb_enumeration_complete ( ) {
puts ( " USB enumeration complete \n " ) ;
is_enumerated = 1 ;
}
int usb_cb_control_msg ( USB_Setup_TypeDef * setup , uint8_t * resp , bool hardwired ) {
unsigned int resp_len = 0 ;
uart_ring * ur = NULL ;
int i ;
timestamp_t t ;
switch ( setup - > b . bRequest ) {
// **** 0xa0: get rtc time
case 0xa0 :
resp_len = get_rtc_pkt ( resp ) ;
break ;
// **** 0xa1: set rtc year
case 0xa1 :
t = rtc_get_time ( ) ;
t . year = setup - > b . wValue . w ;
rtc_set_time ( t ) ;
break ;
// **** 0xa2: set rtc month
case 0xa2 :
t = rtc_get_time ( ) ;
t . month = setup - > b . wValue . w ;
rtc_set_time ( t ) ;
break ;
// **** 0xa3: set rtc day
case 0xa3 :
t = rtc_get_time ( ) ;
t . day = setup - > b . wValue . w ;
rtc_set_time ( t ) ;
break ;
// **** 0xa4: set rtc weekday
case 0xa4 :
t = rtc_get_time ( ) ;
t . weekday = setup - > b . wValue . w ;
rtc_set_time ( t ) ;
break ;
// **** 0xa5: set rtc hour
case 0xa5 :
t = rtc_get_time ( ) ;
t . hour = setup - > b . wValue . w ;
rtc_set_time ( t ) ;
break ;
// **** 0xa6: set rtc minute
case 0xa6 :
t = rtc_get_time ( ) ;
t . minute = setup - > b . wValue . w ;
rtc_set_time ( t ) ;
break ;
// **** 0xa7: set rtc second
case 0xa7 :
t = rtc_get_time ( ) ;
t . second = setup - > b . wValue . w ;
rtc_set_time ( t ) ;
break ;
// **** 0xb0: set IR power
case 0xb0 :
if ( power_save_status = = POWER_SAVE_STATUS_DISABLED ) {
current_board - > set_ir_power ( setup - > b . wValue . w ) ;
} else {
puts ( " Setting IR power not allowed in power saving mode \n " ) ;
}
break ;
// **** 0xb1: set fan power
case 0xb1 :
if ( power_save_status = = POWER_SAVE_STATUS_DISABLED ) {
current_board - > set_fan_power ( setup - > b . wValue . w ) ;
} else {
puts ( " Setting fan power not allowed in power saving mode \n " ) ;
}
break ;
// **** 0xb2: get fan rpm
case 0xb2 :
resp [ 0 ] = ( fan_rpm & 0x00FFU ) ;
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 ) ;
puts ( " txd: " ) ; puth ( can_txd_cnt ) ;
puts ( " rx: " ) ; puth ( can_rx_cnt ) ;
puts ( " err: " ) ; puth ( can_err_cnt ) ;
puts ( " \n " ) ;
break ;
// **** 0xc1: get hardware type
case 0xc1 :
resp [ 0 ] = hw_type ;
resp_len = 1 ;
break ;
// **** 0xd0: fetch serial number
case 0xd0 :
// addresses are OTP
if ( setup - > b . wValue . w = = 1U ) {
( void ) memcpy ( resp , ( uint8_t * ) 0x1fff79c0 , 0x10 ) ;
resp_len = 0x10 ;
} else {
get_provision_chunk ( resp ) ;
resp_len = PROVISION_CHUNK_LEN ;
}
break ;
// **** 0xd1: enter bootloader mode
case 0xd1 :
// this allows reflashing of the bootstub
// so it's blocked over wifi
switch ( setup - > b . wValue . w ) {
case 0 :
// only allow bootloader entry on debug builds
# ifdef ALLOW_DEBUG
if ( hardwired ) {
puts ( " -> entering bootloader \n " ) ;
enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC ;
NVIC_SystemReset ( ) ;
}
# endif
break ;
case 1 :
puts ( " -> entering softloader \n " ) ;
enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC ;
NVIC_SystemReset ( ) ;
break ;
default :
puts ( " Bootloader mode invalid \n " ) ;
break ;
}
break ;
// **** 0xd2: get health packet
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 ) ;
( void ) memcpy ( resp , gitversion , sizeof ( gitversion ) ) ;
resp_len = sizeof ( gitversion ) - 1U ;
break ;
// **** 0xd8: reset ST
case 0xd8 :
NVIC_SystemReset ( ) ;
break ;
// **** 0xd9: set ESP power
case 0xd9 :
if ( setup - > b . wValue . w = = 1U ) {
current_board - > set_esp_gps_mode ( ESP_GPS_ENABLED ) ;
} else if ( setup - > b . wValue . w = = 2U ) {
current_board - > set_esp_gps_mode ( ESP_GPS_BOOTMODE ) ;
} else {
current_board - > set_esp_gps_mode ( ESP_GPS_DISABLED ) ;
}
break ;
// **** 0xda: reset ESP, with optional boot mode
case 0xda :
current_board - > set_esp_gps_mode ( ESP_GPS_DISABLED ) ;
delay ( 1000000 ) ;
if ( setup - > b . wValue . w = = 1U ) {
current_board - > set_esp_gps_mode ( ESP_GPS_BOOTMODE ) ;
} else {
current_board - > set_esp_gps_mode ( ESP_GPS_ENABLED ) ;
}
delay ( 1000000 ) ;
current_board - > set_esp_gps_mode ( ESP_GPS_ENABLED ) ;
break ;
// **** 0xdb: set GMLAN (white/grey) or OBD CAN (black) multiplexing mode
case 0xdb :
if ( board_has_obd ( ) ) {
if ( setup - > b . wValue . w = = 1U ) {
// Enable OBD CAN
current_board - > set_can_mode ( CAN_MODE_OBD_CAN2 ) ;
} else {
// Disable OBD CAN
current_board - > set_can_mode ( CAN_MODE_NORMAL ) ;
}
} else {
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 :
// Blocked over WiFi.
// 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 ;
// **** 0xdd: enable can forwarding
case 0xdd :
// wValue = Can Bus Num to forward from
// wIndex = Can Bus Num to forward to
if ( ( setup - > b . wValue . w < BUS_MAX ) & & ( setup - > b . wIndex . w < BUS_MAX ) & &
( 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 ) ;
} else if ( ( setup - > b . wValue . w < BUS_MAX ) & & ( setup - > b . wIndex . w = = 0xFFU ) ) { //Clear Forwarding
can_set_forwarding ( setup - > b . wValue . w , - 1 ) ;
} else {
puts ( " Invalid CAN bus forwarding \n " ) ;
}
break ;
// **** 0xde: set can bitrate
case 0xde :
if ( setup - > b . wValue . w < BUS_MAX ) {
can_speed [ setup - > b . wValue . w ] = setup - > b . wIndex . w ;
can_init ( CAN_NUM_FROM_BUS_NUM ( setup - > b . wValue . w ) ) ;
}
break ;
// **** 0xdf: set long controls allowed
case 0xdf :
if ( hardwired ) {
long_controls_allowed = setup - > b . wValue . w & 1U ;
}
break ;
// **** 0xe0: uart read
case 0xe0 :
ur = get_ring_by_number ( setup - > b . wValue . w ) ;
if ( ! ur ) {
break ;
}
// TODO: Remove this again and fix boardd code to hande the message bursts instead of single chars
if ( ur = = & uart_ring_esp_gps ) {
dma_pointer_handler ( ur , DMA2_Stream5 - > NDTR ) ;
}
// read
while ( ( resp_len < MIN ( setup - > b . wLength . w , MAX_RESP_LEN ) ) & &
getc ( ur , ( char * ) & resp [ resp_len ] ) ) {
+ + resp_len ;
}
break ;
// **** 0xe1: uart set baud rate
case 0xe1 :
ur = get_ring_by_number ( setup - > b . wValue . w ) ;
if ( ! ur ) {
break ;
}
uart_set_baud ( ur - > uart , setup - > b . wIndex . w ) ;
break ;
// **** 0xe2: uart set parity
case 0xe2 :
ur = get_ring_by_number ( setup - > b . wValue . w ) ;
if ( ! ur ) {
break ;
}
switch ( setup - > b . wIndex . w ) {
case 0 :
// disable parity, 8-bit
ur - > uart - > CR1 & = ~ ( USART_CR1_PCE | USART_CR1_M ) ;
break ;
case 1 :
// even parity, 9-bit
ur - > uart - > CR1 & = ~ USART_CR1_PS ;
ur - > uart - > CR1 | = USART_CR1_PCE | USART_CR1_M ;
break ;
case 2 :
// odd parity, 9-bit
ur - > uart - > CR1 | = USART_CR1_PS ;
ur - > uart - > CR1 | = USART_CR1_PCE | USART_CR1_M ;
break ;
default :
break ;
}
break ;
// **** 0xe4: uart set baud rate extended
case 0xe4 :
ur = get_ring_by_number ( setup - > b . wValue . w ) ;
if ( ! ur ) {
break ;
}
uart_set_baud ( ur - > uart , ( int ) setup - > b . wIndex . w * 300 ) ;
break ;
// **** 0xe5: set CAN loopback (for testing)
case 0xe5 :
can_loopback = ( setup - > b . wValue . w > 0U ) ;
can_init_all ( ) ;
break ;
// **** 0xe6: set USB power
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 ) {
GPIOC - > ODR & = ~ ( 1U < < 10 ) ;
GPIOC - > MODER & = ~ GPIO_MODER_MODER10_1 ;
GPIOC - > MODER | = GPIO_MODER_MODER10_0 ;
} else {
GPIOC - > ODR & = ~ ( 1U < < 12 ) ;
GPIOC - > MODER & = ~ GPIO_MODER_MODER12_1 ;
GPIOC - > MODER | = GPIO_MODER_MODER12_0 ;
}
for ( i = 0 ; i < 80 ; i + + ) {
delay ( 8000 ) ;
if ( setup - > b . wValue . w = = 1U ) {
GPIOC - > ODR | = ( 1U < < 10 ) ;
GPIOC - > ODR & = ~ ( 1U < < 10 ) ;
} else {
GPIOC - > ODR | = ( 1U < < 12 ) ;
GPIOC - > ODR & = ~ ( 1U < < 12 ) ;
}
}
if ( setup - > b . wValue . w = = 1U ) {
GPIOC - > MODER & = ~ GPIO_MODER_MODER10_0 ;
GPIOC - > MODER | = GPIO_MODER_MODER10_1 ;
} else {
GPIOC - > MODER & = ~ GPIO_MODER_MODER12_0 ;
GPIOC - > MODER | = GPIO_MODER_MODER12_1 ;
}
delay ( 140 * 9000 ) ;
break ;
// **** 0xf1: Clear CAN ring buffer.
case 0xf1 :
if ( setup - > b . wValue . w = = 0xFFFFU ) {
puts ( " Clearing CAN Rx queue \n " ) ;
can_clear ( & can_rx_q ) ;
} else if ( setup - > b . wValue . w < BUS_MAX ) {
puts ( " Clearing CAN Tx queue \n " ) ;
can_clear ( can_queues [ setup - > b . wValue . w ] ) ;
} else {
puts ( " Clearing CAN CAN ring buffer failed: wrong bus number \n " ) ;
}
break ;
// **** 0xf2: Clear UART ring buffer.
case 0xf2 :
{
uart_ring * rb = get_ring_by_number ( setup - > b . wValue . w ) ;
if ( rb ! = NULL ) {
puts ( " Clearing UART queue. \n " ) ;
clear_uart_buff ( rb ) ;
}
break ;
}
// **** 0xf3: Heartbeat. Resets heartbeat counter.
case 0xf3 :
{
heartbeat_counter = 0U ;
break ;
}
default :
puts ( " NO HANDLER " ) ;
puth ( setup - > b . bRequest ) ;
puts ( " \n " ) ;
break ;
}
return resp_len ;
}
# ifndef EON
int spi_cb_rx ( uint8_t * data , int len , uint8_t * data_out ) {
// data[0] = endpoint
// data[2] = length
// data[4:] = data
UNUSED ( len ) ;
int resp_len = 0 ;
switch ( data [ 0 ] ) {
case 0 :
// control transfer
resp_len = usb_cb_control_msg ( ( USB_Setup_TypeDef * ) ( data + 4 ) , data_out , 0 ) ;
break ;
case 1 :
// ep 1, read
resp_len = usb_cb_ep1_in ( data_out , 0x40 , 0 ) ;
break ;
case 2 :
// ep 2, send serial
usb_cb_ep2_out ( data + 4 , data [ 2 ] , 0 ) ;
break ;
case 3 :
// ep 3, send CAN
usb_cb_ep3_out ( data + 4 , data [ 2 ] , 0 ) ;
break ;
default :
puts ( " SPI data invalid " ) ;
break ;
}
return resp_len ;
}
# endif
// ***************************** main code *****************************
// cppcheck-suppress unusedFunction ; used in headers not included in cppcheck
void __initialize_hardware_early ( void ) {
early ( ) ;
}
void __attribute__ ( ( noinline ) ) enable_fpu ( void ) {
// enable the FPU
SCB - > CPACR | = ( ( 3UL < < ( 10U * 2U ) ) | ( 3UL < < ( 11U * 2U ) ) ) ;
}
// 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
void TIM1_BRK_TIM9_IRQ_Handler ( void ) {
if ( TIM9 - > SR ! = 0 ) {
can_live = pending_can_live ;
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 ( ( uptime_cnt & 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 " ) ;
# endif
// Tick fan driver
fan_tick ( ) ;
//puts("Fan speed: "); puth((unsigned int) fan_rpm); puts("rpm\n");
// set green LED to be 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
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 ;
}
# 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 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
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 ( ) ;
// init early devices
clock_init ( ) ;
peripherals_init ( ) ;
detect_configuration ( ) ;
detect_board_type ( ) ;
adc_init ( ) ;
// print hello
puts ( " \n \n \n ************************ MAIN START ************************ \n " ) ;
// check for non-supported board types
if ( hw_type = = HW_TYPE_UNKNOWN ) {
puts ( " Unsupported board type \n " ) ;
while ( 1 ) { /* hang */ }
}
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 ( ) ;
// enable main uart if it's connected
if ( has_external_debug_serial ) {
// WEIRDNESS: without this gate around the UART, it would "crash", but only if the ESP is enabled
// assuming it's because the lines were left floating and spurious noise was on them
uart_init ( & uart_ring_debug , 115200 ) ;
}
if ( board_has_gps ( ) ) {
uart_init ( & uart_ring_esp_gps , 9600 ) ;
} else {
// enable ESP uart
uart_init ( & uart_ring_esp_gps , 115200 ) ;
}
if ( board_has_lin ( ) ) {
// enable LIN
uart_init ( & uart_ring_lin1 , 10400 ) ;
UART5 - > CR2 | = USART_CR2_LINEN ;
uart_init ( & uart_ring_lin2 , 10400 ) ;
USART3 - > CR2 | = USART_CR2_LINEN ;
}
// init microsecond system timer
// increments 1000000 times per second
// generate an update to set the prescaler
TIM2 - > PSC = 48 - 1 ;
TIM2 - > CR1 = TIM_CR1_CEN ;
TIM2 - > EGR = TIM_EGR_UG ;
// use TIM2->CNT to read
// 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
// 1hz
timer_init ( TIM9 , 1464 ) ;
NVIC_EnableIRQ ( TIM1_BRK_TIM9_IRQn ) ;
# ifdef DEBUG
puts ( " DEBUG ENABLED \n " ) ;
# endif
// enable USB (right before interrupts or enum can fail!)
usb_init ( ) ;
puts ( " **** INTERRUPTS ON **** \n " ) ;
enable_interrupts ( ) ;
// LED should keep on blinking all the time
uint64_t cnt = 0 ;
for ( cnt = 0 ; ; cnt + + ) {
if ( power_save_status = = POWER_SAVE_STATUS_DISABLED ) {
# 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 ) ; }
}
}
}
# 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 ( ) ;
}
}
return 0 ;
}