mirror of
https://github.com/dragonpilot/dragonpilot.git
synced 2026-02-24 04:53:52 +08:00
30c7ca8a5 bump version to 1.5.3 9403dbebe Need to fix wifi test before re-enabling. 0812362b5 GPS UART fix until boardd is refactored (#294) ffbdb87a8 python2 -> 3 fixes to pedal flasher (#292) 78b75ef59 Added build type to release version strings 736c2cbf7 Fixed sending of bytes over PandaSerial 0894b28f1 Fixed USB power mode on black (#291) 4b3358c92 patch to be able to switch from EON to PC with a Panda that has EON b… (#290) a95c44a71 Made setting of NOOUTPUT on no heartbeat more efficient (#287) 948683688 UART instability fix with high interrupt load (#283) 9a9e9d47b Fix usb_power_mode missing initialization (#289) af0960ad3 DFU fix (#288) 70219d7bb match safety enum in cereal (#285) a338d3932 Fix build for jenkins test 78ef4a6eb Stop charge (#284) 5266a4028 Fix typo (#286) f4787ec5a Revert "turn on CDP when ignition switches on (#281)" d37daee97 Revert "NONE and CLIENT should be the same thing in white/grey pandas" e97b283e7 NONE and CLIENT should be the same thing in white/grey pandas 8c1df559f turn on CDP when ignition switches on (#281) 847a35d42 Fix bullet points fac027716 Misra update (#280) 5a04df6b1 Added description of regression tests to README c4aabae59 Fixed some python3 bugs in the test scripts and PandaSerial 9af0cb353 Bump version c4ac3d63b Disable GPS load switching on black pandas 078ee588c This is the correct table, actually 578b95ee3 Misra table of coverage added d383a2625 bump panda b98ca010d fix sdk build in python3 env (#279) 63d3dc7d3 Set python3 env before runnign get_sdk, so we know if it fails e951d79c0 legacy code we don't control can remain python2 11b715118 Merge pull request #276 from commaai/python3 9893a842a Merge pull request #277 from zorrobyte/patch-1 d3268690c Revert "revert back esptool to python2 and force to build esptools with python2" 875e76012 revert back esptool to python2 and force to build esptools with python2 9c40e6240 needed to install python3 ed2ac87cf Also moved safety tests to python3 6842b2d2c move esptool sdk installation before python3 env is set. Kind of a cheat b5a2cabcd this hopefully fixes build test 628050955 Fixes safety replay 2c220b623 this fixes language regr test fdbe789b8 use python 3 in Docker container ee1ae4f86 Better hash print 0de9ef73c Revert "Final 2to3 on the whole repo" c92fd3bc9 Final 2to3 on the whole repo 5f2bc4460 better b2a30fdbd make works! b74005d10 fix sign.py fe727706b read file as byte and no tab before sleep 32a344ef6 Update README.md 2dc34096a 2to3 applied ffa68ef71 undo unnecessary brackets for print dbc248027 Fix all the prints with 2to3, some need to be undo 5a7aeba0f xrange is gone 982c4c928 one more python3 env 1e2412a29 env python -> env python3 git-subtree-dir: panda git-subtree-split: 30c7ca8a53a3adb05d23d7cfe64fb716a656ef1a
760 lines
22 KiB
C
760 lines
22 KiB
C
//#define EON
|
|
//#define PANDA
|
|
|
|
// ********************* Includes *********************
|
|
#include "config.h"
|
|
#include "obj/gitversion.h"
|
|
|
|
#include "libc.h"
|
|
#include "provision.h"
|
|
|
|
#include "main_declarations.h"
|
|
|
|
#include "drivers/llcan.h"
|
|
#include "drivers/llgpio.h"
|
|
#include "drivers/adc.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"
|
|
|
|
// ********************* Serial debugging *********************
|
|
|
|
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
|
|
|
|
// jump to DFU flash
|
|
if (rcv == 'z') {
|
|
enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC;
|
|
NVIC_SystemReset();
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************** 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 = current_board->check_ignition() ? 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 (current_board->check_ignition()) {
|
|
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);
|
|
if (err == -1) {
|
|
puts("Error: safety set mode failed\n");
|
|
} else {
|
|
switch (mode) {
|
|
case SAFETY_NOOUTPUT:
|
|
set_intercept_relay(false);
|
|
if(hw_type == HW_TYPE_BLACK_PANDA){
|
|
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(hw_type == HW_TYPE_BLACK_PANDA){
|
|
current_board->set_can_mode(CAN_MODE_OBD_CAN2);
|
|
}
|
|
can_silent = ALL_CAN_LIVE;
|
|
break;
|
|
default:
|
|
set_intercept_relay(true);
|
|
heartbeat_counter = 0U;
|
|
if(hw_type == HW_TYPE_BLACK_PANDA){
|
|
current_board->set_can_mode(CAN_MODE_NORMAL);
|
|
}
|
|
can_silent = ALL_CAN_LIVE;
|
|
break;
|
|
}
|
|
if (safety_ignition_hook() != -1) {
|
|
// if the ignition hook depends on something other than the started GPIO
|
|
// we have to disable power savings (fix for GM and Tesla)
|
|
set_power_save_state(POWER_SAVE_STATUS_DISABLED);
|
|
} else {
|
|
// power mode is already POWER_SAVE_STATUS_DISABLED and CAN TXs are active
|
|
}
|
|
can_init_all();
|
|
}
|
|
}
|
|
|
|
// ***************************** USB port *****************************
|
|
|
|
int get_health_pkt(void *dat) {
|
|
struct __attribute__((packed)) {
|
|
uint32_t voltage_pkt;
|
|
uint32_t current_pkt;
|
|
uint32_t can_send_errs_pkt;
|
|
uint32_t can_fwd_errs_pkt;
|
|
uint32_t gmlan_send_errs_pkt;
|
|
uint8_t started_pkt;
|
|
uint8_t controls_allowed_pkt;
|
|
uint8_t gas_interceptor_detected_pkt;
|
|
uint8_t car_harness_status_pkt;
|
|
uint8_t usb_power_mode_pkt;
|
|
} *health = dat;
|
|
|
|
health->voltage_pkt = adc_get_voltage();
|
|
|
|
// No current sense on panda black
|
|
if(hw_type != HW_TYPE_BLACK_PANDA){
|
|
health->current_pkt = adc_get(ADCCHAN_CURRENT);
|
|
} else {
|
|
health->current_pkt = 0;
|
|
}
|
|
|
|
int safety_ignition = safety_ignition_hook();
|
|
if (safety_ignition < 0) {
|
|
//Use the GPIO pin to determine ignition
|
|
health->started_pkt = (uint8_t)(current_board->check_ignition());
|
|
} else {
|
|
//Current safety hooks want to determine ignition (ex: GM)
|
|
health->started_pkt = safety_ignition;
|
|
}
|
|
|
|
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;
|
|
|
|
return sizeof(*health);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
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;
|
|
switch (setup->b.bRequest) {
|
|
// **** 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;
|
|
// **** 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(hw_type == HW_TYPE_BLACK_PANDA){
|
|
if (setup->b.wValue.w == 1U) {
|
|
// Enable OBD CAN
|
|
current_board->set_can_mode(CAN_MODE_OBD_CAN2);
|
|
} else {
|
|
// 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 NOOUTPUT and ELM security mode to be set over wifi.
|
|
if (hardwired || (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;
|
|
// **** 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)));
|
|
}
|
|
|
|
uint64_t tcnt = 0;
|
|
|
|
// go into NOOUTPUT 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 TIM3_IRQHandler(void) {
|
|
if (TIM3->SR != 0) {
|
|
can_live = pending_can_live;
|
|
|
|
current_board->usb_power_mode_tick(tcnt);
|
|
|
|
//puth(usart1_dma); puts(" "); puth(DMA2_Stream5->M0AR); puts(" "); puth(DMA2_Stream5->NDTR); puts("\n");
|
|
|
|
// reset this every 16th pass
|
|
if ((tcnt & 0xFU) == 0U) {
|
|
pending_can_live = 0;
|
|
}
|
|
#ifdef DEBUG
|
|
puts("** blink ");
|
|
puth(can_rx_q.r_ptr); puts(" "); puth(can_rx_q.w_ptr); puts(" ");
|
|
puth(can_tx1_q.r_ptr); puts(" "); puth(can_tx1_q.w_ptr); puts(" ");
|
|
puth(can_tx2_q.r_ptr); puts(" "); puth(can_tx2_q.w_ptr); puts("\n");
|
|
#endif
|
|
|
|
// 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, (tcnt & 1U) && (power_save_status == POWER_SAVE_STATUS_ENABLED));
|
|
|
|
// increase heartbeat counter and cap it at the uint32 limit
|
|
if (heartbeat_counter < __UINT32_MAX__) {
|
|
heartbeat_counter += 1U;
|
|
}
|
|
|
|
// check heartbeat counter if we are running EON code. If the heartbeat has been gone for a while, go to NOOUTPUT safety mode.
|
|
#ifdef EON
|
|
if (heartbeat_counter >= (current_board->check_ignition() ? 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);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// on to the next one
|
|
tcnt += 1U;
|
|
}
|
|
TIM3->SR = 0;
|
|
}
|
|
|
|
int main(void) {
|
|
// 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);
|
|
}
|
|
|
|
// there is no LIN on panda black
|
|
if(hw_type != HW_TYPE_BLACK_PANDA){
|
|
// 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
|
|
|
|
// 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();
|
|
|
|
#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 (current_board->check_ignition()) {
|
|
set_power_save_state(POWER_SAVE_STATUS_ENABLED);
|
|
}*/
|
|
#endif
|
|
|
|
// 48mhz / 65536 ~= 732 / 732 = 1
|
|
timer_init(TIM3, 732);
|
|
NVIC_EnableIRQ(TIM3_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) {
|
|
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); }
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
__WFI();
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|