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
+3 -1
View File
@@ -19,7 +19,9 @@
void detect_board_type(void) {
#ifdef PANDA
// SPI lines floating: white (TODO: is this reliable?)
// SPI lines floating: white (TODO: is this reliable? Not really, we have to enable ESP/GPS to be able to detect this on the UART)
set_gpio_output(GPIOC, 14, 1);
set_gpio_output(GPIOC, 5, 1);
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;
+3 -1
View File
@@ -6,11 +6,12 @@ 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 void (*board_usb_power_mode_tick)(uint32_t uptime);
typedef bool (*board_check_ignition)(void);
typedef uint32_t (*board_read_current)(void);
typedef void (*board_set_ir_power)(uint8_t percentage);
typedef void (*board_set_fan_power)(uint8_t percentage);
typedef void (*board_set_phone_power)(bool enabled);
struct board {
const char *board_type;
@@ -27,6 +28,7 @@ struct board {
board_read_current read_current;
board_set_ir_power set_ir_power;
board_set_fan_power set_fan_power;
board_set_phone_power set_phone_power;
};
// ******************* Definitions ********************
+11 -3
View File
@@ -123,8 +123,8 @@ void black_set_can_mode(uint8_t mode){
}
}
void black_usb_power_mode_tick(uint64_t tcnt){
UNUSED(tcnt);
void black_usb_power_mode_tick(uint32_t uptime){
UNUSED(uptime);
// Not applicable
}
@@ -146,6 +146,10 @@ void black_set_fan_power(uint8_t percentage){
UNUSED(percentage);
}
void black_set_phone_power(bool enabled){
UNUSED(enabled);
}
void black_init(void) {
common_init_gpio();
@@ -158,6 +162,9 @@ void black_init(void) {
set_gpio_mode(GPIOC, 0, MODE_ANALOG);
set_gpio_mode(GPIOC, 3, MODE_ANALOG);
// Set default state of GPS
current_board->set_esp_gps_mode(ESP_GPS_ENABLED);
// C10: OBD_SBU1_RELAY (harness relay driving output)
// C11: OBD_SBU2_RELAY (harness relay driving output)
set_gpio_mode(GPIOC, 10, MODE_OUTPUT);
@@ -227,5 +234,6 @@ const board board_black = {
.check_ignition = black_check_ignition,
.read_current = black_read_current,
.set_fan_power = black_set_fan_power,
.set_ir_power = black_set_ir_power
.set_ir_power = black_set_ir_power,
.set_phone_power = black_set_phone_power
};
+1 -1
View File
@@ -61,7 +61,7 @@ void peripherals_init(void){
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // pedal and fan PWM
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; // gmlan_alt and IR PWM
//RCC->APB1ENR |= RCC_APB1ENR_TIM5EN;
//RCC->APB1ENR |= RCC_APB1ENR_TIM6EN;
RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; // interrupt timer
RCC->APB1ENR |= RCC_APB1ENR_PWREN; // for RTC config
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN;
+11 -2
View File
@@ -3,10 +3,18 @@
// ////////// //
// Most hardware functionality is similar to white panda
void grey_init(void) {
white_grey_common_init();
// Set default state of GPS
current_board->set_esp_gps_mode(ESP_GPS_ENABLED);
}
const board board_grey = {
.board_type = "Grey",
.harness_config = &white_harness_config,
.init = white_init,
.init = grey_init,
.enable_can_transciever = white_enable_can_transciever,
.enable_can_transcievers = white_enable_can_transcievers,
.set_led = white_set_led,
@@ -17,5 +25,6 @@ const board board_grey = {
.check_ignition = white_check_ignition,
.read_current = white_read_current,
.set_fan_power = white_set_fan_power,
.set_ir_power = white_set_ir_power
.set_ir_power = white_set_ir_power,
.set_phone_power = white_set_phone_power
};
+8 -3
View File
@@ -50,8 +50,8 @@ void pedal_set_can_mode(uint8_t mode){
}
}
void pedal_usb_power_mode_tick(uint64_t tcnt){
UNUSED(tcnt);
void pedal_usb_power_mode_tick(uint32_t uptime){
UNUSED(uptime);
// Not applicable
}
@@ -73,6 +73,10 @@ void pedal_set_fan_power(uint8_t percentage){
UNUSED(percentage);
}
void pedal_set_phone_power(bool enabled){
UNUSED(enabled);
}
void pedal_init(void) {
common_init_gpio();
@@ -108,5 +112,6 @@ const board board_pedal = {
.check_ignition = pedal_check_ignition,
.read_current = pedal_read_current,
.set_fan_power = pedal_set_fan_power,
.set_ir_power = pedal_set_ir_power
.set_ir_power = pedal_set_ir_power,
.set_phone_power = pedal_set_phone_power
};
+45 -11
View File
@@ -1,6 +1,8 @@
// ///////////// //
// Uno + Harness //
// ///////////// //
#define BOOTKICK_TIME 3U
uint8_t bootkick_timer = 0U;
void uno_enable_can_transciever(uint8_t transciever, bool enabled) {
switch (transciever){
@@ -48,9 +50,38 @@ void uno_set_gps_load_switch(bool enabled) {
set_gpio_output(GPIOC, 12, enabled);
}
void uno_set_bootkick(bool enabled){
set_gpio_output(GPIOB, 14, !enabled);
}
void uno_bootkick(void) {
bootkick_timer = BOOTKICK_TIME;
uno_set_bootkick(true);
}
void uno_set_phone_power(bool enabled){
set_gpio_output(GPIOB, 4, enabled);
}
void uno_set_usb_power_mode(uint8_t mode) {
UNUSED(mode);
puts("Setting USB mode makes no sense on UNO\n");
bool valid = false;
switch (mode) {
case USB_POWER_CLIENT:
uno_set_phone_power(false);
valid = true;
break;
case USB_POWER_CDP:
uno_set_phone_power(true);
uno_bootkick();
valid = true;
break;
default:
puts("Invalid USB power mode\n");
break;
}
if (valid) {
usb_power_mode = mode;
}
}
void uno_set_esp_gps_mode(uint8_t mode) {
@@ -106,12 +137,11 @@ void uno_set_can_mode(uint8_t mode){
}
}
void uno_set_bootkick(bool enabled){
set_gpio_output(GPIOB, 14, !enabled);
}
void uno_usb_power_mode_tick(uint64_t tcnt){
if(tcnt == 3U){
void uno_usb_power_mode_tick(uint32_t uptime){
UNUSED(uptime);
if(bootkick_timer != 0U){
bootkick_timer--;
} else {
uno_set_bootkick(false);
}
}
@@ -152,6 +182,9 @@ void uno_init(void) {
set_gpio_mode(GPIOC, 0, MODE_ANALOG);
set_gpio_mode(GPIOC, 3, MODE_ANALOG);
// Set default state of GPS
current_board->set_esp_gps_mode(ESP_GPS_ENABLED);
// C10: OBD_SBU1_RELAY (harness relay driving output)
// C11: OBD_SBU2_RELAY (harness relay driving output)
set_gpio_mode(GPIOC, 10, MODE_OUTPUT);
@@ -168,7 +201,7 @@ void uno_init(void) {
uno_set_gps_load_switch(true);
// Turn on phone regulator
set_gpio_output(GPIOB, 4, 1);
uno_set_phone_power(true);
// Initialize IR PWM and set to 0%
set_gpio_alternate(GPIOB, 7, GPIO_AF2_TIM4);
@@ -212,7 +245,7 @@ void uno_init(void) {
}
// Bootkick phone
uno_set_bootkick(true);
uno_bootkick();
}
const harness_configuration uno_harness_config = {
@@ -243,5 +276,6 @@ const board board_uno = {
.check_ignition = uno_check_ignition,
.read_current = uno_read_current,
.set_fan_power = uno_set_fan_power,
.set_ir_power = uno_set_ir_power
.set_ir_power = uno_set_ir_power,
.set_phone_power = uno_set_phone_power
};
+32 -21
View File
@@ -78,11 +78,13 @@ void white_set_esp_gps_mode(uint8_t mode) {
set_gpio_output(GPIOC, 14, 0);
set_gpio_output(GPIOC, 5, 0);
break;
#ifndef EON
case ESP_GPS_ENABLED:
// ESP ON
set_gpio_output(GPIOC, 14, 1);
set_gpio_output(GPIOC, 5, 1);
break;
#endif
case ESP_GPS_BOOTMODE:
set_gpio_output(GPIOC, 14, 1);
set_gpio_output(GPIOC, 5, 0);
@@ -156,8 +158,8 @@ uint32_t white_read_current(void){
return adc_get(ADCCHAN_CURRENT);
}
uint64_t marker = 0;
void white_usb_power_mode_tick(uint64_t tcnt){
uint32_t marker = 0;
void white_usb_power_mode_tick(uint32_t uptime){
// on EON or BOOTSTUB, no state machine
#if !defined(BOOTSTUB) && !defined(EON)
@@ -171,47 +173,47 @@ void white_usb_power_mode_tick(uint64_t tcnt){
switch (usb_power_mode) {
case USB_POWER_CLIENT:
if ((tcnt - marker) >= CLICKS) {
if ((uptime - 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;
marker = uptime;
}
}
// keep resetting the timer if it's enumerated
if (is_enumerated) {
marker = tcnt;
marker = uptime;
}
break;
case USB_POWER_CDP:
// been CLICKS clicks since we switched to CDP
if ((tcnt-marker) >= CLICKS) {
if ((uptime - 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;
marker = uptime;
}
}
// keep resetting the timer if there's no current draw in CDP
if (current >= CURRENT_THRESHOLD) {
marker = tcnt;
marker = uptime;
}
break;
case USB_POWER_DCP:
// been at least CLICKS clicks since we switched to DCP
if ((tcnt-marker) >= CLICKS) {
if ((uptime - 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;
marker = uptime;
}
}
// keep resetting the timer if there's current draw in DCP
if (current < CURRENT_THRESHOLD) {
marker = tcnt;
marker = uptime;
}
break;
default:
@@ -219,7 +221,7 @@ void white_usb_power_mode_tick(uint64_t tcnt){
break;
}
#else
UNUSED(tcnt);
UNUSED(uptime);
#endif
}
@@ -236,7 +238,11 @@ bool white_check_ignition(void){
return !get_gpio_input(GPIOA, 1);
}
void white_init(void) {
void white_set_phone_power(bool enabled){
UNUSED(enabled);
}
void white_grey_common_init(void) {
common_init_gpio();
// C3: current sense
@@ -296,13 +302,6 @@ void white_init(void) {
// Set normal CAN mode
white_set_can_mode(CAN_MODE_NORMAL);
// Setup ignition interrupts
SYSCFG->EXTICR[1] = SYSCFG_EXTICR1_EXTI1_PA;
EXTI->IMR |= (1U << 1);
EXTI->RTSR |= (1U << 1);
EXTI->FTSR |= (1U << 1);
NVIC_EnableIRQ(EXTI1_IRQn);
// Init usb power mode
uint32_t voltage = adc_get_voltage();
// Init in CDP mode only if panda is powered by 12V.
@@ -314,6 +313,17 @@ void white_init(void) {
}
}
void white_init(void) {
white_grey_common_init();
// Set default state of ESP
#ifdef EON
current_board->set_esp_gps_mode(ESP_GPS_DISABLED);
#else
current_board->set_esp_gps_mode(ESP_GPS_ENABLED);
#endif
}
const harness_configuration white_harness_config = {
.has_harness = false
};
@@ -332,5 +342,6 @@ const board board_white = {
.check_ignition = white_check_ignition,
.read_current = white_read_current,
.set_fan_power = white_set_fan_power,
.set_ir_power = white_set_ir_power
.set_ir_power = white_set_ir_power,
.set_phone_power = white_set_phone_power
};
+17
View File
@@ -1,5 +1,8 @@
#define BOOTSTUB
#define VERS_TAG 0x53524556
#define MIN_VERSION 2
#include "config.h"
#include "obj/gitversion.h"
@@ -29,7 +32,11 @@ const board *current_board;
// ********************* Includes *********************
#include "libc.h"
#include "provision.h"
#include "critical.h"
#include "faults.h"
#include "drivers/registers.h"
#include "drivers/interrupts.h"
#include "drivers/clock.h"
#include "drivers/llgpio.h"
#include "drivers/adc.h"
@@ -65,6 +72,9 @@ extern void *_app_start[];
// BOUNTY: $200 coupon on shop.comma.ai or $100 check.
int main(void) {
// Init interrupt table
init_interrupts(true);
disable_interrupts();
clock_init();
detect_configuration();
@@ -83,6 +93,13 @@ int main(void) {
uint8_t digest[SHA_DIGEST_SIZE];
SHA_hash(&_app_start[1], len-4, digest);
// verify version, last bytes in the signed area
uint32_t vers[2] = {0};
memcpy(&vers, ((void*)&_app_start[0]) + len - sizeof(vers), sizeof(vers));
if (vers[0] != VERS_TAG || vers[1] < MIN_VERSION) {
goto fail;
}
// verify RSA signature
if (RSA_verify(&release_rsa_key, ((void*)&_app_start[0]) + len, RSANUMBYTES, digest, SHA_DIGEST_SIZE)) {
goto good;
+2 -2
View File
@@ -33,7 +33,7 @@ POSTCOMPILE = @mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d && touch $@
# this no longer pushes the bootstub
flash: obj/$(PROJ_NAME).bin
PYTHONPATH=../ python -c "from python import Panda; Panda().flash('obj/$(PROJ_NAME).bin')"
PYTHONPATH=../ python3 -c "from python import Panda; Panda().flash('obj/$(PROJ_NAME).bin')"
ota: obj/$(PROJ_NAME).bin
curl http://192.168.0.10/stupdate --upload-file $<
@@ -42,7 +42,7 @@ bin: obj/$(PROJ_NAME).bin
# this flashes everything
recover: obj/bootstub.$(PROJ_NAME).bin obj/$(PROJ_NAME).bin
-PYTHONPATH=../ python -c "from python import Panda; Panda().reset(enter_bootloader=True)"
-PYTHONPATH=../ python3 -c "from python import Panda; Panda().reset(enter_bootloader=True)"
sleep 1.0
$(DFU_UTIL) -d 0483:df11 -a 0 -s 0x08004000 -D obj/$(PROJ_NAME).bin
$(DFU_UTIL) -d 0483:df11 -a 0 -s 0x08000000:leave -D obj/bootstub.$(PROJ_NAME).bin
+4
View File
@@ -5,6 +5,7 @@
//#define DEBUG_UART
//#define DEBUG_USB
//#define DEBUG_SPI
//#define DEBUG_FAULTS
#ifdef STM32F4
#define PANDA
@@ -37,5 +38,8 @@
#define MAX_RESP_LEN 0x40U
// Around (1Mbps / 8 bits/byte / 12 bytes per message)
#define CAN_INTERRUPT_RATE 12000U
#endif
+23
View File
@@ -0,0 +1,23 @@
// ********************* Critical section helpers *********************
volatile bool interrupts_enabled = false;
void enable_interrupts(void) {
interrupts_enabled = true;
__enable_irq();
}
void disable_interrupts(void) {
interrupts_enabled = false;
__disable_irq();
}
uint8_t global_critical_depth = 0U;
#define ENTER_CRITICAL() \
__disable_irq(); \
global_critical_depth += 1U;
#define EXIT_CRITICAL() \
global_critical_depth -= 1U; \
if ((global_critical_depth == 0U) && interrupts_enabled) { \
__enable_irq(); \
}
+6 -16
View File
@@ -9,26 +9,16 @@
#define ADCCHAN_CURRENT 13
void adc_init(void) {
// global setup
ADC->CCR = ADC_CCR_TSVREFE | ADC_CCR_VBATE;
//ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_EOCS | ADC_CR2_DDS;
ADC1->CR2 = ADC_CR2_ADON;
// long
//ADC1->SMPR1 = ADC_SMPR1_SMP10 | ADC_SMPR1_SMP11 | ADC_SMPR1_SMP12 | ADC_SMPR1_SMP13;
ADC1->SMPR1 = ADC_SMPR1_SMP12 | ADC_SMPR1_SMP13;
register_set(&(ADC->CCR), ADC_CCR_TSVREFE | ADC_CCR_VBATE, 0xC30000U);
register_set(&(ADC1->CR2), ADC_CR2_ADON, 0xFF7F0F03U);
register_set(&(ADC1->SMPR1), ADC_SMPR1_SMP12 | ADC_SMPR1_SMP13, 0x7FFFFFFU);
}
uint32_t adc_get(unsigned int channel) {
// includes length
//ADC1->SQR1 = 0;
// select channel
ADC1->JSQR = channel << 15;
//ADC1->CR1 = ADC_CR1_DISCNUM_0;
//ADC1->CR1 = ADC_CR1_EOCIE;
// Select channel
register_set(&(ADC1->JSQR), (channel << 15U), 0x3FFFFFU);
// Start conversion
ADC1->SR &= ~(ADC_SR_JEOC);
ADC1->CR2 |= ADC_CR2_JSWSTART;
while (!(ADC1->SR & ADC_SR_JEOC));
+38 -32
View File
@@ -27,11 +27,12 @@ void can_set_forwarding(int from, int to);
void can_init(uint8_t can_number);
void can_init_all(void);
void can_send(CAN_FIFOMailBox_TypeDef *to_push, uint8_t bus_number);
void can_send(CAN_FIFOMailBox_TypeDef *to_push, uint8_t bus_number, bool skip_tx_hook);
bool can_pop(can_ring *q, CAN_FIFOMailBox_TypeDef *elem);
// Ignition detected from CAN meessages
bool ignition_can = false;
uint32_t ignition_can_cnt = 0U;
// end API
@@ -148,23 +149,10 @@ void can_set_speed(uint8_t can_number) {
}
}
void can_init(uint8_t can_number) {
if (can_number != 0xffU) {
CAN_TypeDef *CAN = CANIF_FROM_CAN_NUM(can_number);
can_set_speed(can_number);
llcan_init(CAN);
// in case there are queued up messages
process_can(can_number);
}
}
void can_init_all(void) {
for (uint8_t i=0U; i < CAN_MAX; i++) {
can_init(i);
}
current_board->enable_can_transcievers(true);
}
void can_flip_buses(uint8_t bus1, uint8_t bus2){
@@ -336,11 +324,12 @@ void process_can(uint8_t can_number) {
}
void ignition_can_hook(CAN_FIFOMailBox_TypeDef *to_push) {
int bus = GET_BUS(to_push);
int addr = GET_ADDR(to_push);
int len = GET_LEN(to_push);
ignition_can_cnt = 0U; // reset counter
if (bus == 0) {
// GM exception
if ((addr == 0x1F1) && (len == 8)) {
@@ -357,11 +346,6 @@ void ignition_can_hook(CAN_FIFOMailBox_TypeDef *to_push) {
// this message isn't all zeros when ignition is on
ignition_can = GET_BYTES_04(to_push) != 0;
}
// VW exception
if ((addr == 0x3C0) && (len == 4)) {
// VW Terminal 15 (ignition-on) state
ignition_can = (GET_BYTE(to_push, 2) & 0x2) != 0;
}
}
}
@@ -394,7 +378,7 @@ void can_rx(uint8_t can_number) {
to_send.RDTR = to_push.RDTR;
to_send.RDLR = to_push.RDLR;
to_send.RDHR = to_push.RDHR;
can_send(&to_send, bus_fwd_num);
can_send(&to_send, bus_fwd_num, true);
}
safety_rx_hook(&to_push);
@@ -408,20 +392,20 @@ void can_rx(uint8_t can_number) {
}
}
void CAN1_TX_IRQHandler(void) { process_can(0); }
void CAN1_RX0_IRQHandler(void) { can_rx(0); }
void CAN1_SCE_IRQHandler(void) { can_sce(CAN1); }
void CAN1_TX_IRQ_Handler(void) { process_can(0); }
void CAN1_RX0_IRQ_Handler(void) { can_rx(0); }
void CAN1_SCE_IRQ_Handler(void) { can_sce(CAN1); }
void CAN2_TX_IRQHandler(void) { process_can(1); }
void CAN2_RX0_IRQHandler(void) { can_rx(1); }
void CAN2_SCE_IRQHandler(void) { can_sce(CAN2); }
void CAN2_TX_IRQ_Handler(void) { process_can(1); }
void CAN2_RX0_IRQ_Handler(void) { can_rx(1); }
void CAN2_SCE_IRQ_Handler(void) { can_sce(CAN2); }
void CAN3_TX_IRQHandler(void) { process_can(2); }
void CAN3_RX0_IRQHandler(void) { can_rx(2); }
void CAN3_SCE_IRQHandler(void) { can_sce(CAN3); }
void CAN3_TX_IRQ_Handler(void) { process_can(2); }
void CAN3_RX0_IRQ_Handler(void) { can_rx(2); }
void CAN3_SCE_IRQ_Handler(void) { can_sce(CAN3); }
void can_send(CAN_FIFOMailBox_TypeDef *to_push, uint8_t bus_number) {
if (safety_tx_hook(to_push) != 0) {
void can_send(CAN_FIFOMailBox_TypeDef *to_push, uint8_t bus_number, bool skip_tx_hook) {
if (skip_tx_hook || safety_tx_hook(to_push) != 0) {
if (bus_number < BUS_MAX) {
// add CAN packet to send queue
// bus number isn't passed through
@@ -440,3 +424,25 @@ void can_set_forwarding(int from, int to) {
can_forwarding[from] = to;
}
void can_init(uint8_t can_number) {
REGISTER_INTERRUPT(CAN1_TX_IRQn, CAN1_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
REGISTER_INTERRUPT(CAN1_RX0_IRQn, CAN1_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
REGISTER_INTERRUPT(CAN1_SCE_IRQn, CAN1_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
REGISTER_INTERRUPT(CAN2_TX_IRQn, CAN2_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_2)
REGISTER_INTERRUPT(CAN2_RX0_IRQn, CAN2_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_2)
REGISTER_INTERRUPT(CAN2_SCE_IRQn, CAN2_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_2)
REGISTER_INTERRUPT(CAN3_TX_IRQn, CAN3_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_3)
REGISTER_INTERRUPT(CAN3_RX0_IRQn, CAN3_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_3)
REGISTER_INTERRUPT(CAN3_SCE_IRQn, CAN3_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_3)
if (can_number != 0xffU) {
CAN_TypeDef *CAN = CANIF_FROM_CAN_NUM(can_number);
can_set_speed(can_number);
llcan_init(CAN);
// in case there are queued up messages
process_can(can_number);
}
}
+12 -12
View File
@@ -1,25 +1,24 @@
void clock_init(void) {
// enable external oscillator
RCC->CR |= RCC_CR_HSEON;
register_set_bits(&(RCC->CR), RCC_CR_HSEON);
while ((RCC->CR & RCC_CR_HSERDY) == 0);
// divide things
RCC->CFGR = RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE2_DIV2 | RCC_CFGR_PPRE1_DIV4;
register_set(&(RCC->CFGR), RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE2_DIV2 | RCC_CFGR_PPRE1_DIV4, 0xFF7FFCF3U);
// 16mhz crystal
RCC->PLLCFGR = RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 |
RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLN_5 | RCC_PLLCFGR_PLLSRC_HSE;
register_set(&(RCC->PLLCFGR), RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 | RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLN_5 | RCC_PLLCFGR_PLLSRC_HSE, 0x7F437FFFU);
// start PLL
RCC->CR |= RCC_CR_PLLON;
register_set_bits(&(RCC->CR), RCC_CR_PLLON);
while ((RCC->CR & RCC_CR_PLLRDY) == 0);
// Configure Flash prefetch, Instruction cache, Data cache and wait state
// *** without this, it breaks ***
FLASH->ACR = FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_5WS;
register_set(&(FLASH->ACR), FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_5WS, 0x1F0FU);
// switch to PLL
RCC->CFGR |= RCC_CFGR_SW_PLL;
register_set_bits(&(RCC->CFGR), RCC_CFGR_SW_PLL);
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
// *** running on PLL ***
@@ -27,14 +26,15 @@ void clock_init(void) {
void watchdog_init(void) {
// setup watchdog
IWDG->KR = 0x5555;
IWDG->PR = 0; // divider /4
IWDG->KR = 0x5555U;
register_set(&(IWDG->PR), 0x0U, 0x7U); // divider/4
// 0 = 0.125 ms, let's have a 50ms watchdog
IWDG->RLR = 400 - 1;
IWDG->KR = 0xCCCC;
register_set(&(IWDG->RLR), (400U-1U), 0xFFFU);
IWDG->KR = 0xCCCCU;
}
void watchdog_feed(void) {
IWDG->KR = 0xAAAA;
IWDG->KR = 0xAAAAU;
}
+7 -10
View File
@@ -2,22 +2,19 @@ void puth(unsigned int i);
void puts(const char *a);
void dac_init(void) {
// no buffers required since we have an opamp
//DAC->CR = DAC_CR_EN1 | DAC_CR_BOFF1 | DAC_CR_EN2 | DAC_CR_BOFF2;
DAC->DHR12R1 = 0;
DAC->DHR12R2 = 0;
DAC->CR = DAC_CR_EN1 | DAC_CR_EN2;
// No buffers required since we have an opamp
register_set(&(DAC->DHR12R1), 0U, 0xFFFU);
register_set(&(DAC->DHR12R2), 0U, 0xFFFU);
register_set(&(DAC->CR), DAC_CR_EN1 | DAC_CR_EN2, 0x3FFF3FFFU);
}
void dac_set(int channel, uint32_t value) {
if (channel == 0) {
DAC->DHR12R1 = value;
register_set(&(DAC->DHR12R1), value, 0xFFFU);
} else if (channel == 1) {
DAC->DHR12R2 = value;
register_set(&(DAC->DHR12R2), value, 0xFFFU);
} else {
puts("Failed to set DAC: invalid channel value: ");
puth(value);
puts("\n");
puts("Failed to set DAC: invalid channel value: 0x"); puth(value); puts("\n");
}
}
+16 -13
View File
@@ -1,15 +1,3 @@
void fan_init(void){
// Init PWM speed control
pwm_init(TIM3, 3);
// Init TACH interrupt
SYSCFG->EXTICR[0] = SYSCFG_EXTICR1_EXTI2_PD;
EXTI->IMR |= (1U << 2);
EXTI->RTSR |= (1U << 2);
EXTI->FTSR |= (1U << 2);
NVIC_EnableIRQ(EXTI2_IRQn);
}
void fan_set_power(uint8_t percentage){
pwm_set(TIM3, 3, percentage);
}
@@ -27,10 +15,25 @@ void fan_tick(void){
}
// TACH interrupt handler
void EXTI2_IRQHandler(void) {
void EXTI2_IRQ_Handler(void) {
volatile unsigned int pr = EXTI->PR & (1U << 2);
if ((pr & (1U << 2)) != 0U) {
fan_tach_counter++;
}
EXTI->PR = (1U << 2);
}
void fan_init(void){
// 5000RPM * 4 tach edges / 60 seconds
REGISTER_INTERRUPT(EXTI2_IRQn, EXTI2_IRQ_Handler, 700U, FAULT_INTERRUPT_RATE_TACH)
// Init PWM speed control
pwm_init(TIM3, 3);
// Init TACH interrupt
register_set(&(SYSCFG->EXTICR[0]), SYSCFG_EXTICR1_EXTI2_PD, 0xF00U);
register_set_bits(&(EXTI->IMR), (1U << 2));
register_set_bits(&(EXTI->RTSR), (1U << 2));
register_set_bits(&(EXTI->FTSR), (1U << 2));
NVIC_EnableIRQ(EXTI2_IRQn);
}
+11 -9
View File
@@ -124,15 +124,15 @@ int get_bit_message(char *out, CAN_FIFOMailBox_TypeDef *to_bang) {
void setup_timer4(void) {
// setup
TIM4->PSC = 48-1; // tick on 1 us
TIM4->CR1 = TIM_CR1_CEN; // enable
TIM4->ARR = 30-1; // 33.3 kbps
register_set(&(TIM4->PSC), (48-1), 0xFFFFU); // Tick on 1 us
register_set(&(TIM4->CR1), TIM_CR1_CEN, 0x3FU); // Enable
register_set(&(TIM4->ARR), (30-1), 0xFFFFU); // 33.3 kbps
// in case it's disabled
NVIC_EnableIRQ(TIM4_IRQn);
// run the interrupt
TIM4->DIER = TIM_DIER_UIE; // update interrupt
register_set(&(TIM4->DIER), TIM_DIER_UIE, 0x5F5FU); // Update interrupt
TIM4->SR = 0;
}
@@ -171,9 +171,9 @@ void reset_gmlan_switch_timeout(void) {
void set_bitbanged_gmlan(int val) {
if (val != 0) {
GPIOB->ODR |= (1U << 13);
register_set_bits(&(GPIOB->ODR), (1U << 13));
} else {
GPIOB->ODR &= ~(1U << 13);
register_clear_bits(&(GPIOB->ODR), (1U << 13));
}
}
@@ -187,7 +187,7 @@ int gmlan_fail_count = 0;
#define REQUIRED_SILENT_TIME 10
#define MAX_FAIL_COUNT 10
void TIM4_IRQHandler(void) {
void TIM4_IRQ_Handler(void) {
if (gmlan_alt_mode == BITBANG) {
if ((TIM4->SR & TIM_SR_UIF) && (gmlan_sendmax != -1)) {
int read = get_gpio_input(GPIOB, 12);
@@ -231,8 +231,8 @@ void TIM4_IRQHandler(void) {
if ((gmlan_sending == gmlan_sendmax) || (gmlan_fail_count == MAX_FAIL_COUNT)) {
set_bitbanged_gmlan(1); // recessive
set_gpio_mode(GPIOB, 13, MODE_INPUT);
TIM4->DIER = 0; // no update interrupt
TIM4->CR1 = 0; // disable timer
register_clear_bits(&(TIM4->DIER), TIM_DIER_UIE); // No update interrupt
register_set(&(TIM4->CR1), 0U, 0x3FU); // Disable timer
gmlan_sendmax = -1; // exit
}
}
@@ -279,6 +279,8 @@ bool bitbang_gmlan(CAN_FIFOMailBox_TypeDef *to_bang) {
set_bitbanged_gmlan(1); // recessive
set_gpio_mode(GPIOB, 13, MODE_OUTPUT);
// 33kbps
REGISTER_INTERRUPT(TIM4_IRQn, TIM4_IRQ_Handler, 40000U, FAULT_INTERRUPT_RATE_GMLAN)
setup_timer4();
}
return gmlan_send_ok;
+3 -28
View File
@@ -8,7 +8,7 @@ uint8_t car_harness_status = 0U;
struct harness_configuration {
const bool has_harness;
GPIO_TypeDef *GPIO_SBU1;
GPIO_TypeDef *GPIO_SBU1;
GPIO_TypeDef *GPIO_SBU2;
GPIO_TypeDef *GPIO_relay_normal;
GPIO_TypeDef *GPIO_relay_flipped;
@@ -52,28 +52,6 @@ bool harness_check_ignition(void) {
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;
@@ -117,14 +95,11 @@ void harness_init(void) {
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");
}
}
}
+164
View File
@@ -0,0 +1,164 @@
typedef struct interrupt {
IRQn_Type irq_type;
void (*handler)(void);
uint32_t call_counter;
uint32_t max_call_rate; // Call rate is defined as the amount of calls each second
uint32_t call_rate_fault;
} interrupt;
void unused_interrupt_handler(void) {
// Something is wrong if this handler is called!
puts("Unused interrupt handler called!\n");
fault_occurred(FAULT_UNUSED_INTERRUPT_HANDLED);
}
#define NUM_INTERRUPTS 102U // There are 102 external interrupt sources (see stm32f413.h)
interrupt interrupts[NUM_INTERRUPTS];
#define REGISTER_INTERRUPT(irq_num, func_ptr, call_rate, rate_fault) \
interrupts[irq_num].irq_type = irq_num; \
interrupts[irq_num].handler = func_ptr; \
interrupts[irq_num].call_counter = 0U; \
interrupts[irq_num].max_call_rate = call_rate; \
interrupts[irq_num].call_rate_fault = rate_fault;
bool check_interrupt_rate = false;
void handle_interrupt(IRQn_Type irq_type){
interrupts[irq_type].call_counter++;
interrupts[irq_type].handler();
// Check that the interrupts don't fire too often
if(check_interrupt_rate && (interrupts[irq_type].call_counter > interrupts[irq_type].max_call_rate)){
puts("Interrupt 0x"); puth(irq_type); puts(" fired too often (0x"); puth(interrupts[irq_type].call_counter); puts("/s)!\n");
fault_occurred(interrupts[irq_type].call_rate_fault);
}
}
// Reset interrupt counter every second
void TIM6_DAC_IRQ_Handler(void) {
if (TIM6->SR != 0) {
for(uint16_t i=0U; i<NUM_INTERRUPTS; i++){
interrupts[i].call_counter = 0U;
}
}
TIM6->SR = 0;
}
void init_interrupts(bool check_rate_limit){
check_interrupt_rate = check_rate_limit;
for(uint16_t i=0U; i<NUM_INTERRUPTS; i++){
interrupts[i].handler = unused_interrupt_handler;
}
// Init timer 10 for a 1s interval
register_set_bits(&(RCC->APB1ENR), RCC_APB1ENR_TIM6EN); // Enable interrupt timer peripheral
REGISTER_INTERRUPT(TIM6_DAC_IRQn, TIM6_DAC_IRQ_Handler, 1, FAULT_INTERRUPT_RATE_INTERRUPTS)
register_set(&(TIM6->PSC), (732-1), 0xFFFFU);
register_set(&(TIM6->DIER), TIM_DIER_UIE, 0x5F5FU);
register_set(&(TIM6->CR1), TIM_CR1_CEN, 0x3FU);
TIM6->SR = 0;
NVIC_EnableIRQ(TIM6_DAC_IRQn);
}
// ********************* Bare interrupt handlers *********************
// Only implemented the STM32F413 interrupts for now, the STM32F203 specific ones do not fall into the scope of SIL2
void WWDG_IRQHandler(void) {handle_interrupt(WWDG_IRQn);}
void PVD_IRQHandler(void) {handle_interrupt(PVD_IRQn);}
void TAMP_STAMP_IRQHandler(void) {handle_interrupt(TAMP_STAMP_IRQn);}
void RTC_WKUP_IRQHandler(void) {handle_interrupt(RTC_WKUP_IRQn);}
void FLASH_IRQHandler(void) {handle_interrupt(FLASH_IRQn);}
void RCC_IRQHandler(void) {handle_interrupt(RCC_IRQn);}
void EXTI0_IRQHandler(void) {handle_interrupt(EXTI0_IRQn);}
void EXTI1_IRQHandler(void) {handle_interrupt(EXTI1_IRQn);}
void EXTI2_IRQHandler(void) {handle_interrupt(EXTI2_IRQn);}
void EXTI3_IRQHandler(void) {handle_interrupt(EXTI3_IRQn);}
void EXTI4_IRQHandler(void) {handle_interrupt(EXTI4_IRQn);}
void DMA1_Stream0_IRQHandler(void) {handle_interrupt(DMA1_Stream0_IRQn);}
void DMA1_Stream1_IRQHandler(void) {handle_interrupt(DMA1_Stream1_IRQn);}
void DMA1_Stream2_IRQHandler(void) {handle_interrupt(DMA1_Stream2_IRQn);}
void DMA1_Stream3_IRQHandler(void) {handle_interrupt(DMA1_Stream3_IRQn);}
void DMA1_Stream4_IRQHandler(void) {handle_interrupt(DMA1_Stream4_IRQn);}
void DMA1_Stream5_IRQHandler(void) {handle_interrupt(DMA1_Stream5_IRQn);}
void DMA1_Stream6_IRQHandler(void) {handle_interrupt(DMA1_Stream6_IRQn);}
void ADC_IRQHandler(void) {handle_interrupt(ADC_IRQn);}
void CAN1_TX_IRQHandler(void) {handle_interrupt(CAN1_TX_IRQn);}
void CAN1_RX0_IRQHandler(void) {handle_interrupt(CAN1_RX0_IRQn);}
void CAN1_RX1_IRQHandler(void) {handle_interrupt(CAN1_RX1_IRQn);}
void CAN1_SCE_IRQHandler(void) {handle_interrupt(CAN1_SCE_IRQn);}
void EXTI9_5_IRQHandler(void) {handle_interrupt(EXTI9_5_IRQn);}
void TIM1_BRK_TIM9_IRQHandler(void) {handle_interrupt(TIM1_BRK_TIM9_IRQn);}
void TIM1_UP_TIM10_IRQHandler(void) {handle_interrupt(TIM1_UP_TIM10_IRQn);}
void TIM1_TRG_COM_TIM11_IRQHandler(void) {handle_interrupt(TIM1_TRG_COM_TIM11_IRQn);}
void TIM1_CC_IRQHandler(void) {handle_interrupt(TIM1_CC_IRQn);}
void TIM2_IRQHandler(void) {handle_interrupt(TIM2_IRQn);}
void TIM3_IRQHandler(void) {handle_interrupt(TIM3_IRQn);}
void TIM4_IRQHandler(void) {handle_interrupt(TIM4_IRQn);}
void I2C1_EV_IRQHandler(void) {handle_interrupt(I2C1_EV_IRQn);}
void I2C1_ER_IRQHandler(void) {handle_interrupt(I2C1_ER_IRQn);}
void I2C2_EV_IRQHandler(void) {handle_interrupt(I2C2_EV_IRQn);}
void I2C2_ER_IRQHandler(void) {handle_interrupt(I2C2_ER_IRQn);}
void SPI1_IRQHandler(void) {handle_interrupt(SPI1_IRQn);}
void SPI2_IRQHandler(void) {handle_interrupt(SPI2_IRQn);}
void USART1_IRQHandler(void) {handle_interrupt(USART1_IRQn);}
void USART2_IRQHandler(void) {handle_interrupt(USART2_IRQn);}
void USART3_IRQHandler(void) {handle_interrupt(USART3_IRQn);}
void EXTI15_10_IRQHandler(void) {handle_interrupt(EXTI15_10_IRQn);}
void RTC_Alarm_IRQHandler(void) {handle_interrupt(RTC_Alarm_IRQn);}
void OTG_FS_WKUP_IRQHandler(void) {handle_interrupt(OTG_FS_WKUP_IRQn);}
void TIM8_BRK_TIM12_IRQHandler(void) {handle_interrupt(TIM8_BRK_TIM12_IRQn);}
void TIM8_UP_TIM13_IRQHandler(void) {handle_interrupt(TIM8_UP_TIM13_IRQn);}
void TIM8_TRG_COM_TIM14_IRQHandler(void) {handle_interrupt(TIM8_TRG_COM_TIM14_IRQn);}
void TIM8_CC_IRQHandler(void) {handle_interrupt(TIM8_CC_IRQn);}
void DMA1_Stream7_IRQHandler(void) {handle_interrupt(DMA1_Stream7_IRQn);}
void FSMC_IRQHandler(void) {handle_interrupt(FSMC_IRQn);}
void SDIO_IRQHandler(void) {handle_interrupt(SDIO_IRQn);}
void TIM5_IRQHandler(void) {handle_interrupt(TIM5_IRQn);}
void SPI3_IRQHandler(void) {handle_interrupt(SPI3_IRQn);}
void UART4_IRQHandler(void) {handle_interrupt(UART4_IRQn);}
void UART5_IRQHandler(void) {handle_interrupt(UART5_IRQn);}
void TIM6_DAC_IRQHandler(void) {handle_interrupt(TIM6_DAC_IRQn);}
void TIM7_IRQHandler(void) {handle_interrupt(TIM7_IRQn);}
void DMA2_Stream0_IRQHandler(void) {handle_interrupt(DMA2_Stream0_IRQn);}
void DMA2_Stream1_IRQHandler(void) {handle_interrupt(DMA2_Stream1_IRQn);}
void DMA2_Stream2_IRQHandler(void) {handle_interrupt(DMA2_Stream2_IRQn);}
void DMA2_Stream3_IRQHandler(void) {handle_interrupt(DMA2_Stream3_IRQn);}
void DMA2_Stream4_IRQHandler(void) {handle_interrupt(DMA2_Stream4_IRQn);}
void CAN2_TX_IRQHandler(void) {handle_interrupt(CAN2_TX_IRQn);}
void CAN2_RX0_IRQHandler(void) {handle_interrupt(CAN2_RX0_IRQn);}
void CAN2_RX1_IRQHandler(void) {handle_interrupt(CAN2_RX1_IRQn);}
void CAN2_SCE_IRQHandler(void) {handle_interrupt(CAN2_SCE_IRQn);}
void OTG_FS_IRQHandler(void) {handle_interrupt(OTG_FS_IRQn);}
void DMA2_Stream5_IRQHandler(void) {handle_interrupt(DMA2_Stream5_IRQn);}
void DMA2_Stream6_IRQHandler(void) {handle_interrupt(DMA2_Stream6_IRQn);}
void DMA2_Stream7_IRQHandler(void) {handle_interrupt(DMA2_Stream7_IRQn);}
void USART6_IRQHandler(void) {handle_interrupt(USART6_IRQn);}
void I2C3_EV_IRQHandler(void) {handle_interrupt(I2C3_EV_IRQn);}
void I2C3_ER_IRQHandler(void) {handle_interrupt(I2C3_ER_IRQn);}
#ifdef STM32F4
void DFSDM1_FLT0_IRQHandler(void) {handle_interrupt(DFSDM1_FLT0_IRQn);}
void DFSDM1_FLT1_IRQHandler(void) {handle_interrupt(DFSDM1_FLT1_IRQn);}
void CAN3_TX_IRQHandler(void) {handle_interrupt(CAN3_TX_IRQn);}
void CAN3_RX0_IRQHandler(void) {handle_interrupt(CAN3_RX0_IRQn);}
void CAN3_RX1_IRQHandler(void) {handle_interrupt(CAN3_RX1_IRQn);}
void CAN3_SCE_IRQHandler(void) {handle_interrupt(CAN3_SCE_IRQn);}
void RNG_IRQHandler(void) {handle_interrupt(RNG_IRQn);}
void FPU_IRQHandler(void) {handle_interrupt(FPU_IRQn);}
void UART7_IRQHandler(void) {handle_interrupt(UART7_IRQn);}
void UART8_IRQHandler(void) {handle_interrupt(UART8_IRQn);}
void SPI4_IRQHandler(void) {handle_interrupt(SPI4_IRQn);}
void SPI5_IRQHandler(void) {handle_interrupt(SPI5_IRQn);}
void SAI1_IRQHandler(void) {handle_interrupt(SAI1_IRQn);}
void UART9_IRQHandler(void) {handle_interrupt(UART9_IRQn);}
void UART10_IRQHandler(void) {handle_interrupt(UART10_IRQn);}
void QUADSPI_IRQHandler(void) {handle_interrupt(QUADSPI_IRQn);}
void FMPI2C1_EV_IRQHandler(void) {handle_interrupt(FMPI2C1_EV_IRQn);}
void FMPI2C1_ER_IRQHandler(void) {handle_interrupt(FMPI2C1_ER_IRQn);}
void LPTIM1_IRQHandler(void) {handle_interrupt(LPTIM1_IRQn);}
void DFSDM2_FLT0_IRQHandler(void) {handle_interrupt(DFSDM2_FLT0_IRQn);}
void DFSDM2_FLT1_IRQHandler(void) {handle_interrupt(DFSDM2_FLT1_IRQn);}
void DFSDM2_FLT2_IRQHandler(void) {handle_interrupt(DFSDM2_FLT2_IRQn);}
void DFSDM2_FLT3_IRQHandler(void) {handle_interrupt(DFSDM2_FLT3_IRQn);}
#endif
+20 -16
View File
@@ -19,25 +19,24 @@ void puts(const char *a);
bool llcan_set_speed(CAN_TypeDef *CAN_obj, uint32_t speed, bool loopback, bool silent) {
// initialization mode
CAN_obj->MCR = CAN_MCR_TTCM | CAN_MCR_INRQ;
register_set(&(CAN_obj->MCR), CAN_MCR_TTCM | CAN_MCR_INRQ, 0x180FFU);
while((CAN_obj->MSR & CAN_MSR_INAK) != CAN_MSR_INAK);
// set time quanta from defines
CAN_obj->BTR = (CAN_BTR_TS1_0 * (CAN_SEQ1-1)) |
register_set(&(CAN_obj->BTR), ((CAN_BTR_TS1_0 * (CAN_SEQ1-1)) |
(CAN_BTR_TS2_0 * (CAN_SEQ2-1)) |
(can_speed_to_prescaler(speed) - 1U);
(can_speed_to_prescaler(speed) - 1U)), 0xC37F03FFU);
// silent loopback mode for debugging
if (loopback) {
CAN_obj->BTR |= CAN_BTR_SILM | CAN_BTR_LBKM;
register_set_bits(&(CAN_obj->BTR), CAN_BTR_SILM | CAN_BTR_LBKM);
}
if (silent) {
CAN_obj->BTR |= CAN_BTR_SILM;
register_set_bits(&(CAN_obj->BTR), CAN_BTR_SILM);
}
// reset
// cppcheck-suppress redundantAssignment ; it's a register
CAN_obj->MCR = CAN_MCR_TTCM | CAN_MCR_ABOM;
register_set(&(CAN_obj->MCR), CAN_MCR_TTCM | CAN_MCR_ABOM, 0x180FFU);
#define CAN_TIMEOUT 1000000
int tmp = 0;
@@ -51,20 +50,25 @@ bool llcan_set_speed(CAN_TypeDef *CAN_obj, uint32_t speed, bool loopback, bool s
}
void llcan_init(CAN_TypeDef *CAN_obj) {
// accept all filter
CAN_obj->FMR |= CAN_FMR_FINIT;
// Enter init mode
register_set_bits(&(CAN_obj->FMR), CAN_FMR_FINIT);
// Wait for INAK bit to be set
while(((CAN_obj->MSR & CAN_MSR_INAK) == CAN_MSR_INAK)) {}
// no mask
CAN_obj->sFilterRegister[0].FR1 = 0;
CAN_obj->sFilterRegister[0].FR2 = 0;
CAN_obj->sFilterRegister[14].FR1 = 0;
CAN_obj->sFilterRegister[14].FR2 = 0;
// For some weird reason some of these registers do not want to set properly on CAN2 and CAN3. Probably something to do with the single/dual mode and their different filters.
CAN_obj->sFilterRegister[0].FR1 = 0U;
CAN_obj->sFilterRegister[0].FR2 = 0U;
CAN_obj->sFilterRegister[14].FR1 = 0U;
CAN_obj->sFilterRegister[14].FR2 = 0U;
CAN_obj->FA1R |= 1U | (1U << 14);
CAN_obj->FMR &= ~(CAN_FMR_FINIT);
// Exit init mode, do not wait
register_clear_bits(&(CAN_obj->FMR), CAN_FMR_FINIT);
// enable certain CAN interrupts
CAN_obj->IER |= CAN_IER_TMEIE | CAN_IER_FMPIE0 | CAN_IER_WKUIE;
register_set_bits(&(CAN_obj->IER), CAN_IER_TMEIE | CAN_IER_FMPIE0 | CAN_IER_WKUIE);
if (CAN_obj == CAN1) {
NVIC_EnableIRQ(CAN1_TX_IRQn);
@@ -87,7 +91,7 @@ void llcan_init(CAN_TypeDef *CAN_obj) {
void llcan_clear_send(CAN_TypeDef *CAN_obj) {
CAN_obj->TSR |= CAN_TSR_ABRQ0;
CAN_obj->MSR &= ~(CAN_MSR_ERRI);
register_clear_bits(&(CAN_obj->MSR), CAN_MSR_ERRI);
// cppcheck-suppress selfAssignment ; needed to clear the register
CAN_obj->MSR = CAN_obj->MSR;
}
+7 -7
View File
@@ -15,16 +15,16 @@ void set_gpio_mode(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int mode) {
uint32_t tmp = GPIO->MODER;
tmp &= ~(3U << (pin * 2U));
tmp |= (mode << (pin * 2U));
GPIO->MODER = tmp;
register_set(&(GPIO->MODER), tmp, 0xFFFFFFFFU);
EXIT_CRITICAL();
}
void set_gpio_output(GPIO_TypeDef *GPIO, unsigned int pin, bool enabled) {
ENTER_CRITICAL();
if (enabled) {
GPIO->ODR |= (1U << pin);
register_set_bits(&(GPIO->ODR), (1U << pin));
} else {
GPIO->ODR &= ~(1U << pin);
register_clear_bits(&(GPIO->ODR), (1U << pin));
}
set_gpio_mode(GPIO, pin, MODE_OUTPUT);
EXIT_CRITICAL();
@@ -33,9 +33,9 @@ void set_gpio_output(GPIO_TypeDef *GPIO, unsigned int pin, bool enabled) {
void set_gpio_output_type(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int output_type){
ENTER_CRITICAL();
if(output_type == OUTPUT_TYPE_OPEN_DRAIN) {
GPIO->OTYPER |= (1U << pin);
register_set_bits(&(GPIO->OTYPER), (1U << pin));
} else {
GPIO->OTYPER &= ~(1U << pin);
register_clear_bits(&(GPIO->OTYPER), (1U << pin));
}
EXIT_CRITICAL();
}
@@ -45,7 +45,7 @@ void set_gpio_alternate(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int mode)
uint32_t tmp = GPIO->AFR[pin >> 3U];
tmp &= ~(0xFU << ((pin & 7U) * 4U));
tmp |= mode << ((pin & 7U) * 4U);
GPIO->AFR[pin >> 3] = tmp;
register_set(&(GPIO->AFR[pin >> 3]), tmp, 0xFFFFFFFFU);
set_gpio_mode(GPIO, pin, MODE_ALTERNATE);
EXIT_CRITICAL();
}
@@ -55,7 +55,7 @@ void set_gpio_pullup(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int mode) {
uint32_t tmp = GPIO->PUPDR;
tmp &= ~(3U << (pin * 2U));
tmp |= (mode << (pin * 2U));
GPIO->PUPDR = tmp;
register_set(&(GPIO->PUPDR), tmp, 0xFFFFFFFFU);
EXIT_CRITICAL();
}
+16 -15
View File
@@ -1,53 +1,54 @@
#define PWM_COUNTER_OVERFLOW 2000U // To get ~50kHz
// TODO: Implement for 32-bit timers
void pwm_init(TIM_TypeDef *TIM, uint8_t channel){
// Enable timer and auto-reload
TIM->CR1 = TIM_CR1_CEN | TIM_CR1_ARPE;
register_set(&(TIM->CR1), TIM_CR1_CEN | TIM_CR1_ARPE, 0x3FU);
// Set channel as PWM mode 1 and enable output
switch(channel){
case 1U:
TIM->CCMR1 |= (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1PE);
TIM->CCER |= TIM_CCER_CC1E;
register_set_bits(&(TIM->CCMR1), (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1PE));
register_set_bits(&(TIM->CCER), TIM_CCER_CC1E);
break;
case 2U:
TIM->CCMR1 |= (TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2PE);
TIM->CCER |= TIM_CCER_CC2E;
register_set_bits(&(TIM->CCMR1), (TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2PE));
register_set_bits(&(TIM->CCER), TIM_CCER_CC2E);
break;
case 3U:
TIM->CCMR2 |= (TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3PE);
TIM->CCER |= TIM_CCER_CC3E;
register_set_bits(&(TIM->CCMR2), (TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3PE));
register_set_bits(&(TIM->CCER), TIM_CCER_CC3E);
break;
case 4U:
TIM->CCMR2 |= (TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4PE);
TIM->CCER |= TIM_CCER_CC4E;
register_set_bits(&(TIM->CCMR2), (TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4PE));
register_set_bits(&(TIM->CCER), TIM_CCER_CC4E);
break;
default:
break;
}
// Set max counter value
TIM->ARR = PWM_COUNTER_OVERFLOW;
register_set(&(TIM->ARR), PWM_COUNTER_OVERFLOW, 0xFFFFU);
// Update registers and clear counter
TIM->EGR |= TIM_EGR_UG;
}
// TODO: Implement for 32-bit timers
void pwm_set(TIM_TypeDef *TIM, uint8_t channel, uint8_t percentage){
uint16_t comp_value = (((uint16_t) percentage * PWM_COUNTER_OVERFLOW) / 100U);
switch(channel){
case 1U:
TIM->CCR1 = comp_value;
register_set(&(TIM->CCR1), comp_value, 0xFFFFU);
break;
case 2U:
TIM->CCR2 = comp_value;
register_set(&(TIM->CCR2), comp_value, 0xFFFFU);
break;
case 3U:
TIM->CCR3 = comp_value;
register_set(&(TIM->CCR3), comp_value, 0xFFFFU);
break;
case 4U:
TIM->CCR4 = comp_value;
register_set(&(TIM->CCR4), comp_value, 0xFFFFU);
break;
default:
break;
+81
View File
@@ -0,0 +1,81 @@
typedef struct reg {
volatile uint32_t *address;
uint32_t value;
uint32_t check_mask;
} reg;
// 10 bit hash with 23 as a prime
#define REGISTER_MAP_SIZE 0x3FFU
#define HASHING_PRIME 23U
#define CHECK_COLLISION(hash, addr) (((uint32_t) register_map[hash].address != 0U) && (register_map[hash].address != addr))
reg register_map[REGISTER_MAP_SIZE];
// Hash spread in first and second iterations seems to be reasonable.
// See: tests/development/register_hashmap_spread.py
// Also, check the collision warnings in the debug output, and minimize those.
uint16_t hash_addr(uint32_t input){
return (((input >> 16U) ^ ((((input + 1U) & 0xFFFFU) * HASHING_PRIME) & 0xFFFFU)) & REGISTER_MAP_SIZE);
}
// Do not put bits in the check mask that get changed by the hardware
void register_set(volatile uint32_t *addr, uint32_t val, uint32_t mask){
ENTER_CRITICAL()
// Set bits in register that are also in the mask
(*addr) = ((*addr) & (~mask)) | (val & mask);
// Add these values to the map
uint16_t hash = hash_addr((uint32_t) addr);
uint16_t tries = REGISTER_MAP_SIZE;
while(CHECK_COLLISION(hash, addr) && (tries > 0U)) { hash = hash_addr((uint32_t) hash); tries--;}
if (tries != 0U){
register_map[hash].address = addr;
register_map[hash].value = (register_map[hash].value & (~mask)) | (val & mask);
register_map[hash].check_mask |= mask;
} else {
#ifdef DEBUG_FAULTS
puts("Hash collision: address 0x"); puth((uint32_t) addr); puts("!\n");
#endif
}
EXIT_CRITICAL()
}
// Set individual bits. Also add them to the check_mask.
// Do not use this to change bits that get reset by the hardware
void register_set_bits(volatile uint32_t *addr, uint32_t val) {
return register_set(addr, val, val);
}
// Clear individual bits. Also add them to the check_mask.
// Do not use this to clear bits that get set by the hardware
void register_clear_bits(volatile uint32_t *addr, uint32_t val) {
return register_set(addr, (~val), val);
}
// To be called periodically
void check_registers(void){
for(uint16_t i=0U; i<REGISTER_MAP_SIZE; i++){
if((uint32_t) register_map[i].address != 0U){
ENTER_CRITICAL()
if((*(register_map[i].address) & register_map[i].check_mask) != (register_map[i].value & register_map[i].check_mask)){
#ifdef DEBUG_FAULTS
puts("Register at address 0x"); puth((uint32_t) register_map[i].address); puts(" is divergent!");
puts(" Map: 0x"); puth(register_map[i].value);
puts(" Register: 0x"); puth(*(register_map[i].address));
puts(" Mask: 0x"); puth(register_map[i].check_mask);
puts("\n");
#endif
fault_occurred(FAULT_REGISTER_DIVERGENT);
}
EXIT_CRITICAL()
}
}
}
void init_registers(void) {
for(uint16_t i=0U; i<REGISTER_MAP_SIZE; i++){
register_map[i].address = (volatile uint32_t *) 0U;
register_map[i].check_mask = 0U;
}
}
+10 -10
View File
@@ -27,19 +27,19 @@ void rtc_init(void){
if((RCC->BDCR & RCC_BDCR_MASK) != RCC_BDCR_OPTIONS){
puts("Initializing RTC\n");
// Reset backup domain
RCC->BDCR |= RCC_BDCR_BDRST;
register_set_bits(&(RCC->BDCR), RCC_BDCR_BDRST);
// Disable write protection
PWR->CR |= PWR_CR_DBP;
register_set_bits(&(PWR->CR), PWR_CR_DBP);
// Clear backup domain reset
RCC->BDCR &= ~(RCC_BDCR_BDRST);
register_clear_bits(&(RCC->BDCR), RCC_BDCR_BDRST);
// Set RTC options
RCC->BDCR = RCC_BDCR_OPTIONS | (RCC->BDCR & (~RCC_BDCR_MASK));
register_set(&(RCC->BDCR), RCC_BDCR_OPTIONS, RCC_BDCR_MASK);
// Enable write protection
PWR->CR &= ~(PWR_CR_DBP);
register_clear_bits(&(PWR->CR), PWR_CR_DBP);
}
}
}
@@ -49,12 +49,12 @@ void rtc_set_time(timestamp_t time){
puts("Setting RTC time\n");
// Disable write protection
PWR->CR |= PWR_CR_DBP;
register_set_bits(&(PWR->CR), PWR_CR_DBP);
RTC->WPR = 0xCA;
RTC->WPR = 0x53;
// Enable initialization mode
RTC->ISR |= RTC_ISR_INIT;
register_set_bits(&(RTC->ISR), RTC_ISR_INIT);
while((RTC->ISR & RTC_ISR_INITF) == 0){}
// Set time
@@ -62,17 +62,17 @@ void rtc_set_time(timestamp_t time){
RTC->DR = (to_bcd(time.year - YEAR_OFFSET) << RTC_DR_YU_Pos) | (time.weekday << RTC_DR_WDU_Pos) | (to_bcd(time.month) << RTC_DR_MU_Pos) | (to_bcd(time.day) << RTC_DR_DU_Pos);
// Set options
RTC->CR = 0U;
register_set(&(RTC->CR), 0U, 0xFCFFFFU);
// Disable initalization mode
RTC->ISR &= ~(RTC_ISR_INIT);
register_clear_bits(&(RTC->ISR), RTC_ISR_INIT);
// Wait for synchronization
while((RTC->ISR & RTC_ISR_RSF) == 0){}
// Re-enable write protection
RTC->WPR = 0x00;
PWR->CR &= ~(PWR_CR_DBP);
register_clear_bits(&(PWR->CR), PWR_CR_DBP);
}
}
+45 -41
View File
@@ -10,45 +10,22 @@ uint8_t spi_buf[SPI_BUF_SIZE];
int spi_buf_count = 0;
int spi_total_count = 0;
void spi_init(void) {
//puts("SPI init\n");
SPI1->CR1 = SPI_CR1_SPE;
// enable SPI interrupts
//SPI1->CR2 = SPI_CR2_RXNEIE | SPI_CR2_ERRIE | SPI_CR2_TXEIE;
SPI1->CR2 = SPI_CR2_RXNEIE;
NVIC_EnableIRQ(DMA2_Stream2_IRQn);
NVIC_EnableIRQ(DMA2_Stream3_IRQn);
//NVIC_EnableIRQ(SPI1_IRQn);
// reset handshake back to pull up
set_gpio_mode(GPIOB, 0, MODE_INPUT);
set_gpio_pullup(GPIOB, 0, PULL_UP);
// setup interrupt on falling edge of SPI enable (on PA4)
SYSCFG->EXTICR[2] = SYSCFG_EXTICR2_EXTI4_PA;
EXTI->IMR |= (1U << 4);
EXTI->FTSR |= (1U << 4);
NVIC_EnableIRQ(EXTI4_IRQn);
}
void spi_tx_dma(void *addr, int len) {
// disable DMA
SPI1->CR2 &= ~SPI_CR2_TXDMAEN;
DMA2_Stream3->CR &= ~DMA_SxCR_EN;
register_clear_bits(&(SPI1->CR2), SPI_CR2_TXDMAEN);
register_clear_bits(&(DMA2_Stream3->CR), DMA_SxCR_EN);
// DMA2, stream 3, channel 3
DMA2_Stream3->M0AR = (uint32_t)addr;
register_set(&(DMA2_Stream3->M0AR), (uint32_t)addr, 0xFFFFFFFFU);
DMA2_Stream3->NDTR = len;
DMA2_Stream3->PAR = (uint32_t)&(SPI1->DR);
register_set(&(DMA2_Stream3->PAR), (uint32_t)&(SPI1->DR), 0xFFFFFFFFU);
// channel3, increment memory, memory -> periph, enable
DMA2_Stream3->CR = DMA_SxCR_CHSEL_1 | DMA_SxCR_CHSEL_0 | DMA_SxCR_MINC | DMA_SxCR_DIR_0 | DMA_SxCR_EN;
register_set(&(DMA2_Stream3->CR), (DMA_SxCR_CHSEL_1 | DMA_SxCR_CHSEL_0 | DMA_SxCR_MINC | DMA_SxCR_DIR_0 | DMA_SxCR_EN), 0x1E077EFEU);
delay(0);
DMA2_Stream3->CR |= DMA_SxCR_TCIE;
register_set_bits(&(DMA2_Stream3->CR), DMA_SxCR_TCIE);
SPI1->CR2 |= SPI_CR2_TXDMAEN;
register_set_bits(&(SPI1->CR2), SPI_CR2_TXDMAEN);
// signal data is ready by driving low
// esp must be configured as input by this point
@@ -57,33 +34,32 @@ void spi_tx_dma(void *addr, int len) {
void spi_rx_dma(void *addr, int len) {
// disable DMA
SPI1->CR2 &= ~SPI_CR2_RXDMAEN;
DMA2_Stream2->CR &= ~DMA_SxCR_EN;
register_clear_bits(&(SPI1->CR2), SPI_CR2_RXDMAEN);
register_clear_bits(&(DMA2_Stream2->CR), DMA_SxCR_EN);
// drain the bus
volatile uint8_t dat = SPI1->DR;
(void)dat;
// DMA2, stream 2, channel 3
DMA2_Stream2->M0AR = (uint32_t)addr;
register_set(&(DMA2_Stream2->M0AR), (uint32_t)addr, 0xFFFFFFFFU);
DMA2_Stream2->NDTR = len;
DMA2_Stream2->PAR = (uint32_t)&(SPI1->DR);
register_set(&(DMA2_Stream2->PAR), (uint32_t)&(SPI1->DR), 0xFFFFFFFFU);
// channel3, increment memory, periph -> memory, enable
DMA2_Stream2->CR = DMA_SxCR_CHSEL_1 | DMA_SxCR_CHSEL_0 | DMA_SxCR_MINC | DMA_SxCR_EN;
register_set(&(DMA2_Stream2->CR), (DMA_SxCR_CHSEL_1 | DMA_SxCR_CHSEL_0 | DMA_SxCR_MINC | DMA_SxCR_EN), 0x1E077EFEU);
delay(0);
DMA2_Stream2->CR |= DMA_SxCR_TCIE;
register_set_bits(&(DMA2_Stream2->CR), DMA_SxCR_TCIE);
SPI1->CR2 |= SPI_CR2_RXDMAEN;
register_set_bits(&(SPI1->CR2), SPI_CR2_RXDMAEN);
}
// ***************************** SPI IRQs *****************************
// can't go on the stack cause it's DMAed
uint8_t spi_tx_buf[0x44];
// SPI RX
void DMA2_Stream2_IRQHandler(void) {
void DMA2_Stream2_IRQ_Handler(void) {
int *resp_len = (int*)spi_tx_buf;
(void)memset(spi_tx_buf, 0xaa, 0x44);
*resp_len = spi_cb_rx(spi_buf, 0x14, spi_tx_buf+4);
@@ -99,7 +75,7 @@ void DMA2_Stream2_IRQHandler(void) {
}
// SPI TX
void DMA2_Stream3_IRQHandler(void) {
void DMA2_Stream3_IRQ_Handler(void) {
#ifdef DEBUG_SPI
puts("SPI handshake\n");
#endif
@@ -112,7 +88,7 @@ void DMA2_Stream3_IRQHandler(void) {
DMA2->LIFCR = DMA_LIFCR_CTCIF3;
}
void EXTI4_IRQHandler(void) {
void EXTI4_IRQ_Handler(void) {
volatile unsigned int pr = EXTI->PR & (1U << 4);
#ifdef DEBUG_SPI
puts("exti4\n");
@@ -125,3 +101,31 @@ void EXTI4_IRQHandler(void) {
EXTI->PR = pr;
}
// ***************************** SPI init *****************************
void spi_init(void) {
// Max SPI clock the ESP can produce is 80MHz. At buffer size of 256 bytes, that's a max of about 40k buffers per second
REGISTER_INTERRUPT(DMA2_Stream2_IRQn, DMA2_Stream2_IRQ_Handler, 50000U, FAULT_INTERRUPT_RATE_SPI_DMA)
REGISTER_INTERRUPT(DMA2_Stream3_IRQn, DMA2_Stream3_IRQ_Handler, 50000U, FAULT_INTERRUPT_RATE_SPI_DMA)
REGISTER_INTERRUPT(EXTI4_IRQn, EXTI4_IRQ_Handler, 50000U, FAULT_INTERRUPT_RATE_SPI_CS) // TODO: Figure out if this is a reasonable limit
//puts("SPI init\n");
register_set(&(SPI1->CR1), SPI_CR1_SPE, 0xFFFFU);
// enable SPI interrupts
//SPI1->CR2 = SPI_CR2_RXNEIE | SPI_CR2_ERRIE | SPI_CR2_TXEIE;
register_set(&(SPI1->CR2), SPI_CR2_RXNEIE, 0xF7U);
NVIC_EnableIRQ(DMA2_Stream2_IRQn);
NVIC_EnableIRQ(DMA2_Stream3_IRQn);
//NVIC_EnableIRQ(SPI1_IRQn);
// reset handshake back to pull up
set_gpio_mode(GPIOB, 0, MODE_INPUT);
set_gpio_pullup(GPIOB, 0, PULL_UP);
// setup interrupt on falling edge of SPI enable (on PA4)
register_set(&(SYSCFG->EXTICR[2]), SYSCFG_EXTICR2_EXTI4_PA, 0xFFFFU);
register_set_bits(&(EXTI->IMR), (1U << 4));
register_set_bits(&(EXTI->FTSR), (1U << 4));
NVIC_EnableIRQ(EXTI4_IRQn);
}
+3 -3
View File
@@ -1,7 +1,7 @@
void timer_init(TIM_TypeDef *TIM, int psc) {
TIM->PSC = psc-1;
TIM->DIER = TIM_DIER_UIE;
TIM->CR1 = TIM_CR1_CEN;
register_set(&(TIM->PSC), (psc-1), 0xFFFFU);
register_set(&(TIM->DIER), TIM_DIER_UIE, 0x5F5FU);
register_set(&(TIM->CR1), TIM_CR1_CEN, 0x3FU);
TIM->SR = 0;
}
+12 -5
View File
@@ -197,12 +197,12 @@ void uart_interrupt_handler(uart_ring *q) {
EXIT_CRITICAL();
}
void USART1_IRQHandler(void) { uart_interrupt_handler(&uart_ring_esp_gps); }
void USART2_IRQHandler(void) { uart_interrupt_handler(&uart_ring_debug); }
void USART3_IRQHandler(void) { uart_interrupt_handler(&uart_ring_lin2); }
void UART5_IRQHandler(void) { uart_interrupt_handler(&uart_ring_lin1); }
void USART1_IRQ_Handler(void) { uart_interrupt_handler(&uart_ring_esp_gps); }
void USART2_IRQ_Handler(void) { uart_interrupt_handler(&uart_ring_debug); }
void USART3_IRQ_Handler(void) { uart_interrupt_handler(&uart_ring_lin2); }
void UART5_IRQ_Handler(void) { uart_interrupt_handler(&uart_ring_lin1); }
void DMA2_Stream5_IRQHandler(void) {
void DMA2_Stream5_IRQ_Handler(void) {
ENTER_CRITICAL();
// Handle errors
@@ -272,6 +272,13 @@ void uart_set_baud(USART_TypeDef *u, unsigned int baud) {
}
void uart_init(uart_ring *q, int baud) {
// Register interrupts (max data rate: 115200 baud)
REGISTER_INTERRUPT(USART1_IRQn, USART1_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_1)
REGISTER_INTERRUPT(USART2_IRQn, USART2_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_2)
REGISTER_INTERRUPT(USART3_IRQn, USART3_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_3)
REGISTER_INTERRUPT(UART5_IRQn, UART5_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_5)
REGISTER_INTERRUPT(DMA2_Stream5_IRQn, DMA2_Stream5_IRQ_Handler, 100U, FAULT_INTERRUPT_RATE_UART_DMA) // Called twice per buffer
// Set baud and enable peripheral with TX and RX mode
uart_set_baud(q->uart, baud);
q->uart->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
+77 -79
View File
@@ -281,15 +281,8 @@ uint8_t binary_object_store_desc[] = {
// BOS header
BINARY_OBJECT_STORE_DESCRIPTOR_LENGTH, // bLength, this is only the length of the header
BINARY_OBJECT_STORE_DESCRIPTOR, // bDescriptorType
0x40, 0x00, // wTotalLength (LSB, MSB)
0x03, // bNumDeviceCaps (USB 2.0 + WebUSB + WinUSB)
// -------------------------------------------------
// USB 2.0 extension descriptor
0x07, // bLength, Descriptor size
0x10, // bDescriptorType, Device Capability Descriptor Type
0x02, // bDevCapabilityType, USB 2.0 extension capability type
0x00, 0x00, 0x00, 0x00, // bmAttributes, LIBUSB_BM_LPM_SUPPORT = 2 and its the only option
0x39, 0x00, // wTotalLength (LSB, MSB)
0x02, // bNumDeviceCaps (WebUSB + WinUSB)
// -------------------------------------------------
// WebUSB descriptor
@@ -667,76 +660,7 @@ void usb_setup(void) {
}
}
void usb_init(void) {
// full speed PHY, do reset and remove power down
/*puth(USBx->GRSTCTL);
puts(" resetting PHY\n");*/
while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0);
//puts("AHB idle\n");
// reset PHY here
USBx->GRSTCTL |= USB_OTG_GRSTCTL_CSRST;
while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_CSRST) == USB_OTG_GRSTCTL_CSRST);
//puts("reset done\n");
// internal PHY, force device mode
USBx->GUSBCFG = USB_OTG_GUSBCFG_PHYSEL | USB_OTG_GUSBCFG_FDMOD;
// slowest timings
USBx->GUSBCFG |= ((USBD_FS_TRDT_VALUE << 10) & USB_OTG_GUSBCFG_TRDT);
// power up the PHY
#ifdef STM32F4
USBx->GCCFG = USB_OTG_GCCFG_PWRDWN;
//USBx->GCCFG |= USB_OTG_GCCFG_VBDEN | USB_OTG_GCCFG_SDEN |USB_OTG_GCCFG_PDEN | USB_OTG_GCCFG_DCDEN;
/* B-peripheral session valid override enable*/
USBx->GOTGCTL |= USB_OTG_GOTGCTL_BVALOVAL;
USBx->GOTGCTL |= USB_OTG_GOTGCTL_BVALOEN;
#else
USBx->GCCFG = USB_OTG_GCCFG_PWRDWN | USB_OTG_GCCFG_NOVBUSSENS;
#endif
// be a device, slowest timings
//USBx->GUSBCFG = USB_OTG_GUSBCFG_FDMOD | USB_OTG_GUSBCFG_PHYSEL | USB_OTG_GUSBCFG_TRDT | USB_OTG_GUSBCFG_TOCAL;
//USBx->GUSBCFG |= (uint32_t)((USBD_FS_TRDT_VALUE << 10) & USB_OTG_GUSBCFG_TRDT);
//USBx->GUSBCFG = USB_OTG_GUSBCFG_PHYSEL | USB_OTG_GUSBCFG_TRDT | USB_OTG_GUSBCFG_TOCAL;
// **** for debugging, doesn't seem to work ****
//USBx->GUSBCFG |= USB_OTG_GUSBCFG_CTXPKT;
// reset PHY clock
USBx_PCGCCTL = 0;
// enable the fancy OTG things
// DCFG_FRAME_INTERVAL_80 is 0
//USBx->GUSBCFG |= USB_OTG_GUSBCFG_HNPCAP | USB_OTG_GUSBCFG_SRPCAP;
USBx_DEVICE->DCFG |= USB_OTG_SPEED_FULL | USB_OTG_DCFG_NZLSOHSK;
//USBx_DEVICE->DCFG = USB_OTG_DCFG_NZLSOHSK | USB_OTG_DCFG_DSPD;
//USBx_DEVICE->DCFG = USB_OTG_DCFG_DSPD;
// clear pending interrupts
USBx->GINTSTS = 0xBFFFFFFFU;
// setup USB interrupts
// all interrupts except TXFIFO EMPTY
//USBx->GINTMSK = 0xFFFFFFFF & ~(USB_OTG_GINTMSK_NPTXFEM | USB_OTG_GINTMSK_PTXFEM | USB_OTG_GINTSTS_SOF | USB_OTG_GINTSTS_EOPF);
//USBx->GINTMSK = 0xFFFFFFFF & ~(USB_OTG_GINTMSK_NPTXFEM | USB_OTG_GINTMSK_PTXFEM);
USBx->GINTMSK = USB_OTG_GINTMSK_USBRST | USB_OTG_GINTMSK_ENUMDNEM | USB_OTG_GINTMSK_OTGINT |
USB_OTG_GINTMSK_RXFLVLM | USB_OTG_GINTMSK_GONAKEFFM | USB_OTG_GINTMSK_GINAKEFFM |
USB_OTG_GINTMSK_OEPINT | USB_OTG_GINTMSK_IEPINT | USB_OTG_GINTMSK_USBSUSPM |
USB_OTG_GINTMSK_CIDSCHGM | USB_OTG_GINTMSK_SRQIM | USB_OTG_GINTMSK_MMISM;
USBx->GAHBCFG = USB_OTG_GAHBCFG_GINT;
// DCTL startup value is 2 on new chip, 0 on old chip
USBx_DEVICE->DCTL = 0;
// enable the IRQ
NVIC_EnableIRQ(OTG_FS_IRQn);
}
// ***************************** USB port *****************************
@@ -1008,7 +932,7 @@ void usb_irqhandler(void) {
//USBx->GINTMSK = 0xFFFFFFFF & ~(USB_OTG_GINTMSK_NPTXFEM | USB_OTG_GINTMSK_PTXFEM | USB_OTG_GINTSTS_SOF | USB_OTG_GINTSTS_EOPF);
}
void OTG_FS_IRQHandler(void) {
void OTG_FS_IRQ_Handler(void) {
NVIC_DisableIRQ(OTG_FS_IRQn);
//__disable_irq();
usb_irqhandler();
@@ -1016,3 +940,77 @@ void OTG_FS_IRQHandler(void) {
NVIC_EnableIRQ(OTG_FS_IRQn);
}
// ***************************** USB init *****************************
void usb_init(void) {
REGISTER_INTERRUPT(OTG_FS_IRQn, OTG_FS_IRQ_Handler, 1500000U, FAULT_INTERRUPT_RATE_USB) //TODO: Find out a better rate limit for USB. Now it's the 1.5MB/s rate
// full speed PHY, do reset and remove power down
/*puth(USBx->GRSTCTL);
puts(" resetting PHY\n");*/
while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0);
//puts("AHB idle\n");
// reset PHY here
USBx->GRSTCTL |= USB_OTG_GRSTCTL_CSRST;
while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_CSRST) == USB_OTG_GRSTCTL_CSRST);
//puts("reset done\n");
// internal PHY, force device mode
USBx->GUSBCFG = USB_OTG_GUSBCFG_PHYSEL | USB_OTG_GUSBCFG_FDMOD;
// slowest timings
USBx->GUSBCFG |= ((USBD_FS_TRDT_VALUE << 10) & USB_OTG_GUSBCFG_TRDT);
// power up the PHY
#ifdef STM32F4
USBx->GCCFG = USB_OTG_GCCFG_PWRDWN;
//USBx->GCCFG |= USB_OTG_GCCFG_VBDEN | USB_OTG_GCCFG_SDEN |USB_OTG_GCCFG_PDEN | USB_OTG_GCCFG_DCDEN;
/* B-peripheral session valid override enable*/
USBx->GOTGCTL |= USB_OTG_GOTGCTL_BVALOVAL;
USBx->GOTGCTL |= USB_OTG_GOTGCTL_BVALOEN;
#else
USBx->GCCFG = USB_OTG_GCCFG_PWRDWN | USB_OTG_GCCFG_NOVBUSSENS;
#endif
// be a device, slowest timings
//USBx->GUSBCFG = USB_OTG_GUSBCFG_FDMOD | USB_OTG_GUSBCFG_PHYSEL | USB_OTG_GUSBCFG_TRDT | USB_OTG_GUSBCFG_TOCAL;
//USBx->GUSBCFG |= (uint32_t)((USBD_FS_TRDT_VALUE << 10) & USB_OTG_GUSBCFG_TRDT);
//USBx->GUSBCFG = USB_OTG_GUSBCFG_PHYSEL | USB_OTG_GUSBCFG_TRDT | USB_OTG_GUSBCFG_TOCAL;
// **** for debugging, doesn't seem to work ****
//USBx->GUSBCFG |= USB_OTG_GUSBCFG_CTXPKT;
// reset PHY clock
USBx_PCGCCTL = 0;
// enable the fancy OTG things
// DCFG_FRAME_INTERVAL_80 is 0
//USBx->GUSBCFG |= USB_OTG_GUSBCFG_HNPCAP | USB_OTG_GUSBCFG_SRPCAP;
USBx_DEVICE->DCFG |= USB_OTG_SPEED_FULL | USB_OTG_DCFG_NZLSOHSK;
//USBx_DEVICE->DCFG = USB_OTG_DCFG_NZLSOHSK | USB_OTG_DCFG_DSPD;
//USBx_DEVICE->DCFG = USB_OTG_DCFG_DSPD;
// clear pending interrupts
USBx->GINTSTS = 0xBFFFFFFFU;
// setup USB interrupts
// all interrupts except TXFIFO EMPTY
//USBx->GINTMSK = 0xFFFFFFFF & ~(USB_OTG_GINTMSK_NPTXFEM | USB_OTG_GINTMSK_PTXFEM | USB_OTG_GINTSTS_SOF | USB_OTG_GINTSTS_EOPF);
//USBx->GINTMSK = 0xFFFFFFFF & ~(USB_OTG_GINTMSK_NPTXFEM | USB_OTG_GINTMSK_PTXFEM);
USBx->GINTMSK = USB_OTG_GINTMSK_USBRST | USB_OTG_GINTMSK_ENUMDNEM | USB_OTG_GINTMSK_OTGINT |
USB_OTG_GINTMSK_RXFLVLM | USB_OTG_GINTMSK_GONAKEFFM | USB_OTG_GINTMSK_GINAKEFFM |
USB_OTG_GINTMSK_OEPINT | USB_OTG_GINTMSK_IEPINT | USB_OTG_GINTMSK_USBSUSPM |
USB_OTG_GINTMSK_CIDSCHGM | USB_OTG_GINTMSK_SRQIM | USB_OTG_GINTMSK_MMISM;
USBx->GAHBCFG = USB_OTG_GAHBCFG_GINT;
// DCTL startup value is 2 on new chip, 0 on old chip
USBx_DEVICE->DCTL = 0;
// enable the IRQ
NVIC_EnableIRQ(OTG_FS_IRQn);
}
+49
View File
@@ -0,0 +1,49 @@
#define FAULT_STATUS_NONE 0U
#define FAULT_STATUS_TEMPORARY 1U
#define FAULT_STATUS_PERMANENT 2U
// Fault types
#define FAULT_RELAY_MALFUNCTION (1U << 0)
#define FAULT_UNUSED_INTERRUPT_HANDLED (1U << 1)
#define FAULT_INTERRUPT_RATE_CAN_1 (1U << 2)
#define FAULT_INTERRUPT_RATE_CAN_2 (1U << 3)
#define FAULT_INTERRUPT_RATE_CAN_3 (1U << 4)
#define FAULT_INTERRUPT_RATE_TACH (1U << 5)
#define FAULT_INTERRUPT_RATE_GMLAN (1U << 6)
#define FAULT_INTERRUPT_RATE_INTERRUPTS (1U << 7)
#define FAULT_INTERRUPT_RATE_SPI_DMA (1U << 8)
#define FAULT_INTERRUPT_RATE_SPI_CS (1U << 9)
#define FAULT_INTERRUPT_RATE_UART_1 (1U << 10)
#define FAULT_INTERRUPT_RATE_UART_2 (1U << 11)
#define FAULT_INTERRUPT_RATE_UART_3 (1U << 12)
#define FAULT_INTERRUPT_RATE_UART_5 (1U << 13)
#define FAULT_INTERRUPT_RATE_UART_DMA (1U << 14)
#define FAULT_INTERRUPT_RATE_USB (1U << 15)
#define FAULT_INTERRUPT_RATE_TIM1 (1U << 16)
#define FAULT_INTERRUPT_RATE_TIM3 (1U << 17)
#define FAULT_REGISTER_DIVERGENT (1U << 18)
// Permanent faults
#define PERMANENT_FAULTS 0U
uint8_t fault_status = FAULT_STATUS_NONE;
uint32_t faults = 0U;
void fault_occurred(uint32_t fault) {
faults |= fault;
if((PERMANENT_FAULTS & fault) != 0U){
puts("Permanent fault occurred: 0x"); puth(fault); puts("\n");
fault_status = FAULT_STATUS_PERMANENT;
} else {
puts("Temporary fault occurred: 0x"); puth(fault); puts("\n");
fault_status = FAULT_STATUS_TEMPORARY;
}
}
void fault_recovered(uint32_t fault) {
if((PERMANENT_FAULTS & fault) == 0U){
faults &= ~fault;
} else {
puts("Cannot recover from a permanent fault!\n");
}
}
+3 -7
View File
@@ -23,6 +23,9 @@ void early(void) {
// Reset global critical depth
global_critical_depth = 0;
// Init register and interrupt tables
init_registers();
// neccesary for DFU flashing on a non-power cycled white panda
enable_interrupts();
@@ -59,13 +62,6 @@ void early(void) {
detect_configuration();
detect_board_type();
#ifdef PANDA
// enable the ESP, disable ESP boot mode
// dont disable on grey panda
current_board->set_esp_gps_mode(ESP_GPS_ENABLED);
#endif
if (enter_bootloader_mode == ENTER_BOOTLOADER_MAGIC) {
#ifdef PANDA
current_board->set_esp_gps_mode(ESP_GPS_DISABLED);
+1
View File
@@ -141,6 +141,7 @@ typedef enum
TIM8_TRG_COM_TIM14_IRQn = 45, /*!< TIM8 Trigger and Commutation Interrupt and TIM14 global interrupt */
TIM8_CC_IRQn = 46, /*!< TIM8 Capture Compare global interrupt */
DMA1_Stream7_IRQn = 47, /*!< DMA1 Stream7 Interrupt */
FSMC_IRQn = 48, /*!< FSMC global Interrupt */
SDIO_IRQn = 49, /*!< SDIO global Interrupt */
TIM5_IRQn = 50, /*!< TIM5 global Interrupt */
SPI3_IRQn = 51, /*!< SPI3 global Interrupt */
-25
View File
@@ -40,28 +40,3 @@ int memcmp(const void * ptr1, const void * ptr2, unsigned int num) {
return ret;
}
// ********************* IRQ helpers *********************
volatile bool interrupts_enabled = false;
void enable_interrupts(void) {
interrupts_enabled = true;
__enable_irq();
}
void disable_interrupts(void) {
interrupts_enabled = false;
__disable_irq();
}
uint8_t global_critical_depth = 0U;
#define ENTER_CRITICAL() \
__disable_irq(); \
global_critical_depth += 1U;
#define EXIT_CRITICAL() \
global_critical_depth -= 1U; \
if ((global_critical_depth == 0U) && interrupts_enabled) { \
__enable_irq(); \
}
+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();
}
+2 -1
View File
@@ -11,4 +11,5 @@ void can_set_obd(uint8_t harness_orientation, bool obd);
uint8_t hw_type = 0;
const board *current_board;
bool is_enumerated = 0;
uint32_t heartbeat_counter = 0;
uint32_t heartbeat_counter = 0;
uint32_t uptime_cnt = 0;
+18 -8
View File
@@ -3,7 +3,11 @@
#include "libc.h"
#include "main_declarations.h"
#include "critical.h"
#include "faults.h"
#include "drivers/registers.h"
#include "drivers/interrupts.h"
#include "drivers/llcan.h"
#include "drivers/llgpio.h"
#include "drivers/adc.h"
@@ -129,8 +133,7 @@ uint8_t pedal_checksum(uint8_t *dat, int len) {
#define CAN_GAS_SIZE 6
#define COUNTER_CYCLE 0xFU
// cppcheck-suppress unusedFunction ; used in headers not included in cppcheck
void CAN1_TX_IRQHandler(void) {
void CAN1_TX_IRQ_Handler(void) {
// clear interrupt
CAN->TSR |= CAN_TSR_RQCP0;
}
@@ -152,8 +155,7 @@ uint32_t current_index = 0;
#define FAULT_INVALID 6U
uint8_t state = FAULT_STARTUP;
// cppcheck-suppress unusedFunction ; used in headers not included in cppcheck
void CAN1_RX0_IRQHandler(void) {
void CAN1_RX0_IRQ_Handler(void) {
while ((CAN->RF0R & CAN_RF0R_FMP0) != 0) {
#ifdef DEBUG
puts("CAN RX\n");
@@ -216,8 +218,7 @@ void CAN1_RX0_IRQHandler(void) {
}
}
// cppcheck-suppress unusedFunction ; used in headers not included in cppcheck
void CAN1_SCE_IRQHandler(void) {
void CAN1_SCE_IRQ_Handler(void) {
state = FAULT_SCE;
llcan_clear_send(CAN);
}
@@ -228,8 +229,7 @@ unsigned int pkt_idx = 0;
int led_value = 0;
// cppcheck-suppress unusedFunction ; used in headers not included in cppcheck
void TIM3_IRQHandler(void) {
void TIM3_IRQ_Handler(void) {
#ifdef DEBUG
puth(TIM3->CNT);
puts(" ");
@@ -296,6 +296,16 @@ void pedal(void) {
}
int main(void) {
// Init interrupt table
init_interrupts(true);
REGISTER_INTERRUPT(CAN1_TX_IRQn, CAN1_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
REGISTER_INTERRUPT(CAN1_RX0_IRQn, CAN1_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
REGISTER_INTERRUPT(CAN1_SCE_IRQn, CAN1_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
// Should run at around 732Hz (see init below)
REGISTER_INTERRUPT(TIM3_IRQn, TIM3_IRQ_Handler, 1000U, FAULT_INTERRUPT_RATE_TIM3)
disable_interrupts();
// init devices
+3
View File
@@ -1,3 +1,6 @@
// WARNING: To stay in compliance with the SIL2 rules laid out in STM UM1840, we should never implement any of the available hardware low power modes.
// See rule: CoU_3
#define POWER_SAVE_STATUS_DISABLED 0
#define POWER_SAVE_STATUS_ENABLED 1
+26 -10
View File
@@ -18,7 +18,7 @@
#include "safety/safety_elm327.h"
// from cereal.car.CarParams.SafetyModel
#define SAFETY_NOOUTPUT 0U
#define SAFETY_SILENT 0U
#define SAFETY_HONDA 1U
#define SAFETY_TOYOTA 2U
#define SAFETY_ELM327 3U
@@ -35,8 +35,9 @@
#define SAFETY_TOYOTA_IPAS 16U
#define SAFETY_ALLOUTPUT 17U
#define SAFETY_GM_ASCM 18U
#define SAFETY_NOOUTPUT 19U
uint16_t current_safety_mode = SAFETY_NOOUTPUT;
uint16_t current_safety_mode = SAFETY_SILENT;
const safety_hooks *current_hooks = &nooutput_hooks;
void safety_rx_hook(CAN_FIFOMailBox_TypeDef *to_push){
@@ -55,39 +56,54 @@ int safety_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
return current_hooks->fwd(bus_num, to_fwd);
}
bool addr_allowed(int addr, int bus, const AddrBus addr_list[], int len) {
bool allowed = false;
for (int i = 0; i < len; i++) {
if ((addr == addr_list[i].addr) && (bus == addr_list[i].bus)) {
allowed = true;
break;
}
}
return allowed;
}
typedef struct {
uint16_t id;
const safety_hooks *hooks;
} safety_hook_config;
const safety_hook_config safety_hook_registry[] = {
{SAFETY_NOOUTPUT, &nooutput_hooks},
{SAFETY_SILENT, &nooutput_hooks},
{SAFETY_HONDA, &honda_hooks},
{SAFETY_TOYOTA, &toyota_hooks},
{SAFETY_ELM327, &elm327_hooks},
{SAFETY_GM, &gm_hooks},
{SAFETY_HONDA_BOSCH, &honda_bosch_hooks},
{SAFETY_FORD, &ford_hooks},
{SAFETY_CADILLAC, &cadillac_hooks},
{SAFETY_HYUNDAI, &hyundai_hooks},
{SAFETY_CHRYSLER, &chrysler_hooks},
{SAFETY_TESLA, &tesla_hooks},
{SAFETY_SUBARU, &subaru_hooks},
{SAFETY_MAZDA, &mazda_hooks},
{SAFETY_VOLKSWAGEN, &volkswagen_hooks},
{SAFETY_NOOUTPUT, &nooutput_hooks},
#ifdef ALLOW_DEBUG
{SAFETY_CADILLAC, &cadillac_hooks},
{SAFETY_TOYOTA_IPAS, &toyota_ipas_hooks},
{SAFETY_TESLA, &tesla_hooks},
{SAFETY_ALLOUTPUT, &alloutput_hooks},
{SAFETY_GM_ASCM, &gm_ascm_hooks},
{SAFETY_FORD, &ford_hooks},
#endif
};
int safety_set_mode(uint16_t mode, int16_t param) {
int set_status = -1; // not set
int set_safety_hooks(uint16_t mode, int16_t param) {
safety_mode_cnt = 0U; // reset safety mode timer
int set_status = -1; // not set
int hook_config_count = sizeof(safety_hook_registry) / sizeof(safety_hook_config);
for (int i = 0; i < hook_config_count; i++) {
if (safety_hook_registry[i].id == mode) {
current_hooks = safety_hook_registry[i].hooks;
current_safety_mode = safety_hook_registry[i].id;
set_status = 0; // set
set_status = 0; // set
break;
}
}
@@ -205,7 +221,7 @@ float interpolate(struct lookup_t xy, float x) {
float y0 = xy.y[i];
float dx = xy.x[i+1] - x0;
float dy = xy.y[i+1] - y0;
// dx should not be zero as xy.x is supposed ot be monotonic
// dx should not be zero as xy.x is supposed to be monotonic
if (dx <= 0.) {
dx = 0.0001;
}
+7 -6
View File
@@ -1,5 +1,6 @@
#define CADILLAC_TORQUE_MSG_N 4 // 4 torque messages: 0x151, 0x152, 0x153, 0x154
const AddrBus CADILLAC_TX_MSGS[] = {{0x151, 2}, {0x152, 0}, {0x153, 2}, {0x154, 0}};
const int CADILLAC_MAX_STEER = 150; // 1s
// real time torque limit to prevent controls spamming
// the real time limit is 1500/sec
@@ -55,6 +56,11 @@ static void cadillac_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
static int cadillac_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
int tx = 1;
int addr = GET_ADDR(to_send);
int bus = GET_BUS(to_send);
if (!addr_allowed(addr, bus, CADILLAC_TX_MSGS, sizeof(CADILLAC_TX_MSGS) / sizeof(CADILLAC_TX_MSGS[0]))) {
tx = 0;
}
// steer cmd checks
if ((addr == 0x151) || (addr == 0x152) || (addr == 0x153) || (addr == 0x154)) {
@@ -109,13 +115,8 @@ static int cadillac_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
return tx;
}
static void cadillac_init(int16_t param) {
UNUSED(param);
controls_allowed = 0;
}
const safety_hooks cadillac_hooks = {
.init = cadillac_init,
.init = nooutput_init,
.rx = cadillac_rx_hook,
.tx = cadillac_tx_hook,
.tx_lin = nooutput_tx_lin_hook,
+27 -27
View File
@@ -4,8 +4,8 @@ const uint32_t CHRYSLER_RT_INTERVAL = 250000; // 250ms between real time checks
const int CHRYSLER_MAX_RATE_UP = 3;
const int CHRYSLER_MAX_RATE_DOWN = 3;
const int CHRYSLER_MAX_TORQUE_ERROR = 80; // max torque cmd in excess of torque motor
const AddrBus CHRYSLER_TX_MSGS[] = {{571, 0}, {658, 0}, {678, 0}};
bool chrysler_camera_detected = 0; // is giraffe switch 2 high?
int chrysler_rt_torque_last = 0;
int chrysler_desired_torque_last = 0;
int chrysler_cruise_engaged_last = 0;
@@ -36,23 +36,25 @@ static void chrysler_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
chrysler_cruise_engaged_last = cruise_engaged;
}
// check if stock camera ECU is still online
if ((bus == 0) && (addr == 0x292)) {
chrysler_camera_detected = 1;
controls_allowed = 0;
// check if stock camera ECU is on bus 0
if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == 0x292)) {
relay_malfunction = true;
}
}
static int chrysler_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
int tx = 1;
int addr = GET_ADDR(to_send);
int bus = GET_BUS(to_send);
// If camera is on bus 0, then nothing can be sent
if (chrysler_camera_detected) {
if (!addr_allowed(addr, bus, CHRYSLER_TX_MSGS, sizeof(CHRYSLER_TX_MSGS) / sizeof(CHRYSLER_TX_MSGS[0]))) {
tx = 0;
}
int addr = GET_ADDR(to_send);
if (relay_malfunction) {
tx = 0;
}
// LKA STEER
if (addr == 0x292) {
@@ -100,39 +102,37 @@ static int chrysler_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
}
}
// FORCE CANCEL: safety check only relevant when spamming the cancel button.
// ensuring that only the cancel button press is sent when controls are off.
// This avoids unintended engagements while still allowing resume spam
// TODO: fix bug preventing the button msg to be fwd'd on bus 2
// FORCE CANCEL: only the cancel button press is allowed
if (addr == 571) {
if (GET_BYTE(to_send, 0) != 1) {
tx = 0;
}
}
// 1 allows the message through
return tx;
}
static void chrysler_init(int16_t param) {
UNUSED(param);
controls_allowed = 0;
chrysler_camera_detected = 0;
}
static int chrysler_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
int bus_fwd = -1;
int addr = GET_ADDR(to_fwd);
// forward CAN 0 -> 2 so stock LKAS camera sees messages
if ((bus_num == 0) && !chrysler_camera_detected) {
bus_fwd = 2;
}
// forward all messages from camera except LKAS_COMMAND and LKAS_HUD
if ((bus_num == 2) && !chrysler_camera_detected && (addr != 658) && (addr != 678)) {
bus_fwd = 0;
if (!relay_malfunction) {
// forward CAN 0 -> 2 so stock LKAS camera sees messages
if (bus_num == 0) {
bus_fwd = 2;
}
// forward all messages from camera except LKAS_COMMAND and LKAS_HUD
if ((bus_num == 2) && (addr != 658) && (addr != 678)) {
bus_fwd = 0;
}
}
return bus_fwd;
}
const safety_hooks chrysler_hooks = {
.init = chrysler_init,
.init = nooutput_init,
.rx = chrysler_rx_hook,
.tx = chrysler_tx_hook,
.tx_lin = nooutput_tx_lin_hook,
+4 -2
View File
@@ -6,7 +6,8 @@ void default_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
static void nooutput_init(int16_t param) {
UNUSED(param);
controls_allowed = 0;
controls_allowed = false;
relay_malfunction = false;
}
static int nooutput_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
@@ -39,7 +40,8 @@ const safety_hooks nooutput_hooks = {
static void alloutput_init(int16_t param) {
UNUSED(param);
controls_allowed = 1;
controls_allowed = true;
relay_malfunction = false;
}
static int alloutput_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
+1 -1
View File
@@ -12,7 +12,7 @@ static int elm327_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
//Check valid 29 bit send addresses for ISO 15765-4
//Check valid 11 bit send addresses for ISO 15765-4
if ((addr != 0x18DB33F1) && ((addr & 0x1FFF00FF) != 0x18DA00F1) &&
((addr != 0x7DF) && ((addr & 0x7F8) != 0x7E0))) {
((addr != 0x7DF) && ((addr & 0x1FFFFFF8) != 0x7E0))) {
tx = 0;
}
return tx;
+13 -1
View File
@@ -14,6 +14,7 @@ bool ford_moving = false;
static void ford_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
int addr = GET_ADDR(to_push);
int bus = GET_BUS(to_push);
if (addr == 0x217) {
// wheel speeds are 14 bits every 16
@@ -53,6 +54,10 @@ static void ford_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
}
ford_gas_prev = gas;
}
if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == 0x3CA)) {
relay_malfunction = true;
}
}
// all commands: just steering
@@ -64,11 +69,16 @@ static void ford_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
static int ford_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
int tx = 1;
int addr = GET_ADDR(to_send);
// disallow actuator commands if gas or brake (with vehicle moving) are pressed
// and the the latching controls_allowed flag is True
int pedal_pressed = ford_gas_prev || (ford_brake_prev && ford_moving);
bool current_controls_allowed = controls_allowed && !(pedal_pressed);
int addr = GET_ADDR(to_send);
if (relay_malfunction) {
tx = 0;
}
// STEER: safety check
if (addr == 0x3CA) {
@@ -92,6 +102,8 @@ static int ford_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
return tx;
}
// TODO: keep camera on bus 2 and make a fwd_hook
const safety_hooks ford_hooks = {
.init = nooutput_init,
.rx = ford_rx_hook,
+21 -27
View File
@@ -18,19 +18,21 @@ const int GM_DRIVER_TORQUE_FACTOR = 4;
const int GM_MAX_GAS = 3072;
const int GM_MAX_REGEN = 1404;
const int GM_MAX_BRAKE = 350;
const AddrBus GM_TX_MSGS[] = {{384, 0}, {1033, 0}, {1034, 0}, {715, 0}, {880, 0}, // pt bus
{161, 1}, {774, 1}, {776, 1}, {784, 1}, // obs bus
{789, 2}, // ch bus
{0x104c006c, 3}, {0x10400060, 3}}; // gmlan
int gm_brake_prev = 0;
int gm_gas_prev = 0;
bool gm_moving = false;
// silence everything if stock car control ECUs are still online
bool gm_ascm_detected = 0;
int gm_rt_torque_last = 0;
int gm_desired_torque_last = 0;
uint32_t gm_ts_last = 0;
struct sample_t gm_torque_driver; // last few driver torques measured
static void gm_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
int bus_number = GET_BUS(to_push);
int bus = GET_BUS(to_push);
int addr = GET_ADDR(to_push);
if (addr == 388) {
@@ -46,15 +48,6 @@ static void gm_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
gm_moving = GET_BYTE(to_push, 0) | GET_BYTE(to_push, 1);
}
// Check if ASCM or LKA camera are online
// on powertrain bus.
// 384 = ASCMLKASteeringCmd
// 715 = ASCMGasRegenCmd
if ((bus_number == 0) && ((addr == 384) || (addr == 715))) {
gm_ascm_detected = 1;
controls_allowed = 0;
}
// ACC steering wheel buttons
if (addr == 481) {
int button = (GET_BYTE(to_push, 5) & 0x70) >> 4;
@@ -102,6 +95,14 @@ static void gm_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
controls_allowed = 0;
}
}
// Check if ASCM or LKA camera are online
// on powertrain bus.
// 384 = ASCMLKASteeringCmd
// 715 = ASCMGasRegenCmd
if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && ((addr == 384) || (addr == 715))) {
relay_malfunction = true;
}
}
// all commands: gas/regen, friction brake and steering
@@ -113,9 +114,14 @@ static void gm_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
static int gm_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
int tx = 1;
int addr = GET_ADDR(to_send);
int bus = GET_BUS(to_send);
// There can be only one! (ASCM)
if (gm_ascm_detected) {
if (!addr_allowed(addr, bus, GM_TX_MSGS, sizeof(GM_TX_MSGS)/sizeof(GM_TX_MSGS[0]))) {
tx = 0;
}
if (relay_malfunction) {
tx = 0;
}
@@ -124,8 +130,6 @@ static int gm_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
int pedal_pressed = gm_gas_prev || (gm_brake_prev && gm_moving);
bool current_controls_allowed = controls_allowed && !pedal_pressed;
int addr = GET_ADDR(to_send);
// BRAKE: safety check
if (addr == 789) {
int brake = ((GET_BYTE(to_send, 0) & 0xFU) << 8) + GET_BYTE(to_send, 1);
@@ -188,11 +192,6 @@ static int gm_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
}
}
// PARK ASSIST STEER: unlimited torque, no thanks
if (addr == 823) {
tx = 0;
}
// GAS/REGEN: safety check
if (addr == 715) {
int gas_regen = ((GET_BYTE(to_send, 2) & 0x7FU) << 5) + ((GET_BYTE(to_send, 3) & 0xF8U) >> 3);
@@ -213,14 +212,9 @@ static int gm_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
return tx;
}
static void gm_init(int16_t param) {
UNUSED(param);
controls_allowed = 0;
}
const safety_hooks gm_hooks = {
.init = gm_init,
.init = nooutput_init,
.rx = gm_rx_hook,
.tx = gm_tx_hook,
.tx_lin = nooutput_tx_lin_hook,
+60 -26
View File
@@ -6,7 +6,9 @@
// accel rising edge
// brake rising edge
// brake > 0mph
const AddrBus HONDA_N_TX_MSGS[] = {{0xE4, 0}, {0x194, 0}, {0x1FA, 0}, {0x200, 0}, {0x30C, 0}, {0x33D, 0}, {0x39F, 0}};
const AddrBus HONDA_BH_TX_MSGS[] = {{0xE4, 0}, {0x296, 1}, {0x33D, 0}}; // Bosch Harness
const AddrBus HONDA_BG_TX_MSGS[] = {{0xE4, 2}, {0x296, 0}, {0x33D, 2}}; // Bosch Giraffe
const int HONDA_GAS_INTERCEPTOR_THRESHOLD = 328; // ratio between offset and gain from dbc file
int honda_brake = 0;
int honda_gas_prev = 0;
@@ -95,7 +97,17 @@ static void honda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
} else if (honda_stock_brake >= honda_brake) {
honda_fwd_brake = true;
} else {
// Leave honda forward brake as is
// Leave Honda forward brake as is
}
}
// if steering controls messages are received on the destination bus, it's an indication
// that the relay might be malfunctioning
int bus_rdr_car = (board_has_relay()) ? 0 : 2; // radar bus, car side
if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && ((addr == 0xE4) || (addr == 0x194))) {
if ((honda_bosch_hardware && (bus == bus_rdr_car)) ||
(!honda_bosch_hardware && (bus == 0))) {
relay_malfunction = true;
}
}
}
@@ -112,6 +124,22 @@ static int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
int addr = GET_ADDR(to_send);
int bus = GET_BUS(to_send);
if (honda_bosch_hardware) {
if (board_has_relay() && !addr_allowed(addr, bus, HONDA_BH_TX_MSGS, sizeof(HONDA_BH_TX_MSGS)/sizeof(HONDA_BH_TX_MSGS[0]))) {
tx = 0;
}
if (!board_has_relay() && !addr_allowed(addr, bus, HONDA_BG_TX_MSGS, sizeof(HONDA_BG_TX_MSGS)/sizeof(HONDA_BG_TX_MSGS[0]))) {
tx = 0;
}
}
if (!honda_bosch_hardware && !addr_allowed(addr, bus, HONDA_N_TX_MSGS, sizeof(HONDA_N_TX_MSGS)/sizeof(HONDA_N_TX_MSGS[0]))) {
tx = 0;
}
if (relay_malfunction) {
tx = 0;
}
// disallow actuator commands if gas or brake (with vehicle moving) are pressed
// and the the latching controls_allowed flag is True
int pedal_pressed = honda_gas_prev || (gas_interceptor_prev > HONDA_GAS_INTERCEPTOR_THRESHOLD) ||
@@ -170,13 +198,15 @@ static int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
static void honda_init(int16_t param) {
UNUSED(param);
controls_allowed = 0;
controls_allowed = false;
relay_malfunction = false;
honda_bosch_hardware = false;
honda_alt_brake_msg = false;
}
static void honda_bosch_init(int16_t param) {
controls_allowed = 0;
controls_allowed = false;
relay_malfunction = false;
honda_bosch_hardware = true;
// Checking for alternate brake override from safety parameter
honda_alt_brake_msg = (param == 1) ? true : false;
@@ -189,20 +219,22 @@ static int honda_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
// 0x39f is radar hud
int bus_fwd = -1;
if (bus_num == 0) {
bus_fwd = 2;
}
if (bus_num == 2) {
// block stock lkas messages and stock acc messages (if OP is doing ACC)
int addr = GET_ADDR(to_fwd);
bool is_lkas_msg = (addr == 0xE4) || (addr == 0x194) || (addr == 0x33D);
bool is_acc_hud_msg = (addr == 0x30C) || (addr == 0x39F);
bool is_brake_msg = addr == 0x1FA;
bool block_fwd = is_lkas_msg ||
(is_acc_hud_msg && long_controls_allowed) ||
(is_brake_msg && long_controls_allowed && !honda_fwd_brake);
if (!block_fwd) {
bus_fwd = 0;
if (!relay_malfunction) {
if (bus_num == 0) {
bus_fwd = 2;
}
if (bus_num == 2) {
// block stock lkas messages and stock acc messages (if OP is doing ACC)
int addr = GET_ADDR(to_fwd);
bool is_lkas_msg = (addr == 0xE4) || (addr == 0x194) || (addr == 0x33D);
bool is_acc_hud_msg = (addr == 0x30C) || (addr == 0x39F);
bool is_brake_msg = addr == 0x1FA;
bool block_fwd = is_lkas_msg ||
(is_acc_hud_msg && long_controls_allowed) ||
(is_brake_msg && long_controls_allowed && !honda_fwd_brake);
if (!block_fwd) {
bus_fwd = 0;
}
}
}
return bus_fwd;
@@ -213,14 +245,16 @@ static int honda_bosch_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
int bus_rdr_cam = (board_has_relay()) ? 2 : 1; // radar bus, camera side
int bus_rdr_car = (board_has_relay()) ? 0 : 2; // radar bus, car side
if (bus_num == bus_rdr_car) {
bus_fwd = bus_rdr_cam;
}
if (bus_num == bus_rdr_cam) {
int addr = GET_ADDR(to_fwd);
int is_lkas_msg = (addr == 0xE4) || (addr == 0x33D);
if (!is_lkas_msg) {
bus_fwd = bus_rdr_car;
if (!relay_malfunction) {
if (bus_num == bus_rdr_car) {
bus_fwd = bus_rdr_cam;
}
if (bus_num == bus_rdr_cam) {
int addr = GET_ADDR(to_fwd);
int is_lkas_msg = (addr == 0xE4) || (addr == 0x33D);
if (!is_lkas_msg) {
bus_fwd = bus_rdr_car;
}
}
}
return bus_fwd;
+22 -38
View File
@@ -6,9 +6,8 @@ const int HYUNDAI_MAX_RATE_DOWN = 7;
const int HYUNDAI_DRIVER_TORQUE_ALLOWANCE = 50;
const int HYUNDAI_DRIVER_TORQUE_FACTOR = 2;
bool hyundai_camera_detected = 0;
bool hyundai_giraffe_switch_2 = 0; // is giraffe switch 2 high?
int hyundai_camera_bus = 0;
const AddrBus HYUNDAI_TX_MSGS[] = {{832, 0}, {1265, 0}};
int hyundai_rt_torque_last = 0;
int hyundai_desired_torque_last = 0;
int hyundai_cruise_engaged_last = 0;
@@ -25,15 +24,9 @@ static void hyundai_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
update_sample(&hyundai_torque_driver, torque_driver_new);
}
// check if stock camera ECU is still online
if ((bus == 0) && (addr == 832)) {
hyundai_camera_detected = 1;
controls_allowed = 0;
}
// Find out which bus the camera is on
if (addr == 832) {
hyundai_camera_bus = bus;
// check if stock camera ECU is on bus 0
if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == 832)) {
relay_malfunction = true;
}
// enter controls on rising edge of ACC, exit controls on ACC off
@@ -48,20 +41,19 @@ static void hyundai_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
}
hyundai_cruise_engaged_last = cruise_engaged;
}
// 832 is lkas cmd. If it is on camera bus, then giraffe switch 2 is high
if ((addr == 832) && (bus == hyundai_camera_bus) && (hyundai_camera_bus != 0)) {
hyundai_giraffe_switch_2 = 1;
}
}
static int hyundai_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
int tx = 1;
int addr = GET_ADDR(to_send);
int bus = GET_BUS(to_send);
// There can be only one! (camera)
if (hyundai_camera_detected) {
if (!addr_allowed(addr, bus, HYUNDAI_TX_MSGS, sizeof(HYUNDAI_TX_MSGS)/sizeof(HYUNDAI_TX_MSGS[0]))) {
tx = 0;
}
if (relay_malfunction) {
tx = 0;
}
@@ -115,12 +107,11 @@ static int hyundai_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
// FORCE CANCEL: safety check only relevant when spamming the cancel button.
// ensuring that only the cancel button press is sent (VAL 4) when controls are off.
// This avoids unintended engagements while still allowing resume spam
// TODO: fix bug preventing the button msg to be fwd'd on bus 2
//if ((addr == 1265) && !controls_allowed && (bus == 0) {
// if ((GET_BYTES_04(to_send) & 0x7) != 4) {
// tx = 0;
// }
//}
if ((addr == 1265) && !controls_allowed) {
if ((GET_BYTES_04(to_send) & 0x7) != 4) {
tx = 0;
}
}
// 1 allows the message through
return tx;
@@ -129,29 +120,22 @@ static int hyundai_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
static int hyundai_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
int bus_fwd = -1;
int addr = GET_ADDR(to_fwd);
// forward cam to ccan and viceversa, except lkas cmd
if (hyundai_giraffe_switch_2) {
if (!relay_malfunction) {
if (bus_num == 0) {
bus_fwd = hyundai_camera_bus;
bus_fwd = 2;
}
if (bus_num == hyundai_camera_bus) {
int addr = GET_ADDR(to_fwd);
if (addr != 832) {
bus_fwd = 0;
}
if ((bus_num == 2) && (addr != 832)) {
bus_fwd = 0;
}
}
return bus_fwd;
}
static void hyundai_init(int16_t param) {
UNUSED(param);
controls_allowed = 0;
hyundai_giraffe_switch_2 = 0;
}
const safety_hooks hyundai_hooks = {
.init = hyundai_init,
.init = nooutput_init,
.rx = hyundai_rx_hook,
.tx = hyundai_tx_hook,
.tx_lin = nooutput_tx_lin_hook,
+33 -52
View File
@@ -30,12 +30,6 @@ uint32_t mazda_ts_last = 0;
struct sample_t mazda_torque_driver; // last few driver torques measured
// track msgs coming from OP so that we know what CAM msgs to drop and what to forward
int mazda_op_lkas_detected = 0;
int mazda_op_laneinfo_detected = 0;
int mazda_forward_cam = 0;
int mazda_giraffe_switch_2_on = 0;
void mazda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
int bus = GET_BUS(to_push);
int addr = GET_ADDR(to_push);
@@ -51,7 +45,7 @@ void mazda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
int cruise_engaged = GET_BYTE(to_push, 0) & 8;
if (cruise_engaged != 0) {
if (!mazda_cruise_engaged_last) {
controls_allowed = 1;
controls_allowed = 1;
}
}
else {
@@ -60,17 +54,9 @@ void mazda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
mazda_cruise_engaged_last = cruise_engaged;
}
// we have msgs on bus MAZDA_CAM
if (bus == MAZDA_CAM) {
// the stock CAM is connected
if (addr == MAZDA_LKAS) {
mazda_forward_cam = 1;
}
// if we see wheel speed msgs on MAZDA_CAM bus then giraffe switch 2 is high
// (hardware passthru)
if (addr == MAZDA_WHEEL_SPEED) {
mazda_giraffe_switch_2_on = 1;
}
// if we see wheel speed msgs on MAZDA_CAM bus then relay is closed
if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == MAZDA_CAM) && (addr == MAZDA_WHEEL_SPEED)) {
relay_malfunction = true;
}
}
@@ -79,15 +65,12 @@ static int mazda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
int addr = GET_ADDR(to_send);
int bus = GET_BUS(to_send);
if (relay_malfunction) {
tx = 0;
}
// Check if msg is sent on the main BUS
if (bus == MAZDA_MAIN) {
if ((addr == MAZDA_LKAS) && !mazda_op_lkas_detected){
mazda_op_lkas_detected = 1;
}
if ((addr == MAZDA_LANEINFO) && !mazda_op_laneinfo_detected){
mazda_op_laneinfo_detected = 1;
}
// steer cmd checks
if (addr == MAZDA_LKAS) {
int desired_torque = (((GET_BYTE(to_send, 0) & 0x0f) << 8) | GET_BYTE(to_send, 1)) - MAZDA_MAX_STEER;
@@ -96,42 +79,42 @@ static int mazda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
if (controls_allowed) {
// *** global torque limit check ***
violation |= max_limit_check(desired_torque, MAZDA_MAX_STEER, -MAZDA_MAX_STEER);
// *** global torque limit check ***
violation |= max_limit_check(desired_torque, MAZDA_MAX_STEER, -MAZDA_MAX_STEER);
// *** torque rate limit check ***
int desired_torque_last = mazda_desired_torque_last;
violation |= driver_limit_check(desired_torque, desired_torque_last, &mazda_torque_driver,
MAZDA_MAX_STEER, MAZDA_MAX_RATE_UP, MAZDA_MAX_RATE_DOWN,
MAZDA_DRIVER_TORQUE_ALLOWANCE, MAZDA_DRIVER_TORQUE_FACTOR);
// used next time
mazda_desired_torque_last = desired_torque;
// *** torque rate limit check ***
int desired_torque_last = mazda_desired_torque_last;
violation |= driver_limit_check(desired_torque, desired_torque_last, &mazda_torque_driver,
MAZDA_MAX_STEER, MAZDA_MAX_RATE_UP, MAZDA_MAX_RATE_DOWN,
MAZDA_DRIVER_TORQUE_ALLOWANCE, MAZDA_DRIVER_TORQUE_FACTOR);
// used next time
mazda_desired_torque_last = desired_torque;
// *** torque real time rate limit check ***
violation |= rt_rate_limit_check(desired_torque, mazda_rt_torque_last, MAZDA_MAX_RT_DELTA);
// *** torque real time rate limit check ***
violation |= rt_rate_limit_check(desired_torque, mazda_rt_torque_last, MAZDA_MAX_RT_DELTA);
// every RT_INTERVAL set the new limits
uint32_t ts_elapsed = get_ts_elapsed(ts, mazda_ts_last);
if (ts_elapsed > ((uint32_t) MAZDA_RT_INTERVAL)) {
mazda_rt_torque_last = desired_torque;
mazda_ts_last = ts;
}
// every RT_INTERVAL set the new limits
uint32_t ts_elapsed = get_ts_elapsed(ts, mazda_ts_last);
if (ts_elapsed > ((uint32_t) MAZDA_RT_INTERVAL)) {
mazda_rt_torque_last = desired_torque;
mazda_ts_last = ts;
}
}
// no torque if controls is not allowed
if (!controls_allowed && (desired_torque != 0)) {
violation = 1;
violation = 1;
}
// reset to 0 if either controls is not allowed or there's a violation
if (violation || !controls_allowed) {
mazda_desired_torque_last = 0;
mazda_rt_torque_last = 0;
mazda_ts_last = ts;
mazda_desired_torque_last = 0;
mazda_rt_torque_last = 0;
mazda_ts_last = ts;
}
if (violation) {
tx = 0;
tx = 0;
}
}
}
@@ -140,16 +123,14 @@ static int mazda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
static int mazda_fwd_hook(int bus, CAN_FIFOMailBox_TypeDef *to_fwd) {
int bus_fwd = -1;
if (mazda_forward_cam && !mazda_giraffe_switch_2_on) {
if (!relay_malfunction) {
int addr = GET_ADDR(to_fwd);
if (bus == MAZDA_MAIN) {
bus_fwd = MAZDA_CAM;
}
else if (bus == MAZDA_CAM) {
// drop stock CAM_LKAS and CAM_LANEINFI if OP is sending them
if (!((addr == MAZDA_LKAS) && mazda_op_lkas_detected) &&
!((addr == MAZDA_LANEINFO) && mazda_op_laneinfo_detected)) {
bus_fwd = MAZDA_MAIN;
if (!(addr == MAZDA_LKAS)) {
bus_fwd = MAZDA_MAIN;
}
}
else {
+30 -14
View File
@@ -8,6 +8,8 @@ const int SUBARU_MAX_RATE_DOWN = 70;
const int SUBARU_DRIVER_TORQUE_ALLOWANCE = 60;
const int SUBARU_DRIVER_TORQUE_FACTOR = 10;
const AddrBus SUBARU_TX_MSGS[] = {{0x122, 0}, {0x164, 0}, {0x221, 0}, {0x322, 0}};
int subaru_cruise_engaged_last = 0;
int subaru_rt_torque_last = 0;
int subaru_desired_torque_last = 0;
@@ -38,11 +40,24 @@ static void subaru_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
}
subaru_cruise_engaged_last = cruise_engaged;
}
if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && ((addr == 0x122) || (addr == 0x164))) {
relay_malfunction = true;
}
}
static int subaru_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
int tx = 1;
int addr = GET_ADDR(to_send);
int bus = GET_BUS(to_send);
if (!addr_allowed(addr, bus, SUBARU_TX_MSGS, sizeof(SUBARU_TX_MSGS) / sizeof(SUBARU_TX_MSGS[0]))) {
tx = 0;
}
if (relay_malfunction) {
tx = 0;
}
// steer cmd checks
if ((addr == 0x122) || (addr == 0x164)) {
@@ -98,23 +113,24 @@ static int subaru_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
}
static int subaru_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
int bus_fwd = -1;
if (bus_num == 0) {
bus_fwd = 2; // Camera CAN
}
if (bus_num == 2) {
// 290 is LKAS for Global Platform
// 356 is LKAS for outback 2015
// 545 is ES_Distance
// 802 is ES_LKAS
int addr = GET_ADDR(to_fwd);
int block_msg = (addr == 290) || (addr == 356) || (addr == 545) || (addr == 802);
if (!block_msg) {
bus_fwd = 0; // Main CAN
if (!relay_malfunction) {
if (bus_num == 0) {
bus_fwd = 2; // Camera CAN
}
if (bus_num == 2) {
// 290 is LKAS for Global Platform
// 356 is LKAS for outback 2015
// 545 is ES_Distance
// 802 is ES_LKAS
int addr = GET_ADDR(to_fwd);
int block_msg = (addr == 290) || (addr == 356) || (addr == 545) || (addr == 802);
if (!block_msg) {
bus_fwd = 0; // Main CAN
}
}
}
// fallback to do not forward
return bus_fwd;
}
+20 -20
View File
@@ -18,12 +18,16 @@ const int TOYOTA_MIN_ACCEL = -3000; // 3.0 m/s2
const int TOYOTA_GAS_INTERCEPTOR_THRESHOLD = 475; // ratio between offset and gain from dbc file
// allowed DSU messages on bus 0 and 1
const AddrBus TOYOTA_TX_MSGS[] = {{0x283, 0}, {0x2E6, 0}, {0x2E7, 0}, {0x33E, 0}, {0x344, 0}, {0x365, 0}, {0x366, 0}, {0x4CB, 0}, // DSU bus 0
{0x128, 1}, {0x141, 1}, {0x160, 1}, {0x161, 1}, {0x470, 1}, // DSU bus 1
{0x2E4, 0}, {0x411, 0}, {0x412, 0}, {0x343, 0}, {0x1D2, 0}, // LKAS + ACC
{0x200, 0}}; // interceptor
// global actuation limit states
int toyota_dbc_eps_torque_factor = 100; // conversion factor for STEER_TORQUE_EPS in %: see dbc file
// states
int toyota_giraffe_switch_1 = 0; // is giraffe switch 1 high?
int toyota_camera_forwarded = 0; // should we forward the camera bus?
int toyota_desired_torque_last = 0; // last desired steer torque
int toyota_rt_torque_last = 0; // last desired torque for real time check
uint32_t toyota_ts_last = 0;
@@ -87,14 +91,9 @@ static void toyota_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
toyota_gas_prev = gas;
}
// msgs are only on bus 2 if panda is connected to frc
if (bus == 2) {
toyota_camera_forwarded = 1;
}
// 0x2E4 is lkas cmd. If it is on bus 0, then giraffe switch 1 is high
if ((addr == 0x2E4) && (bus == 0)) {
toyota_giraffe_switch_1 = 1;
// 0x2E4 is lkas cmd. If it is on bus 0, then relay is unexpectedly closed
if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (addr == 0x2E4) && (bus == 0)) {
relay_malfunction = true;
}
}
@@ -104,14 +103,17 @@ static int toyota_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
int addr = GET_ADDR(to_send);
int bus = GET_BUS(to_send);
if (!addr_allowed(addr, bus, TOYOTA_TX_MSGS, sizeof(TOYOTA_TX_MSGS)/sizeof(TOYOTA_TX_MSGS[0]))) {
tx = 0;
}
if (relay_malfunction) {
tx = 0;
}
// Check if msg is sent on BUS 0
if (bus == 0) {
// no IPAS in non IPAS mode
if ((addr == 0x266) || (addr == 0x167)) {
tx = 0;
}
// GAS PEDAL: safety check
if (addr == 0x200) {
if (!controls_allowed || !long_controls_allowed) {
@@ -185,28 +187,26 @@ static int toyota_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
}
}
// 1 allows the message through
return tx;
}
static void toyota_init(int16_t param) {
controls_allowed = 0;
toyota_giraffe_switch_1 = 0;
toyota_camera_forwarded = 0;
relay_malfunction = 0;
toyota_dbc_eps_torque_factor = param;
}
static int toyota_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
int bus_fwd = -1;
if (toyota_camera_forwarded && !toyota_giraffe_switch_1) {
if (!relay_malfunction) {
if (bus_num == 0) {
bus_fwd = 2;
}
if (bus_num == 2) {
int addr = GET_ADDR(to_fwd);
// block stock lkas messages and stock acc messages (if OP is doing ACC)
// in TSS2, 0.191 is LTA which we need to block to avoid controls collision
// in TSS2, 0x191 is LTA which we need to block to avoid controls collision
int is_lkas_msg = ((addr == 0x2E4) || (addr == 0x412) || (addr == 0x191));
// in TSS2 the camera does ACC as well, so filter 0x343
int is_acc_msg = (addr == 0x343);
+44 -34
View File
@@ -1,3 +1,11 @@
// Safety-relevant CAN messages for the Volkswagen MQB platform.
#define MSG_EPS_01 0x09F
#define MSG_MOTOR_20 0x121
#define MSG_ACC_06 0x122
#define MSG_HCA_01 0x126
#define MSG_GRA_ACC_01 0x12B
#define MSG_LDW_02 0x397
const int VOLKSWAGEN_MAX_STEER = 250; // 2.5 Nm (EPS side max of 3.0Nm with fault if violated)
const int VOLKSWAGEN_MAX_RT_DELTA = 75; // 4 max rate up * 50Hz send rate * 250000 RT interval / 1000000 = 50 ; 50 * 1.5 for safety pad = 75
const uint32_t VOLKSWAGEN_RT_INTERVAL = 250000; // 250ms between real time checks
@@ -6,26 +14,15 @@ const int VOLKSWAGEN_MAX_RATE_DOWN = 10; // 5.0 Nm/s available rate o
const int VOLKSWAGEN_DRIVER_TORQUE_ALLOWANCE = 80;
const int VOLKSWAGEN_DRIVER_TORQUE_FACTOR = 3;
// MSG_GRA_ACC_01 is allowed on bus 0 and 2 to keep compatibility with gateway and camera integration
const AddrBus VOLKSWAGEN_TX_MSGS[] = {{MSG_HCA_01, 0}, {MSG_GRA_ACC_01, 0}, {MSG_GRA_ACC_01, 2}, {MSG_LDW_02, 0}};
struct sample_t volkswagen_torque_driver; // last few driver torques measured
int volkswagen_rt_torque_last = 0;
int volkswagen_desired_torque_last = 0;
uint32_t volkswagen_ts_last = 0;
int volkswagen_gas_prev = 0;
// Safety-relevant CAN messages for the Volkswagen MQB platform.
#define MSG_EPS_01 0x09F
#define MSG_MOTOR_20 0x121
#define MSG_ACC_06 0x122
#define MSG_HCA_01 0x126
#define MSG_GRA_ACC_01 0x12B
#define MSG_LDW_02 0x397
#define MSG_KLEMMEN_STATUS_01 0x3C0
static void volkswagen_init(int16_t param) {
UNUSED(param); // May use param in the future to indicate MQB vs PQ35/PQ46/NMS vs MLB, or wiring configuration.
controls_allowed = 0;
}
static void volkswagen_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
int bus = GET_BUS(to_push);
int addr = GET_ADDR(to_push);
@@ -58,6 +55,10 @@ static void volkswagen_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
}
volkswagen_gas_prev = gas;
}
if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == MSG_HCA_01)) {
relay_malfunction = true;
}
}
static int volkswagen_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
@@ -65,6 +66,14 @@ static int volkswagen_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
int bus = GET_BUS(to_send);
int tx = 1;
if (!addr_allowed(addr, bus, VOLKSWAGEN_TX_MSGS, sizeof(VOLKSWAGEN_TX_MSGS)/sizeof(VOLKSWAGEN_TX_MSGS[0]))) {
tx = 0;
}
if (relay_malfunction) {
tx = 0;
}
// Safety check for HCA_01 Heading Control Assist torque.
if (addr == MSG_HCA_01) {
bool violation = false;
@@ -118,7 +127,7 @@ static int volkswagen_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
// FORCE CANCEL: ensuring that only the cancel button press is sent when controls are off.
// This avoids unintended engagements while still allowing resume spam
if ((bus == 2) && (addr == MSG_GRA_ACC_01) && !controls_allowed) {
if ((addr == MSG_GRA_ACC_01) && !controls_allowed) {
// disallow resume and set: bits 16 and 19
if ((GET_BYTE(to_send, 2) & 0x9) != 0) {
tx = 0;
@@ -135,31 +144,32 @@ static int volkswagen_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
// NOTE: Will need refactoring for other bus layouts, such as no-forwarding at camera or J533 running-gear CAN
switch (bus_num) {
case 0:
// Forward all traffic from J533 gateway to Extended CAN devices.
bus_fwd = 2;
break;
case 2:
if ((addr == MSG_HCA_01) || (addr == MSG_LDW_02)) {
// OP takes control of the Heading Control Assist and Lane Departure Warning messages from the camera.
if (!relay_malfunction) {
switch (bus_num) {
case 0:
// Forward all traffic from J533 gateway to Extended CAN devices.
bus_fwd = 2;
break;
case 2:
if ((addr == MSG_HCA_01) || (addr == MSG_LDW_02)) {
// OP takes control of the Heading Control Assist and Lane Departure Warning messages from the camera.
bus_fwd = -1;
} else {
// Forward all remaining traffic from Extended CAN devices to J533 gateway.
bus_fwd = 0;
}
break;
default:
// No other buses should be in use; fallback to do-not-forward.
bus_fwd = -1;
} else {
// Forward all remaining traffic from Extended CAN devices to J533 gateway.
bus_fwd = 0;
}
break;
default:
// No other buses should be in use; fallback to do-not-forward.
bus_fwd = -1;
break;
break;
}
}
return bus_fwd;
}
const safety_hooks volkswagen_hooks = {
.init = volkswagen_init,
.init = nooutput_init,
.rx = volkswagen_rx_hook,
.tx = volkswagen_tx_hook,
.tx_lin = nooutput_tx_lin_hook,
+16 -4
View File
@@ -11,6 +11,11 @@ struct lookup_t {
float y[3];
};
typedef struct {
int addr;
int bus;
} AddrBus;
void safety_rx_hook(CAN_FIFOMailBox_TypeDef *to_push);
int safety_tx_hook(CAN_FIFOMailBox_TypeDef *to_send);
int safety_tx_lin_hook(int lin_num, uint8_t *data, int len);
@@ -25,6 +30,7 @@ bool driver_limit_check(int val, int val_last, struct sample_t *val_driver,
const int MAX_ALLOWANCE, const int DRIVER_FACTOR);
bool rt_rate_limit_check(int val, int val_last, const int MAX_RT_DELTA);
float interpolate(struct lookup_t xy, float x);
bool addr_allowed(int addr, int bus, const AddrBus addr_list[], int len);
typedef void (*safety_hook_init)(int16_t param);
typedef void (*rx_hook)(CAN_FIFOMailBox_TypeDef *to_push);
@@ -40,13 +46,19 @@ typedef struct {
fwd_hook fwd;
} safety_hooks;
// This can be set by the safety hooks.
bool controls_allowed = 0;
bool gas_interceptor_detected = 0;
// This can be set by the safety hooks
bool controls_allowed = false;
bool relay_malfunction = false;
bool gas_interceptor_detected = false;
int gas_interceptor_prev = 0;
// This is set by USB command 0xdf
bool long_controls_allowed = 1;
bool long_controls_allowed = true;
// time since safety mode has been changed
uint32_t safety_mode_cnt = 0U;
// allow 1s of transition timeout after relay changes state before assessing malfunctioning
const uint32_t RELAY_TRNS_TIMEOUT = 1U;
// avg between 2 tracks
#define GET_INTERCEPTOR(msg) (((GET_BYTE((msg), 0) << 8) + GET_BYTE((msg), 1) + ((GET_BYTE((msg), 2) << 8) + GET_BYTE((msg), 3)) / 2 ) / 2)
+14 -3
View File
@@ -65,7 +65,12 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired)
// so it's blocked over wifi
switch (setup->b.wValue.w) {
case 0:
#ifdef ALLOW_DEBUG
if (hardwired) {
#else
// no more bootstub on UNO
if (hardwired && hw_type != HW_TYPE_UNO) {
#endif
puts("-> entering bootloader\n");
enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC;
NVIC_SystemReset();
@@ -151,7 +156,7 @@ int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) {
#define CAN_BL_INPUT 0x1
#define CAN_BL_OUTPUT 0x2
void CAN1_TX_IRQHandler(void) {
void CAN1_TX_IRQ_Handler(void) {
// clear interrupt
CAN->TSR |= CAN_TSR_RQCP0;
}
@@ -178,7 +183,7 @@ void bl_can_send(uint8_t *odat) {
CAN->sTxMailBox[0].TIR = (CAN_BL_OUTPUT << 21) | 1;
}
void CAN1_RX0_IRQHandler(void) {
void CAN1_RX0_IRQ_Handler(void) {
while (CAN->RF0R & CAN_RF0R_FMP0) {
if ((CAN->sFIFOMailBox[0].RIR>>21) == CAN_BL_INPUT) {
uint8_t dat[8];
@@ -253,13 +258,19 @@ void CAN1_RX0_IRQHandler(void) {
}
}
void CAN1_SCE_IRQHandler(void) {
void CAN1_SCE_IRQ_Handler(void) {
llcan_clear_send(CAN);
}
#endif
void soft_flasher_start(void) {
#ifdef PEDAL
REGISTER_INTERRUPT(CAN1_TX_IRQn, CAN1_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
REGISTER_INTERRUPT(CAN1_RX0_IRQn, CAN1_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
REGISTER_INTERRUPT(CAN1_SCE_IRQn, CAN1_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
#endif
puts("\n\n\n************************ FLASHER START ************************\n");
enter_bootloader_mode = 0;