Merge panda subtree

pull/689/head
Vehicle Researcher 6 years ago
commit 0829b0a767
  1. 37
      panda/.circleci/config.yml
  2. 5
      panda/.gitignore
  3. 2
      panda/Dockerfile
  4. 2
      panda/Jenkinsfile
  5. 2
      panda/VERSION
  6. 9
      panda/board/Makefile.legacy
  7. 8
      panda/board/Makefile.strict
  8. 6
      panda/board/README.md
  9. 16
      panda/board/bootstub.c
  10. 277
      panda/board/drivers/can.h
  11. 40
      panda/board/drivers/clock.h
  12. 141
      panda/board/drivers/drivers.h
  13. 3
      panda/board/drivers/gmlan_alt.h
  14. 80
      panda/board/drivers/llcan.h
  15. 9
      panda/board/drivers/llgpio.h
  16. 88
      panda/board/drivers/lline_relay.h
  17. 11
      panda/board/drivers/spi.h
  18. 22
      panda/board/drivers/uart.h
  19. 48
      panda/board/drivers/usb.h
  20. 77
      panda/board/gpio.h
  21. 488
      panda/board/main.c
  22. 44
      panda/board/pedal/main.c
  23. 140
      panda/board/power_saving.h
  24. 29
      panda/board/safety.h
  25. 4
      panda/board/safety/safety_cadillac.h
  26. 4
      panda/board/safety/safety_chrysler.h
  27. 16
      panda/board/safety/safety_defaults.h
  28. 17
      panda/board/safety/safety_elm327.h
  29. 1
      panda/board/safety/safety_ford.h
  30. 10
      panda/board/safety/safety_gm.h
  31. 1
      panda/board/safety/safety_gm_ascm.h
  32. 61
      panda/board/safety/safety_honda.h
  33. 4
      panda/board/safety/safety_hyundai.h
  34. 4
      panda/board/safety/safety_subaru.h
  35. 22
      panda/board/safety/safety_tesla.h
  36. 97
      panda/board/safety/safety_toyota.h
  37. 1
      panda/board/safety/safety_toyota_ipas.h
  38. 11
      panda/board/spi_flasher.h
  39. BIN
      panda/buy.png
  40. 4
      panda/examples/query_vin_and_stats.py
  41. 3
      panda/python/__init__.py
  42. 7
      panda/run_automated_tests.sh
  43. 6
      panda/tests/automated/0_builds.py
  44. 2
      panda/tests/automated/3_wifi.py
  45. 9
      panda/tests/build_strict/Dockerfile
  46. 6
      panda/tests/misra/Dockerfile
  47. 8
      panda/tests/misra/test_misra.sh
  48. 14
      panda/tests/safety/libpandasafety_py.py
  49. 55
      panda/tests/safety/test.c
  50. 47
      panda/tests/safety/test_gm.py
  51. 101
      panda/tests/safety/test_honda.py
  52. 120
      panda/tests/safety/test_toyota.py

@ -12,6 +12,37 @@ jobs:
name: Run safety test name: Run safety test
command: | command: |
docker run panda_safety /bin/bash -c "cd /panda/tests/safety; ./test.sh" docker run panda_safety /bin/bash -c "cd /panda/tests/safety; ./test.sh"
misra-c2012:
machine:
docker_layer_caching: true
steps:
- checkout
- run:
name: Build image
command: "docker build -t panda_misra -f tests/misra/Dockerfile ."
- run:
name: Run Misra C 2012 test
command: |
mkdir /tmp/misra
docker run -v /tmp/misra:/tmp/misra panda_misra /bin/bash -c "cd /panda/tests/misra; ./test_misra.sh"
- store_artifacts:
name: Store misra test output
path: /tmp/misra/output.txt
strict-compiler:
machine:
docker_layer_caching: true
steps:
- checkout
- run:
name: Build image
command: "docker build -t panda_strict_compiler -f tests/build_strict/Dockerfile ."
- run:
name: Build Panda with strict compiler rules
command: |
docker run panda_strict_compiler /bin/bash -c "cd /panda/board; make -f Makefile.strict clean; make -f Makefile.strict bin"
build: build:
machine: machine:
docker_layer_caching: true docker_layer_caching: true
@ -40,10 +71,6 @@ jobs:
name: Build Pedal STM bootstub image name: Build Pedal STM bootstub image
command: | command: |
docker run panda_build /bin/bash -c "cd /panda/board/pedal; make obj/bootstub.bin" docker run panda_build /bin/bash -c "cd /panda/board/pedal; make obj/bootstub.bin"
- run:
name: Build NEO STM image
command: |
docker run panda_build /bin/bash -c "cd /panda/board; make clean; make -f Makefile.legacy obj/comma.bin"
- run: - run:
name: Build ESP image name: Build ESP image
command: | command: |
@ -54,4 +81,6 @@ workflows:
main: main:
jobs: jobs:
- safety - safety
- misra-c2012
- strict-compiler
- build - build

5
panda/.gitignore vendored

@ -10,5 +10,6 @@ a.out
dist/ dist/
pandacan.egg-info/ pandacan.egg-info/
board/obj/ board/obj/
examples/output.csv examples/output.csv
.DS_Store .DS_Store
nosetests.xml

@ -59,6 +59,4 @@ USER pandauser
RUN cd /tmp/panda/boardesp && ./get_sdk_ci.sh RUN cd /tmp/panda/boardesp && ./get_sdk_ci.sh
USER root USER root
COPY ./xx/pandaextra /tmp/pandaextra
ADD ./panda.tar.gz /tmp/panda ADD ./panda.tar.gz /tmp/panda

2
panda/Jenkinsfile vendored

@ -14,8 +14,6 @@ pipeline {
steps { steps {
timeout(time: 60, unit: 'MINUTES') { timeout(time: 60, unit: 'MINUTES') {
script { script {
sh 'git clone --no-checkout --depth 1 git@github.com:commaai/xx.git || true'
sh 'cd xx && git fetch origin && git checkout origin/master -- pandaextra && cd ..' // Needed for certs for panda flashing
sh 'git archive -v -o panda.tar.gz --format=tar.gz HEAD' sh 'git archive -v -o panda.tar.gz --format=tar.gz HEAD'
dockerImage = docker.build("${env.DOCKER_IMAGE_TAG}") dockerImage = docker.build("${env.DOCKER_IMAGE_TAG}")
} }

@ -1 +1 @@
v1.2.1 v1.3.1

@ -1,9 +0,0 @@
# :set noet
PROJ_NAME = comma
CFLAGS = -g -Wall
CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m3
CFLAGS += -msoft-float -DSTM32F2 -DSTM32F205xx
STARTUP_FILE = startup_stm32f205xx
include build.mk

@ -0,0 +1,8 @@
PROJ_NAME = panda
CFLAGS = -g -Wall -Wextra -pedantic -Wstrict-prototypes
CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4
CFLAGS += -mhard-float -DSTM32F4 -DSTM32F413xx -mfpu=fpv4-sp-d16 -fsingle-precision-constant
STARTUP_FILE = startup_stm32f413xx
include build.mk

@ -23,12 +23,6 @@ Programming
make make
``` ```
**NEO**
```
make -f Makefile.legacy
```
Troubleshooting Troubleshooting
---- ----

@ -12,11 +12,14 @@
#include "stm32f2xx_hal_gpio_ex.h" #include "stm32f2xx_hal_gpio_ex.h"
#endif #endif
// default since there's no serial
int puts(const char *a) { return 0; }
void puth(unsigned int i) {}
#include "libc.h" #include "libc.h"
#include "provision.h" #include "provision.h"
#include "drivers/drivers.h" #include "drivers/clock.h"
#include "drivers/llgpio.h" #include "drivers/llgpio.h"
#include "gpio.h" #include "gpio.h"
@ -24,15 +27,6 @@
#include "drivers/usb.h" #include "drivers/usb.h"
//#include "drivers/uart.h" //#include "drivers/uart.h"
#ifdef PEDAL
#define CUSTOM_CAN_INTERRUPTS
#include "safety.h"
#include "drivers/can.h"
#endif
int puts(const char *a) { return 0; }
void puth(unsigned int i) {}
#include "crypto/rsa.h" #include "crypto/rsa.h"
#include "crypto/sha.h" #include "crypto/sha.h"

@ -1,10 +1,38 @@
// IRQs: CAN1_TX, CAN1_RX0, CAN1_SCE, CAN2_TX, CAN2_RX0, CAN2_SCE, CAN3_TX, CAN3_RX0, CAN3_SCE // IRQs: CAN1_TX, CAN1_RX0, CAN1_SCE
// CAN2_TX, CAN2_RX0, CAN2_SCE
// CAN3_TX, CAN3_RX0, CAN3_SCE
typedef struct {
uint32_t w_ptr;
uint32_t r_ptr;
uint32_t fifo_size;
CAN_FIFOMailBox_TypeDef *elems;
} can_ring;
#define CAN_BUS_RET_FLAG 0x80
#define CAN_BUS_NUM_MASK 0x7F
#define BUS_MAX 4
extern int can_live, pending_can_live;
// must reinit after changing these
extern int can_loopback, can_silent;
extern uint32_t can_speed[];
void can_set_forwarding(int from, int to);
void can_init(uint8_t can_number);
void can_init_all();
void can_send(CAN_FIFOMailBox_TypeDef *to_push, uint8_t bus_number);
int can_pop(can_ring *q, CAN_FIFOMailBox_TypeDef *elem);
// end API
#define ALL_CAN_SILENT 0xFF #define ALL_CAN_SILENT 0xFF
#define ALL_CAN_BUT_MAIN_SILENT 0xFE #define ALL_CAN_BUT_MAIN_SILENT 0xFE
#define ALL_CAN_LIVE 0 #define ALL_CAN_LIVE 0
#include "lline_relay.h"
int can_live = 0, pending_can_live = 0, can_loopback = 0, can_silent = ALL_CAN_SILENT; int can_live = 0, pending_can_live = 0, can_loopback = 0, can_silent = ALL_CAN_SILENT;
// ********************* instantiate queues ********************* // ********************* instantiate queues *********************
@ -16,19 +44,9 @@ int can_live = 0, pending_can_live = 0, can_loopback = 0, can_silent = ALL_CAN_S
can_buffer(rx_q, 0x1000) can_buffer(rx_q, 0x1000)
can_buffer(tx1_q, 0x100) can_buffer(tx1_q, 0x100)
can_buffer(tx2_q, 0x100) can_buffer(tx2_q, 0x100)
can_buffer(tx3_q, 0x100)
#ifdef PANDA can_buffer(txgmlan_q, 0x100)
can_buffer(tx3_q, 0x100) can_ring *can_queues[] = {&can_tx1_q, &can_tx2_q, &can_tx3_q, &can_txgmlan_q};
can_buffer(txgmlan_q, 0x100)
can_ring *can_queues[] = {&can_tx1_q, &can_tx2_q, &can_tx3_q, &can_txgmlan_q};
#else
can_ring *can_queues[] = {&can_tx1_q, &can_tx2_q};
#endif
#ifdef PANDA
// Forward declare
void power_save_reset_timer();
#endif
// ********************* interrupt safe queue ********************* // ********************* interrupt safe queue *********************
@ -85,76 +103,20 @@ int can_tx_cnt = 0;
int can_txd_cnt = 0; int can_txd_cnt = 0;
int can_err_cnt = 0; int can_err_cnt = 0;
// NEO: Bus 1=CAN1 Bus 2=CAN2
// Panda: Bus 0=CAN1 Bus 1=CAN2 Bus 2=CAN3 // Panda: Bus 0=CAN1 Bus 1=CAN2 Bus 2=CAN3
#ifdef PANDA CAN_TypeDef *cans[] = {CAN1, CAN2, CAN3};
CAN_TypeDef *cans[] = {CAN1, CAN2, CAN3}; uint8_t bus_lookup[] = {0,1,2};
uint8_t bus_lookup[] = {0,1,2}; uint8_t can_num_lookup[] = {0,1,2,-1};
uint8_t can_num_lookup[] = {0,1,2,-1}; int8_t can_forwarding[] = {-1,-1,-1,-1};
int8_t can_forwarding[] = {-1,-1,-1,-1}; uint32_t can_speed[] = {5000, 5000, 5000, 333};
uint32_t can_speed[] = {5000, 5000, 5000, 333}; #define CAN_MAX 3
bool can_autobaud_enabled[] = {false, false, false, false};
#define CAN_MAX 3
#else
CAN_TypeDef *cans[] = {CAN1, CAN2};
uint8_t bus_lookup[] = {1,0};
uint8_t can_num_lookup[] = {1,0};
int8_t can_forwarding[] = {-1,-1};
uint32_t can_speed[] = {5000, 5000};
bool can_autobaud_enabled[] = {false, false};
#define CAN_MAX 2
#endif
uint32_t can_autobaud_speeds[] = {5000, 2500, 1250, 1000, 10000};
#define AUTOBAUD_SPEEDS_LEN (sizeof(can_autobaud_speeds) / sizeof(can_autobaud_speeds[0]))
#define CANIF_FROM_CAN_NUM(num) (cans[num]) #define CANIF_FROM_CAN_NUM(num) (cans[num])
#ifdef PANDA
#define CAN_NUM_FROM_CANIF(CAN) (CAN==CAN1 ? 0 : (CAN==CAN2 ? 1 : 2)) #define CAN_NUM_FROM_CANIF(CAN) (CAN==CAN1 ? 0 : (CAN==CAN2 ? 1 : 2))
#define CAN_NAME_FROM_CANIF(CAN) (CAN==CAN1 ? "CAN1" : (CAN==CAN2 ? "CAN2" : "CAN3")) #define CAN_NAME_FROM_CANIF(CAN) (CAN==CAN1 ? "CAN1" : (CAN==CAN2 ? "CAN2" : "CAN3"))
#else
#define CAN_NUM_FROM_CANIF(CAN) (CAN==CAN1 ? 0 : 1)
#define CAN_NAME_FROM_CANIF(CAN) (CAN==CAN1 ? "CAN1" : "CAN2")
#endif
#define BUS_NUM_FROM_CAN_NUM(num) (bus_lookup[num]) #define BUS_NUM_FROM_CAN_NUM(num) (bus_lookup[num])
#define CAN_NUM_FROM_BUS_NUM(num) (can_num_lookup[num]) #define CAN_NUM_FROM_BUS_NUM(num) (can_num_lookup[num])
// other option
/*#define CAN_QUANTA 16
#define CAN_SEQ1 13
#define CAN_SEQ2 2*/
// this is needed for 1 mbps support
#define CAN_QUANTA 8
#define CAN_SEQ1 6 // roundf(quanta * 0.875f) - 1;
#define CAN_SEQ2 1 // roundf(quanta * 0.125f);
#define CAN_PCLK 24000
// 333 = 33.3 kbps
// 5000 = 500 kbps
#define can_speed_to_prescaler(x) (CAN_PCLK / CAN_QUANTA * 10 / (x))
void can_autobaud_speed_increment(uint8_t can_number) {
uint32_t autobaud_speed = can_autobaud_speeds[0];
uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number);
for (int i = 0; i < AUTOBAUD_SPEEDS_LEN; i++) {
if (can_speed[bus_number] == can_autobaud_speeds[i]) {
if (i+1 < AUTOBAUD_SPEEDS_LEN) {
autobaud_speed = can_autobaud_speeds[i+1];
}
break;
}
}
can_speed[bus_number] = autobaud_speed;
#ifdef DEBUG
CAN_TypeDef* CAN = CANIF_FROM_CAN_NUM(can_number);
puts(CAN_NAME_FROM_CANIF(CAN));
puts(" auto-baud test ");
putui(can_speed[bus_number]);
puts(" cbps\n");
#endif
}
void process_can(uint8_t can_number); void process_can(uint8_t can_number);
void can_set_speed(uint8_t can_number) { void can_set_speed(uint8_t can_number) {
@ -162,41 +124,14 @@ void can_set_speed(uint8_t can_number) {
uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number); uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number);
while (true) { while (true) {
// initialization mode if (llcan_set_speed(CAN, can_speed[bus_number], can_loopback, can_silent & (1 << can_number))) {
CAN->MCR = CAN_MCR_TTCM | CAN_MCR_INRQ;
while((CAN->MSR & CAN_MSR_INAK) != CAN_MSR_INAK);
// set time quanta from defines
CAN->BTR = (CAN_BTR_TS1_0 * (CAN_SEQ1-1)) |
(CAN_BTR_TS2_0 * (CAN_SEQ2-1)) |
(can_speed_to_prescaler(can_speed[bus_number]) - 1);
// silent loopback mode for debugging
if (can_loopback) {
CAN->BTR |= CAN_BTR_SILM | CAN_BTR_LBKM;
}
if (can_silent & (1 << can_number)) {
CAN->BTR |= CAN_BTR_SILM;
}
// reset
CAN->MCR = CAN_MCR_TTCM | CAN_MCR_ABOM;
#define CAN_TIMEOUT 1000000
int tmp = 0;
while((CAN->MSR & CAN_MSR_INAK) == CAN_MSR_INAK && tmp < CAN_TIMEOUT) tmp++;
if (tmp < CAN_TIMEOUT) {
return; return;
} }
if (can_autobaud_enabled[bus_number]) { puts("CAN init FAILED!!!!!\n");
can_autobaud_speed_increment(can_number); puth(can_number); puts(" ");
} else { puth(BUS_NUM_FROM_CAN_NUM(can_number)); puts("\n");
puts("CAN init FAILED!!!!!\n"); return;
puth(can_number); puts(" ");
puth(BUS_NUM_FROM_CAN_NUM(can_number)); puts("\n");
return;
}
} }
} }
@ -207,40 +142,7 @@ void can_init(uint8_t can_number) {
set_can_enable(CAN, 1); set_can_enable(CAN, 1);
can_set_speed(can_number); can_set_speed(can_number);
// accept all filter llcan_init(CAN);
CAN->FMR |= CAN_FMR_FINIT;
// no mask
CAN->sFilterRegister[0].FR1 = 0;
CAN->sFilterRegister[0].FR2 = 0;
CAN->sFilterRegister[14].FR1 = 0;
CAN->sFilterRegister[14].FR2 = 0;
CAN->FA1R |= 1 | (1 << 14);
CAN->FMR &= ~(CAN_FMR_FINIT);
// enable certain CAN interrupts
CAN->IER |= CAN_IER_TMEIE | CAN_IER_FMPIE0 | CAN_IER_WKUIE;
switch (can_number) {
case 0:
NVIC_EnableIRQ(CAN1_TX_IRQn);
NVIC_EnableIRQ(CAN1_RX0_IRQn);
NVIC_EnableIRQ(CAN1_SCE_IRQn);
break;
case 1:
NVIC_EnableIRQ(CAN2_TX_IRQn);
NVIC_EnableIRQ(CAN2_RX0_IRQn);
NVIC_EnableIRQ(CAN2_SCE_IRQn);
break;
#ifdef CAN3
case 2:
NVIC_EnableIRQ(CAN3_TX_IRQn);
NVIC_EnableIRQ(CAN3_RX0_IRQn);
NVIC_EnableIRQ(CAN3_SCE_IRQn);
break;
#endif
}
// in case there are queued up messages // in case there are queued up messages
process_can(can_number); process_can(can_number);
@ -253,7 +155,6 @@ void can_init_all() {
} }
void can_set_gmlan(int bus) { void can_set_gmlan(int bus) {
#ifdef PANDA
if (bus == -1 || bus != can_num_lookup[3]) { if (bus == -1 || bus != can_num_lookup[3]) {
// GMLAN OFF // GMLAN OFF
switch (can_num_lookup[3]) { switch (can_num_lookup[3]) {
@ -284,7 +185,7 @@ void can_set_gmlan(int bus) {
can_num_lookup[1] = -1; can_num_lookup[1] = -1;
can_num_lookup[3] = 1; can_num_lookup[3] = 1;
can_init(1); can_init(1);
} else if (bus == 2 && revision == PANDA_REV_C) { } else if (bus == 2) {
puts("GMLAN on CAN3\n"); puts("GMLAN on CAN3\n");
// GMLAN on CAN3 // GMLAN on CAN3
set_can_mode(2, 1); set_can_mode(2, 1);
@ -293,7 +194,6 @@ void can_set_gmlan(int bus) {
can_num_lookup[3] = 2; can_num_lookup[3] = 2;
can_init(2); can_init(2);
} }
#endif
} }
// CAN error // CAN error
@ -319,34 +219,8 @@ void can_sce(CAN_TypeDef *CAN) {
puts("\n"); puts("\n");
#endif #endif
uint8_t can_number = CAN_NUM_FROM_CANIF(CAN); can_err_cnt += 1;
uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number); llcan_clear_send(CAN);
if (CAN->MSR & CAN_MSR_WKUI) {
//Waking from sleep
#ifdef DEBUG
puts("WAKE\n");
#endif
set_can_enable(CAN, 1);
CAN->MSR &= ~(CAN_MSR_WKUI);
CAN->MSR = CAN->MSR;
#ifdef PANDA
power_save_reset_timer();
#endif
} else {
can_err_cnt += 1;
if (can_autobaud_enabled[bus_number] && (CAN->ESR & CAN_ESR_LEC)) {
can_autobaud_speed_increment(can_number);
can_set_speed(can_number);
}
// clear current send
CAN->TSR |= CAN_TSR_ABRQ0;
CAN->MSR &= ~(CAN_MSR_ERRI);
CAN->MSR = CAN->MSR;
}
exit_critical_section(); exit_critical_section();
} }
@ -354,9 +228,6 @@ void can_sce(CAN_TypeDef *CAN) {
void process_can(uint8_t can_number) { void process_can(uint8_t can_number) {
if (can_number == 0xff) return; if (can_number == 0xff) return;
#ifdef PANDA
power_save_reset_timer();
#endif
enter_critical_section(); enter_critical_section();
@ -422,22 +293,9 @@ void process_can(uint8_t can_number) {
// CAN receive handlers // CAN receive handlers
// blink blue when we are receiving CAN messages // blink blue when we are receiving CAN messages
void can_rx(uint8_t can_number) { void can_rx(uint8_t can_number) {
#ifdef PANDA
power_save_reset_timer();
#endif
CAN_TypeDef *CAN = CANIF_FROM_CAN_NUM(can_number); CAN_TypeDef *CAN = CANIF_FROM_CAN_NUM(can_number);
uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number); uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number);
while (CAN->RF0R & CAN_RF0R_FMP0) { while (CAN->RF0R & CAN_RF0R_FMP0) {
if (can_autobaud_enabled[bus_number]) {
can_autobaud_enabled[bus_number] = false;
puts(CAN_NAME_FROM_CANIF(CAN));
#ifdef DEBUG
puts(" auto-baud ");
putui(can_speed[bus_number]);
puts(" cbps\n");
#endif
}
can_rx_cnt += 1; can_rx_cnt += 1;
// can is live // can is live
@ -454,25 +312,19 @@ void can_rx(uint8_t can_number) {
to_push.RDTR = (to_push.RDTR & 0xFFFF000F) | (bus_number << 4); to_push.RDTR = (to_push.RDTR & 0xFFFF000F) | (bus_number << 4);
// forwarding (panda only) // forwarding (panda only)
#ifdef PANDA int bus_fwd_num = can_forwarding[bus_number] != -1 ? can_forwarding[bus_number] : safety_fwd_hook(bus_number, &to_push);
if ((get_lline_status() != 0) || !relay_control) { //Relay engaged or relay isn't controlled, allow fwd if (bus_fwd_num != -1) {
int bus_fwd_num = can_forwarding[bus_number] != -1 ? can_forwarding[bus_number] : safety_fwd_hook(bus_number, &to_push); CAN_FIFOMailBox_TypeDef to_send;
if (bus_fwd_num != -1) { to_send.RIR = to_push.RIR | 1; // TXRQ
CAN_FIFOMailBox_TypeDef to_send; to_send.RDTR = to_push.RDTR;
to_send.RIR = to_push.RIR | 1; // TXRQ to_send.RDLR = to_push.RDLR;
to_send.RDTR = to_push.RDTR; to_send.RDHR = to_push.RDHR;
to_send.RDLR = to_push.RDLR; can_send(&to_send, bus_fwd_num);
to_send.RDHR = to_push.RDHR; }
can_send(&to_send, bus_fwd_num);
}
}
#endif
safety_rx_hook(&to_push); safety_rx_hook(&to_push);
#ifdef PANDA set_led(LED_BLUE, 1);
set_led(LED_BLUE, 1);
#endif
can_push(&can_rx_q, &to_push); can_push(&can_rx_q, &to_push);
// next // next
@ -480,8 +332,6 @@ void can_rx(uint8_t can_number) {
} }
} }
#ifndef CUSTOM_CAN_INTERRUPTS
void CAN1_TX_IRQHandler() { process_can(0); } void CAN1_TX_IRQHandler() { process_can(0); }
void CAN1_RX0_IRQHandler() { can_rx(0); } void CAN1_RX0_IRQHandler() { can_rx(0); }
void CAN1_SCE_IRQHandler() { can_sce(CAN1); } void CAN1_SCE_IRQHandler() { can_sce(CAN1); }
@ -490,25 +340,19 @@ void CAN2_TX_IRQHandler() { process_can(1); }
void CAN2_RX0_IRQHandler() { can_rx(1); } void CAN2_RX0_IRQHandler() { can_rx(1); }
void CAN2_SCE_IRQHandler() { can_sce(CAN2); } void CAN2_SCE_IRQHandler() { can_sce(CAN2); }
#ifdef CAN3
void CAN3_TX_IRQHandler() { process_can(2); } void CAN3_TX_IRQHandler() { process_can(2); }
void CAN3_RX0_IRQHandler() { can_rx(2); } void CAN3_RX0_IRQHandler() { can_rx(2); }
void CAN3_SCE_IRQHandler() { can_sce(CAN3); } void CAN3_SCE_IRQHandler() { can_sce(CAN3); }
#endif
#endif
void can_send(CAN_FIFOMailBox_TypeDef *to_push, uint8_t bus_number) { void can_send(CAN_FIFOMailBox_TypeDef *to_push, uint8_t bus_number) {
if (safety_tx_hook(to_push) && !can_autobaud_enabled[bus_number]) { if (safety_tx_hook(to_push)) {
if (bus_number < BUS_MAX) { if (bus_number < BUS_MAX) {
// add CAN packet to send queue // add CAN packet to send queue
// bus number isn't passed through // bus number isn't passed through
to_push->RDTR &= 0xF; to_push->RDTR &= 0xF;
if (bus_number == 3 && can_num_lookup[3] == 0xFF) { if (bus_number == 3 && can_num_lookup[3] == 0xFF) {
#ifdef PANDA
// TODO: why uint8 bro? only int8? // TODO: why uint8 bro? only int8?
bitbang_gmlan(to_push); bitbang_gmlan(to_push);
#endif
} else { } else {
can_push(can_queues[bus_number], to_push); can_push(can_queues[bus_number], to_push);
process_can(CAN_NUM_FROM_BUS_NUM(bus_number)); process_can(CAN_NUM_FROM_BUS_NUM(bus_number));
@ -520,3 +364,4 @@ void can_send(CAN_FIFOMailBox_TypeDef *to_push, uint8_t bus_number) {
void can_set_forwarding(int from, int to) { void can_set_forwarding(int from, int to) {
can_forwarding[from] = to; can_forwarding[from] = to;
} }

@ -0,0 +1,40 @@
void clock_init() {
// enable external oscillator
RCC->CR |= RCC_CR_HSEON;
while ((RCC->CR & RCC_CR_HSERDY) == 0);
// divide shit
RCC->CFGR = RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE2_DIV2 | RCC_CFGR_PPRE1_DIV4;
// 16mhz crystal
RCC->PLLCFGR = RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 |
RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLN_5 | RCC_PLLCFGR_PLLSRC_HSE;
// start PLL
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;
// switch to PLL
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
// *** running on PLL ***
}
void watchdog_init() {
// setup watchdog
IWDG->KR = 0x5555;
IWDG->PR = 0; // divider /4
// 0 = 0.125 ms, let's have a 50ms watchdog
IWDG->RLR = 400 - 1;
IWDG->KR = 0xCCCC;
}
void watchdog_feed() {
IWDG->KR = 0xAAAA;
}

@ -1,141 +0,0 @@
#ifndef PANDA_DRIVERS_H
#define PANDA_DRIVERS_H
// ********************* LLGPIO *********************
#define MODE_INPUT 0
#define MODE_OUTPUT 1
#define MODE_ALTERNATE 2
#define MODE_ANALOG 3
#define PULL_NONE 0
#define PULL_UP 1
#define PULL_DOWN 2
void set_gpio_mode(GPIO_TypeDef *GPIO, int pin, int mode);
void set_gpio_output(GPIO_TypeDef *GPIO, int pin, int val);
void set_gpio_alternate(GPIO_TypeDef *GPIO, int pin, int mode);
void set_gpio_pullup(GPIO_TypeDef *GPIO, int pin, int mode);
int get_gpio_input(GPIO_TypeDef *GPIO, int pin);
// ********************* USB *********************
// IRQs: OTG_FS
typedef union {
uint16_t w;
struct BW {
uint8_t msb;
uint8_t lsb;
}
bw;
}
uint16_t_uint8_t;
typedef union _USB_Setup {
uint32_t d8[2];
struct _SetupPkt_Struc
{
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t_uint8_t wValue;
uint16_t_uint8_t wIndex;
uint16_t_uint8_t wLength;
} b;
}
USB_Setup_TypeDef;
void usb_init();
int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired);
int usb_cb_ep1_in(uint8_t *usbdata, int len, int hardwired);
void usb_cb_ep2_out(uint8_t *usbdata, int len, int hardwired);
void usb_cb_ep3_out(uint8_t *usbdata, int len, int hardwired);
void usb_cb_enumeration_complete();
// ********************* UART *********************
// IRQs: USART1, USART2, USART3, UART5
#define FIFO_SIZE 0x400
typedef struct uart_ring {
uint16_t w_ptr_tx;
uint16_t r_ptr_tx;
uint8_t elems_tx[FIFO_SIZE];
uint16_t w_ptr_rx;
uint16_t r_ptr_rx;
uint8_t elems_rx[FIFO_SIZE];
USART_TypeDef *uart;
void (*callback)(struct uart_ring*);
} uart_ring;
void uart_init(USART_TypeDef *u, int baud);
int getc(uart_ring *q, char *elem);
int putc(uart_ring *q, char elem);
int puts(const char *a);
void puth(unsigned int i);
void hexdump(const void *a, int l);
// ********************* ADC *********************
void adc_init();
uint32_t adc_get(int channel);
// ********************* DAC *********************
void dac_init();
void dac_set(int channel, uint32_t value);
// ********************* TIMER *********************
void timer_init(TIM_TypeDef *TIM, int psc);
// ********************* SPI *********************
// IRQs: DMA2_Stream2, DMA2_Stream3, EXTI4
void spi_init();
int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out);
// ********************* CAN *********************
// IRQs: CAN1_TX, CAN1_RX0, CAN1_SCE
// CAN2_TX, CAN2_RX0, CAN2_SCE
// CAN3_TX, CAN3_RX0, CAN3_SCE
typedef struct {
uint32_t w_ptr;
uint32_t r_ptr;
uint32_t fifo_size;
CAN_FIFOMailBox_TypeDef *elems;
} can_ring;
#define CAN_BUS_RET_FLAG 0x80
#define CAN_BUS_NUM_MASK 0x7F
#ifdef PANDA
#define BUS_MAX 4
#else
#define BUS_MAX 2
#endif
extern int can_live, pending_can_live;
// must reinit after changing these
extern int can_loopback, can_silent;
extern uint32_t can_speed[];
void can_set_forwarding(int from, int to);
void can_init(uint8_t can_number);
void can_init_all();
void can_send(CAN_FIFOMailBox_TypeDef *to_push, uint8_t bus_number);
int can_pop(can_ring *q, CAN_FIFOMailBox_TypeDef *elem);
#endif

@ -114,8 +114,6 @@ int get_bit_message(char *out, CAN_FIFOMailBox_TypeDef *to_bang) {
return len; return len;
} }
#ifdef PANDA
void setup_timer4() { void setup_timer4() {
// setup // setup
TIM4->PSC = 48-1; // tick on 1 us TIM4->PSC = 48-1; // tick on 1 us
@ -273,4 +271,3 @@ void bitbang_gmlan(CAN_FIFOMailBox_TypeDef *to_bang) {
setup_timer4(); setup_timer4();
} }
#endif

@ -0,0 +1,80 @@
// this is needed for 1 mbps support
#define CAN_QUANTA 8
#define CAN_SEQ1 6 // roundf(quanta * 0.875f) - 1;
#define CAN_SEQ2 1 // roundf(quanta * 0.125f);
#define CAN_PCLK 24000
// 333 = 33.3 kbps
// 5000 = 500 kbps
#define can_speed_to_prescaler(x) (CAN_PCLK / CAN_QUANTA * 10 / (x))
bool llcan_set_speed(CAN_TypeDef *CAN, uint32_t speed, bool loopback, bool silent) {
// initialization mode
CAN->MCR = CAN_MCR_TTCM | CAN_MCR_INRQ;
while((CAN->MSR & CAN_MSR_INAK) != CAN_MSR_INAK);
// set time quanta from defines
CAN->BTR = (CAN_BTR_TS1_0 * (CAN_SEQ1-1)) |
(CAN_BTR_TS2_0 * (CAN_SEQ2-1)) |
(can_speed_to_prescaler(speed) - 1);
// silent loopback mode for debugging
if (loopback) {
CAN->BTR |= CAN_BTR_SILM | CAN_BTR_LBKM;
}
if (silent) {
CAN->BTR |= CAN_BTR_SILM;
}
// reset
CAN->MCR = CAN_MCR_TTCM | CAN_MCR_ABOM;
#define CAN_TIMEOUT 1000000
int tmp = 0;
while((CAN->MSR & CAN_MSR_INAK) == CAN_MSR_INAK && tmp < CAN_TIMEOUT) tmp++;
if (tmp < CAN_TIMEOUT) {
return true;
}
return false;
}
void llcan_init(CAN_TypeDef *CAN) {
// accept all filter
CAN->FMR |= CAN_FMR_FINIT;
// no mask
CAN->sFilterRegister[0].FR1 = 0;
CAN->sFilterRegister[0].FR2 = 0;
CAN->sFilterRegister[14].FR1 = 0;
CAN->sFilterRegister[14].FR2 = 0;
CAN->FA1R |= 1 | (1 << 14);
CAN->FMR &= ~(CAN_FMR_FINIT);
// enable certain CAN interrupts
CAN->IER |= CAN_IER_TMEIE | CAN_IER_FMPIE0 | CAN_IER_WKUIE;
if (CAN == CAN1) {
NVIC_EnableIRQ(CAN1_TX_IRQn);
NVIC_EnableIRQ(CAN1_RX0_IRQn);
NVIC_EnableIRQ(CAN1_SCE_IRQn);
} else if (CAN == CAN2) {
NVIC_EnableIRQ(CAN2_TX_IRQn);
NVIC_EnableIRQ(CAN2_RX0_IRQn);
NVIC_EnableIRQ(CAN2_SCE_IRQn);
#ifdef CAN3
} else if (CAN == CAN3) {
NVIC_EnableIRQ(CAN3_TX_IRQn);
NVIC_EnableIRQ(CAN3_RX0_IRQn);
NVIC_EnableIRQ(CAN3_SCE_IRQn);
#endif
}
}
void llcan_clear_send(CAN_TypeDef *CAN) {
CAN->TSR |= CAN_TSR_ABRQ0;
CAN->MSR &= ~(CAN_MSR_ERRI);
CAN->MSR = CAN->MSR;
}

@ -1,3 +1,12 @@
#define MODE_INPUT 0
#define MODE_OUTPUT 1
#define MODE_ALTERNATE 2
#define MODE_ANALOG 3
#define PULL_NONE 0
#define PULL_UP 1
#define PULL_DOWN 2
void set_gpio_mode(GPIO_TypeDef *GPIO, int pin, int mode) { void set_gpio_mode(GPIO_TypeDef *GPIO, int pin, int mode) {
uint32_t tmp = GPIO->MODER; uint32_t tmp = GPIO->MODER;
tmp &= ~(3 << (pin*2)); tmp &= ~(3 << (pin*2));

@ -1,88 +0,0 @@
#ifdef PANDA
int relay_control = 0; // True if relay is controlled through l-line
/* Conrol a relay connected to l-line pin */
// 160us cycles, 1 high, 25 low
volatile int turn_on_relay = 0;
volatile int on_cycles = 25;
//5s timeout
#define LLINE_TIMEOUT_CYCLES 31250
volatile int timeout_cycles = LLINE_TIMEOUT_CYCLES;
void TIM5_IRQHandler(void) {
if (TIM5->SR & TIM_SR_UIF) {
on_cycles--;
timeout_cycles--;
if (timeout_cycles == 0) {
turn_on_relay = 0;
}
if (on_cycles > 0) {
if (turn_on_relay) {
set_gpio_output(GPIOC, 10, 0);
}
}
else {
set_gpio_output(GPIOC, 10, 1);
on_cycles = 25;
}
}
TIM5->ARR = 160-1;
TIM5->SR = 0;
}
void lline_relay_init (void) {
set_lline_output(0);
relay_control = 1;
set_gpio_output(GPIOC, 10, 1);
// setup
TIM5->PSC = 48-1; // tick on 1 us
TIM5->CR1 = TIM_CR1_CEN; // enable
TIM5->ARR = 50-1; // 50 us
TIM5->DIER = TIM_DIER_UIE; // update interrupt
TIM5->CNT = 0;
NVIC_EnableIRQ(TIM5_IRQn);
#ifdef DEBUG
puts("INIT LLINE\n");
puts(" SR ");
putui(TIM5->SR);
puts(" PSC ");
putui(TIM5->PSC);
puts(" CR1 ");
putui(TIM5->CR1);
puts(" ARR ");
putui(TIM5->ARR);
puts(" DIER ");
putui(TIM5->DIER);
puts(" SR ");
putui(TIM5->SR);
puts(" CNT ");
putui(TIM5->CNT);
puts("\n");
#endif
}
void lline_relay_release (void) {
set_lline_output(0);
relay_control = 0;
puts("RELEASE LLINE\n");
set_gpio_alternate(GPIOC, 10, GPIO_AF7_USART3);
NVIC_DisableIRQ(TIM5_IRQn);
}
void set_lline_output(int to_set) {
timeout_cycles = LLINE_TIMEOUT_CYCLES;
turn_on_relay = to_set;
}
int get_lline_status() {
return turn_on_relay;
}
#endif

@ -1,5 +1,10 @@
// IRQs: DMA2_Stream2, DMA2_Stream3, EXTI4 // IRQs: DMA2_Stream2, DMA2_Stream3, EXTI4
void spi_init();
int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out);
// end API
#define SPI_BUF_SIZE 256 #define SPI_BUF_SIZE 256
uint8_t spi_buf[SPI_BUF_SIZE]; uint8_t spi_buf[SPI_BUF_SIZE];
int spi_buf_count = 0; int spi_buf_count = 0;
@ -23,8 +28,8 @@ void spi_init() {
// setup interrupt on falling edge of SPI enable (on PA4) // setup interrupt on falling edge of SPI enable (on PA4)
SYSCFG->EXTICR[2] = SYSCFG_EXTICR2_EXTI4_PA; SYSCFG->EXTICR[2] = SYSCFG_EXTICR2_EXTI4_PA;
EXTI->IMR = (1 << 4); EXTI->IMR |= (1 << 4);
EXTI->FTSR = (1 << 4); EXTI->FTSR |= (1 << 4);
NVIC_EnableIRQ(EXTI4_IRQn); NVIC_EnableIRQ(EXTI4_IRQn);
} }
@ -108,7 +113,7 @@ void DMA2_Stream3_IRQHandler(void) {
} }
void EXTI4_IRQHandler(void) { void EXTI4_IRQHandler(void) {
volatile int pr = EXTI->PR; volatile int pr = EXTI->PR & (1 << 4);
#ifdef DEBUG_SPI #ifdef DEBUG_SPI
puts("exti4\n"); puts("exti4\n");
#endif #endif

@ -1,5 +1,27 @@
// IRQs: USART1, USART2, USART3, UART5 // IRQs: USART1, USART2, USART3, UART5
#define FIFO_SIZE 0x400
typedef struct uart_ring {
uint16_t w_ptr_tx;
uint16_t r_ptr_tx;
uint8_t elems_tx[FIFO_SIZE];
uint16_t w_ptr_rx;
uint16_t r_ptr_rx;
uint8_t elems_rx[FIFO_SIZE];
USART_TypeDef *uart;
void (*callback)(struct uart_ring*);
} uart_ring;
void uart_init(USART_TypeDef *u, int baud);
int getc(uart_ring *q, char *elem);
int putc(uart_ring *q, char elem);
int puts(const char *a);
void puth(unsigned int i);
void hexdump(const void *a, int l);
// ***************************** serial port queues ***************************** // ***************************** serial port queues *****************************
// esp = USART1 // esp = USART1

@ -1,5 +1,35 @@
// IRQs: OTG_FS // IRQs: OTG_FS
typedef union {
uint16_t w;
struct BW {
uint8_t msb;
uint8_t lsb;
}
bw;
}
uint16_t_uint8_t;
typedef union _USB_Setup {
uint32_t d8[2];
struct _SetupPkt_Struc
{
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t_uint8_t wValue;
uint16_t_uint8_t wIndex;
uint16_t_uint8_t wLength;
} b;
}
USB_Setup_TypeDef;
void usb_init();
int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired);
int usb_cb_ep1_in(uint8_t *usbdata, int len, int hardwired);
void usb_cb_ep2_out(uint8_t *usbdata, int len, int hardwired);
void usb_cb_ep3_out(uint8_t *usbdata, int len, int hardwired);
void usb_cb_enumeration_complete();
// **** supporting defines **** // **** supporting defines ****
typedef struct typedef struct
@ -186,17 +216,10 @@ uint16_t string_manufacturer_desc[] = {
'c', 'o', 'm', 'm', 'a', '.', 'a', 'i' 'c', 'o', 'm', 'm', 'a', '.', 'a', 'i'
}; };
#ifdef PANDA
uint16_t string_product_desc[] = { uint16_t string_product_desc[] = {
STRING_DESCRIPTOR_HEADER(5), STRING_DESCRIPTOR_HEADER(5),
'p', 'a', 'n', 'd', 'a' 'p', 'a', 'n', 'd', 'a'
}; };
#else
uint16_t string_product_desc[] = {
STRING_DESCRIPTOR_HEADER(5),
'N', 'E', 'O', 'v', '1'
};
#endif
// default serial number when we're not a panda // default serial number when we're not a panda
uint16_t string_serial_desc[] = { uint16_t string_serial_desc[] = {
@ -210,7 +233,6 @@ uint16_t string_configuration_desc[] = {
'0', '1' // "01" '0', '1' // "01"
}; };
#ifdef PANDA
// WCID (auto install WinUSB driver) // WCID (auto install WinUSB driver)
// https://github.com/pbatard/libwdi/wiki/WCID-Devices // https://github.com/pbatard/libwdi/wiki/WCID-Devices
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/winusb-installation#automatic-installation-of--winusb-without-an-inf-file // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/winusb-installation#automatic-installation-of--winusb-without-an-inf-file
@ -360,8 +382,6 @@ uint8_t winusb_20_desc[WINUSB_PLATFORM_DESCRIPTOR_LENGTH] = {
'1', 0x00, 'a', 0x00, 'd', 0x00, 'e', 0x00, '9', 0x00, '}', 0x00, 0x00, 0x00 // 78 bytes '1', 0x00, 'a', 0x00, 'd', 0x00, 'e', 0x00, '9', 0x00, '}', 0x00, 0x00, 0x00 // 78 bytes
}; };
#endif
// current packet // current packet
USB_Setup_TypeDef setup; USB_Setup_TypeDef setup;
uint8_t usbdata[0x100]; uint8_t usbdata[0x100];
@ -550,7 +570,7 @@ void usb_setup() {
USB_WritePacket((uint8_t*)string_product_desc, min(sizeof(string_product_desc), setup.b.wLength.w), 0); USB_WritePacket((uint8_t*)string_product_desc, min(sizeof(string_product_desc), setup.b.wLength.w), 0);
break; break;
case STRING_OFFSET_ISERIAL: case STRING_OFFSET_ISERIAL:
#ifdef PANDA #ifdef UID_BASE
resp[0] = 0x02 + 12*4; resp[0] = 0x02 + 12*4;
resp[1] = 0x03; resp[1] = 0x03;
@ -568,14 +588,12 @@ void usb_setup() {
USB_WritePacket((const uint8_t *)string_serial_desc, min(sizeof(string_serial_desc), setup.b.wLength.w), 0); USB_WritePacket((const uint8_t *)string_serial_desc, min(sizeof(string_serial_desc), setup.b.wLength.w), 0);
#endif #endif
break; break;
#ifdef PANDA
case STRING_OFFSET_ICONFIGURATION: case STRING_OFFSET_ICONFIGURATION:
USB_WritePacket((uint8_t*)string_configuration_desc, min(sizeof(string_configuration_desc), setup.b.wLength.w), 0); USB_WritePacket((uint8_t*)string_configuration_desc, min(sizeof(string_configuration_desc), setup.b.wLength.w), 0);
break; break;
case 238: case 238:
USB_WritePacket((uint8_t*)string_238_desc, min(sizeof(string_238_desc), setup.b.wLength.w), 0); USB_WritePacket((uint8_t*)string_238_desc, min(sizeof(string_238_desc), setup.b.wLength.w), 0);
break; break;
#endif
default: default:
// nothing // nothing
USB_WritePacket(0, 0, 0); USB_WritePacket(0, 0, 0);
@ -583,12 +601,10 @@ void usb_setup() {
} }
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break; break;
#ifdef PANDA
case USB_DESC_TYPE_BINARY_OBJECT_STORE: case USB_DESC_TYPE_BINARY_OBJECT_STORE:
USB_WritePacket(binary_object_store_desc, min(sizeof(binary_object_store_desc), setup.b.wLength.w), 0); USB_WritePacket(binary_object_store_desc, min(sizeof(binary_object_store_desc), setup.b.wLength.w), 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break; break;
#endif
default: default:
// nothing here? // nothing here?
USB_WritePacket(0, 0, 0); USB_WritePacket(0, 0, 0);
@ -609,7 +625,6 @@ void usb_setup() {
USB_WritePacket(0, 0, 0); USB_WritePacket(0, 0, 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break; break;
#ifdef PANDA
case WEBUSB_VENDOR_CODE: case WEBUSB_VENDOR_CODE:
switch (setup.b.wIndex.w) { switch (setup.b.wIndex.w) {
case WEBUSB_REQ_GET_URL: case WEBUSB_REQ_GET_URL:
@ -641,7 +656,6 @@ void usb_setup() {
USB_WritePacket_EP0(0, 0); USB_WritePacket_EP0(0, 0);
} }
break; break;
#endif
default: default:
resp_len = usb_cb_control_msg(&setup, resp, 1); resp_len = usb_cb_control_msg(&setup, resp, 1);
USB_WritePacket(resp, min(resp_len, setup.b.wLength.w), 0); USB_WritePacket(resp, min(resp_len, setup.b.wLength.w), 0);

@ -1,3 +1,5 @@
// this is last place with ifdef PANDA
#ifdef STM32F4 #ifdef STM32F4
#include "stm32f4xx_hal_gpio_ex.h" #include "stm32f4xx_hal_gpio_ex.h"
#else #else
@ -61,43 +63,6 @@ void detect() {
// ********************* bringup ********************* // ********************* bringup *********************
void clock_init() {
// enable external oscillator
RCC->CR |= RCC_CR_HSEON;
while ((RCC->CR & RCC_CR_HSERDY) == 0);
// divide shit
RCC->CFGR = RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE2_DIV2 | RCC_CFGR_PPRE1_DIV4;
#ifdef PANDA
RCC->PLLCFGR = RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 |
RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLN_5 | RCC_PLLCFGR_PLLSRC_HSE;
#else
#ifdef PEDAL
// comma pedal has a 16mhz crystal
RCC->PLLCFGR = RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 |
RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLN_5 | RCC_PLLCFGR_PLLSRC_HSE;
#else
// NEO board has a 8mhz crystal
RCC->PLLCFGR = RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 |
RCC_PLLCFGR_PLLN_7 | RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLSRC_HSE;
#endif
#endif
// start PLL
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;
// switch to PLL
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
// *** running on PLL ***
}
void periph_init() { void periph_init() {
// enable GPIOB, UART2, CAN, USB clock // enable GPIOB, UART2, CAN, USB clock
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
@ -117,18 +82,16 @@ void periph_init() {
RCC->APB1ENR |= RCC_APB1ENR_CAN3EN; RCC->APB1ENR |= RCC_APB1ENR_CAN3EN;
#endif #endif
RCC->APB1ENR |= RCC_APB1ENR_DACEN; RCC->APB1ENR |= RCC_APB1ENR_DACEN;
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // main counter
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // slow loop and pedal
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; // gmlan_alt
RCC->APB1ENR |= RCC_APB1ENR_TIM5EN; //RCC->APB1ENR |= RCC_APB1ENR_TIM5EN;
RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; //RCC->APB1ENR |= RCC_APB1ENR_TIM6EN;
RCC->APB2ENR |= RCC_APB2ENR_USART1EN; RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN; RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN;
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; //RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
// needed?
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
} }
@ -197,7 +160,7 @@ void set_can_mode(int can, int use_gmlan) {
set_gpio_alternate(GPIOB, 12, GPIO_AF9_CAN2); set_gpio_alternate(GPIOB, 12, GPIO_AF9_CAN2);
set_gpio_alternate(GPIOB, 13, GPIO_AF9_CAN2); set_gpio_alternate(GPIOB, 13, GPIO_AF9_CAN2);
#ifdef CAN3 #ifdef CAN3
} else if (revision == PANDA_REV_C && can == 2) { } else if (can == 2) {
// A8,A15: disable normal mode // A8,A15: disable normal mode
set_gpio_mode(GPIOA, 8, MODE_INPUT); set_gpio_mode(GPIOA, 8, MODE_INPUT);
set_gpio_mode(GPIOA, 15, MODE_INPUT); set_gpio_mode(GPIOA, 15, MODE_INPUT);
@ -218,11 +181,9 @@ void set_can_mode(int can, int use_gmlan) {
set_gpio_alternate(GPIOB, 6, GPIO_AF9_CAN2); set_gpio_alternate(GPIOB, 6, GPIO_AF9_CAN2);
#ifdef CAN3 #ifdef CAN3
} else if (can == 2) { } else if (can == 2) {
if(revision == PANDA_REV_C){ // B3,B4: disable gmlan mode
// B3,B4: disable gmlan mode set_gpio_mode(GPIOB, 3, MODE_INPUT);
set_gpio_mode(GPIOB, 3, MODE_INPUT); set_gpio_mode(GPIOB, 4, MODE_INPUT);
set_gpio_mode(GPIOB, 4, MODE_INPUT);
}
// A8,A15: normal mode // A8,A15: normal mode
set_gpio_alternate(GPIOA, 8, GPIO_AF11_CAN3); set_gpio_alternate(GPIOA, 8, GPIO_AF11_CAN3);
set_gpio_alternate(GPIOA, 15, GPIO_AF11_CAN3); set_gpio_alternate(GPIOA, 15, GPIO_AF11_CAN3);
@ -377,11 +338,7 @@ void gpio_init() {
#ifdef PANDA #ifdef PANDA
// K-line enable moved from B4->B7 to make room for GMLAN on CAN3 // K-line enable moved from B4->B7 to make room for GMLAN on CAN3
if (revision == PANDA_REV_C) { set_gpio_output(GPIOB, 7, 1); // REV C
set_gpio_output(GPIOB, 7, 1); // REV C
} else {
set_gpio_output(GPIOB, 4, 1); // REV AB
}
// C12,D2: K-Line setup on UART 5 // C12,D2: K-Line setup on UART 5
set_gpio_alternate(GPIOC, 12, GPIO_AF8_UART5); set_gpio_alternate(GPIOC, 12, GPIO_AF8_UART5);
@ -392,16 +349,12 @@ void gpio_init() {
set_gpio_output(GPIOA, 14, 1); set_gpio_output(GPIOA, 14, 1);
// C10,C11: L-Line setup on USART 3 // C10,C11: L-Line setup on USART 3
// LLine now used for relay output set_gpio_alternate(GPIOC, 10, GPIO_AF7_USART3);
set_gpio_output(GPIOC, 10, 1);
//set_gpio_alternate(GPIOC, 10, GPIO_AF7_USART3);
set_gpio_alternate(GPIOC, 11, GPIO_AF7_USART3); set_gpio_alternate(GPIOC, 11, GPIO_AF7_USART3);
set_gpio_pullup(GPIOC, 11, PULL_UP); set_gpio_pullup(GPIOC, 11, PULL_UP);
#endif #endif
if (revision == PANDA_REV_C) { set_usb_power_mode(USB_POWER_CLIENT);
set_usb_power_mode(USB_POWER_CLIENT);
}
} }
// ********************* early bringup ********************* // ********************* early bringup *********************

@ -1,14 +1,15 @@
//#define EON
#include "config.h" #include "config.h"
#include "obj/gitversion.h" #include "obj/gitversion.h"
// ********************* includes ********************* // ********************* includes *********************
#include "libc.h" #include "libc.h"
#include "safety.h"
#include "provision.h" #include "provision.h"
#include "drivers/drivers.h" #include "drivers/llcan.h"
#include "drivers/llgpio.h" #include "drivers/llgpio.h"
#include "gpio.h" #include "gpio.h"
@ -16,25 +17,13 @@
#include "drivers/adc.h" #include "drivers/adc.h"
#include "drivers/usb.h" #include "drivers/usb.h"
#include "drivers/gmlan_alt.h" #include "drivers/gmlan_alt.h"
#include "drivers/can.h"
#include "drivers/spi.h" #include "drivers/spi.h"
#include "drivers/timer.h" #include "drivers/timer.h"
#include "drivers/clock.h"
#include "power_saving.h" #include "power_saving.h"
#include "safety.h"
#include "drivers/can.h"
// ***************************** fan *****************************
void fan_init() {
// timer for fan PWM
TIM3->CCMR2 = TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1;
TIM3->CCER = TIM_CCER_CC3E;
timer_init(TIM3, 10);
}
void fan_set_speed(int fan_speed) {
TIM3->CCR3 = fan_speed;
}
// ********************* serial debugging ********************* // ********************* serial debugging *********************
@ -70,6 +59,41 @@ void debug_ring_callback(uart_ring *ring) {
} }
} }
// ***************************** started logic *****************************
int is_gpio_started() {
// ignition is on PA1
return (GPIOA->IDR & (1 << 1)) == 0;
}
void EXTI1_IRQHandler() {
volatile int pr = EXTI->PR & (1 << 1);
if (pr & (1 << 1)) {
#ifdef DEBUG
puts("got started interrupt\n");
#endif
// jenky debounce
delay(100000);
// set power savings mode here
if (is_gpio_started() == 1) {
power_save_disable();
} else {
power_save_enable();
}
EXTI->PR = (1 << 1);
}
}
void started_interrupt_init() {
SYSCFG->EXTICR[1] = SYSCFG_EXTICR1_EXTI1_PA;
EXTI->IMR |= (1 << 1);
EXTI->RTSR |= (1 << 1);
EXTI->FTSR |= (1 << 1);
NVIC_EnableIRQ(EXTI1_IRQn);
}
// ***************************** USB port ***************************** // ***************************** USB port *****************************
int get_health_pkt(void *dat) { int get_health_pkt(void *dat) {
@ -85,40 +109,25 @@ int get_health_pkt(void *dat) {
//Voltage will be measured in mv. 5000 = 5V //Voltage will be measured in mv. 5000 = 5V
uint32_t voltage = adc_get(ADCCHAN_VOLTAGE); uint32_t voltage = adc_get(ADCCHAN_VOLTAGE);
if (revision == PANDA_REV_AB) {
//REVB has a 100, 27 (27/127) voltage divider
//Here is the calculation for the scale
//ADCV = VIN_S * (27/127) * (4095/3.3)
//RETVAL = ADCV * s = VIN_S*1000
//s = 1000/((4095/3.3)*(27/127)) = 3.79053046
//Avoid needing floating point math
health->voltage = (voltage * 3791) / 1000;
} else {
//REVC has a 10, 1 (1/11) voltage divider
//Here is the calculation for the scale (s)
//ADCV = VIN_S * (1/11) * (4095/3.3)
//RETVAL = ADCV * s = VIN_S*1000
//s = 1000/((4095/3.3)*(1/11)) = 8.8623046875
//Avoid needing floating point math
health->voltage = (voltage * 8862) / 1000;
}
#ifdef PANDA // REVC has a 10, 1 (1/11) voltage divider
// Here is the calculation for the scale (s)
// ADCV = VIN_S * (1/11) * (4095/3.3)
// RETVAL = ADCV * s = VIN_S*1000
// s = 1000/((4095/3.3)*(1/11)) = 8.8623046875
// Avoid needing floating point math
health->voltage = (voltage * 8862) / 1000;
health->current = adc_get(ADCCHAN_CURRENT); health->current = adc_get(ADCCHAN_CURRENT);
int safety_ignition = safety_ignition_hook(); int safety_ignition = safety_ignition_hook();
if (safety_ignition < 0) { if (safety_ignition < 0) {
//Use the GPIO pin to determine ignition //Use the GPIO pin to determine ignition
health->started = (GPIOA->IDR & (1 << 1)) == 0; health->started = is_gpio_started();
} else { } else {
//Current safety hooks want to determine ignition (ex: GM) //Current safety hooks want to determine ignition (ex: GM)
health->started = safety_ignition; health->started = safety_ignition;
} }
#else
health->current = 0;
health->started = (GPIOC->IDR & (1 << 13)) != 0;
#endif
health->controls_allowed = controls_allowed; health->controls_allowed = controls_allowed;
health->gas_interceptor_detected = gas_interceptor_detected; health->gas_interceptor_detected = gas_interceptor_detected;
@ -143,7 +152,6 @@ void usb_cb_ep2_out(uint8_t *usbdata, int len, int hardwired) {
uart_ring *ur = get_ring_by_number(usbdata[0]); uart_ring *ur = get_ring_by_number(usbdata[0]);
if (!ur) return; if (!ur) return;
if ((usbdata[0] < 2) || safety_tx_lin_hook(usbdata[0]-2, usbdata+1, len-1)) { if ((usbdata[0] < 2) || safety_tx_lin_hook(usbdata[0]-2, usbdata+1, len-1)) {
if (ur == &esp_ring) power_save_reset_timer();
for (int i = 1; i < len; i++) while (!putc(ur, usbdata[i])); for (int i = 1; i < len; i++) while (!putc(ur, usbdata[i]));
} }
} }
@ -163,14 +171,6 @@ void usb_cb_ep3_out(uint8_t *usbdata, int len, int hardwired) {
uint8_t bus_number = (to_push.RDTR >> 4) & CAN_BUS_NUM_MASK; uint8_t bus_number = (to_push.RDTR >> 4) & CAN_BUS_NUM_MASK;
can_send(&to_push, bus_number); can_send(&to_push, bus_number);
#ifdef PANDA
// Enable relay on can message if allowed.
// Temporary until OP has support for relay
if (safety_relay_hook()) {
set_lline_output(1);
}
#endif
} }
} }
@ -201,16 +201,14 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) {
break; break;
// **** 0xd0: fetch serial number // **** 0xd0: fetch serial number
case 0xd0: case 0xd0:
#ifdef PANDA // addresses are OTP
// addresses are OTP if (setup->b.wValue.w == 1) {
if (setup->b.wValue.w == 1) { memcpy(resp, (void *)0x1fff79c0, 0x10);
memcpy(resp, (void *)0x1fff79c0, 0x10); resp_len = 0x10;
resp_len = 0x10; } else {
} else { get_provision_chunk(resp);
get_provision_chunk(resp); resp_len = PROVISION_CHUNK_LEN;
resp_len = PROVISION_CHUNK_LEN; }
}
#endif
break; break;
// **** 0xd1: enter bootloader mode // **** 0xd1: enter bootloader mode
case 0xd1: case 0xd1:
@ -235,10 +233,6 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) {
case 0xd2: case 0xd2:
resp_len = get_health_pkt(resp); resp_len = get_health_pkt(resp);
break; break;
// **** 0xd3: set fan speed
case 0xd3:
fan_set_speed(setup->b.wValue.w);
break;
// **** 0xd6: get version // **** 0xd6: get version
case 0xd6: case 0xd6:
COMPILE_TIME_ASSERT(sizeof(gitversion) <= MAX_RESP_LEN) COMPILE_TIME_ASSERT(sizeof(gitversion) <= MAX_RESP_LEN)
@ -273,44 +267,43 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) {
break; break;
// **** 0xdb: set GMLAN multiplexing mode // **** 0xdb: set GMLAN multiplexing mode
case 0xdb: case 0xdb:
#ifdef PANDA if (setup->b.wValue.w == 1) {
if (setup->b.wValue.w == 1) { // GMLAN ON
// GMLAN ON if (setup->b.wIndex.w == 1) {
if (setup->b.wIndex.w == 1) { can_set_gmlan(1);
can_set_gmlan(1); } else if (setup->b.wIndex.w == 2) {
} else if (setup->b.wIndex.w == 2) { can_set_gmlan(2);
// might be ignored on rev b panda
can_set_gmlan(2);
}
} else {
can_set_gmlan(-1);
} }
#endif } else {
can_set_gmlan(-1);
}
break; break;
// **** 0xdc: set safety mode // **** 0xdc: set safety mode
case 0xdc: case 0xdc:
// this is the only way to leave silent mode // this is the only way to leave silent mode
// and it's blocked over WiFi // and it's blocked over WiFi
// Allow ELM security mode to be set over wifi. // Allow ELM security mode to be set over wifi.
if (hardwired || setup->b.wValue.w == SAFETY_NOOUTPUT || setup->b.wValue.w == SAFETY_ELM327) { if (hardwired || (setup->b.wValue.w == SAFETY_NOOUTPUT) || (setup->b.wValue.w == SAFETY_ELM327)) {
safety_set_mode(setup->b.wValue.w, (int16_t)setup->b.wIndex.w); safety_set_mode(setup->b.wValue.w, (int16_t)setup->b.wIndex.w);
switch (setup->b.wValue.w) { if (safety_ignition_hook() != -1) {
case SAFETY_NOOUTPUT: // if the ignition hook depends on something other than the started GPIO
can_silent = ALL_CAN_SILENT; // we have to disable power savings (fix for GM and Tesla)
break; power_save_disable();
case SAFETY_ELM327:
can_silent = ALL_CAN_BUT_MAIN_SILENT;
can_autobaud_enabled[0] = false;
break;
default:
can_silent = ALL_CAN_LIVE;
can_autobaud_enabled[0] = false;
can_autobaud_enabled[1] = false;
#ifdef PANDA
can_autobaud_enabled[2] = false;
#endif
break;
} }
#ifndef EON
// always LIVE on EON
switch (setup->b.wValue.w) {
case SAFETY_NOOUTPUT:
can_silent = ALL_CAN_SILENT;
break;
case SAFETY_ELM327:
can_silent = ALL_CAN_BUT_MAIN_SILENT;
break;
default:
can_silent = ALL_CAN_LIVE;
break;
}
#endif
can_init_all(); can_init_all();
} }
break; break;
@ -318,21 +311,26 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) {
case 0xdd: case 0xdd:
// wValue = Can Bus Num to forward from // wValue = Can Bus Num to forward from
// wIndex = Can Bus Num to forward to // wIndex = Can Bus Num to forward to
if (setup->b.wValue.w < BUS_MAX && setup->b.wIndex.w < BUS_MAX && if ((setup->b.wValue.w < BUS_MAX) && (setup->b.wIndex.w < BUS_MAX) &&
setup->b.wValue.w != setup->b.wIndex.w) { // set forwarding (setup->b.wValue.w != setup->b.wIndex.w)) { // set forwarding
can_set_forwarding(setup->b.wValue.w, setup->b.wIndex.w & CAN_BUS_NUM_MASK); can_set_forwarding(setup->b.wValue.w, setup->b.wIndex.w & CAN_BUS_NUM_MASK);
} else if(setup->b.wValue.w < BUS_MAX && setup->b.wIndex.w == 0xFF){ //Clear Forwarding } else if((setup->b.wValue.w < BUS_MAX) && (setup->b.wIndex.w == 0xFF)){ //Clear Forwarding
can_set_forwarding(setup->b.wValue.w, -1); can_set_forwarding(setup->b.wValue.w, -1);
} }
break; break;
// **** 0xde: set can bitrate // **** 0xde: set can bitrate
case 0xde: case 0xde:
if (setup->b.wValue.w < BUS_MAX) { if (setup->b.wValue.w < BUS_MAX) {
can_autobaud_enabled[setup->b.wValue.w] = false;
can_speed[setup->b.wValue.w] = setup->b.wIndex.w; can_speed[setup->b.wValue.w] = setup->b.wIndex.w;
can_init(CAN_NUM_FROM_BUS_NUM(setup->b.wValue.w)); can_init(CAN_NUM_FROM_BUS_NUM(setup->b.wValue.w));
} }
break; break;
// **** 0xdf: set long controls allowed
case 0xdf:
if (hardwired) {
long_controls_allowed = setup->b.wValue.w & 1;
}
break;
// **** 0xe0: uart read // **** 0xe0: uart read
case 0xe0: case 0xe0:
ur = get_ring_by_number(setup->b.wValue.w); ur = get_ring_by_number(setup->b.wValue.w);
@ -386,17 +384,15 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) {
break; break;
// **** 0xe6: set USB power // **** 0xe6: set USB power
case 0xe6: case 0xe6:
if (revision == PANDA_REV_C) { if (setup->b.wValue.w == 1) {
if (setup->b.wValue.w == 1) { puts("user setting CDP mode\n");
puts("user setting CDP mode\n"); set_usb_power_mode(USB_POWER_CDP);
set_usb_power_mode(USB_POWER_CDP); } else if (setup->b.wValue.w == 2) {
} else if (setup->b.wValue.w == 2) { puts("user setting DCP mode\n");
puts("user setting DCP mode\n"); set_usb_power_mode(USB_POWER_DCP);
set_usb_power_mode(USB_POWER_DCP); } else {
} else { puts("user setting CLIENT mode\n");
puts("user setting CLIENT mode\n"); set_usb_power_mode(USB_POWER_CLIENT);
set_usb_power_mode(USB_POWER_CLIENT);
}
} }
break; break;
// **** 0xf0: do k-line wValue pulse on uart2 for Acura // **** 0xf0: do k-line wValue pulse on uart2 for Acura
@ -452,16 +448,6 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) {
} }
break; break;
} }
// **** 0xf3: set l-line relay
case 0xf3:
{
#ifdef PANDA
if (safety_relay_hook()) {
set_lline_output(setup->b.wValue.w == 1);
}
#endif
break;
}
default: default:
puts("NO HANDLER "); puts("NO HANDLER ");
puth(setup->b.bRequest); puth(setup->b.bRequest);
@ -471,7 +457,6 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) {
return resp_len; return resp_len;
} }
#ifdef PANDA
int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) { int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) {
// data[0] = endpoint // data[0] = endpoint
// data[2] = length // data[2] = length
@ -499,12 +484,6 @@ int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) {
return resp_len; return resp_len;
} }
#else
int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) { return 0; };
#endif
// ***************************** main code ***************************** // ***************************** main code *****************************
@ -514,7 +493,99 @@ void __initialize_hardware_early() {
void __attribute__ ((noinline)) enable_fpu() { void __attribute__ ((noinline)) enable_fpu() {
// enable the FPU // enable the FPU
SCB->CPACR |= ((3UL << 10*2) | (3UL << 11*2)); SCB->CPACR |= ((3UL << (10 * 2)) | (3UL << (11 * 2)));
}
uint64_t tcnt = 0;
uint64_t marker = 0;
// called once per second
void TIM3_IRQHandler() {
#define CURRENT_THRESHOLD 0xF00
#define CLICKS 5 // 5 seconds to switch modes
if (TIM3->SR != 0) {
can_live = pending_can_live;
//puth(usart1_dma); puts(" "); puth(DMA2_Stream5->M0AR); puts(" "); puth(DMA2_Stream5->NDTR); puts("\n");
uint32_t current = adc_get(ADCCHAN_CURRENT);
switch (usb_power_mode) {
case USB_POWER_CLIENT:
if ((tcnt-marker) >= CLICKS) {
if (!is_enumerated) {
puts("USBP: didn't enumerate, switching to CDP mode\n");
// switch to CDP
set_usb_power_mode(USB_POWER_CDP);
marker = tcnt;
}
}
// keep resetting the timer if it's enumerated
if (is_enumerated) {
marker = tcnt;
}
break;
case USB_POWER_CDP:
// On the EON, if we get into CDP mode we stay here. No need to go to DCP.
#ifndef EON
// been CLICKS clicks since we switched to CDP
if ((tcnt-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");
set_usb_power_mode(USB_POWER_DCP);
marker = tcnt;
}
}
// keep resetting the timer if there's no current draw in CDP
if (current >= CURRENT_THRESHOLD) {
marker = tcnt;
}
#endif
break;
case USB_POWER_DCP:
// been at least CLICKS clicks since we switched to DCP
if ((tcnt-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");
set_usb_power_mode(USB_POWER_CDP);
marker = tcnt;
}
}
// keep resetting the timer if there's current draw in DCP
if (current < CURRENT_THRESHOLD) {
marker = tcnt;
}
break;
}
// ~0x9a = 500 ma
/*puth(current);
puts("\n");*/
// reset this every 16th pass
if ((tcnt&0xF) == 0) pending_can_live = 0;
#ifdef DEBUG
puts("** blink ");
puth(can_rx_q.r_ptr); puts(" "); puth(can_rx_q.w_ptr); puts(" ");
puth(can_tx1_q.r_ptr); puts(" "); puth(can_tx1_q.w_ptr); puts(" ");
puth(can_tx2_q.r_ptr); puts(" "); puth(can_tx2_q.w_ptr); puts("\n");
#endif
// set green LED to be controls allowed
set_led(LED_GREEN, controls_allowed);
// turn off the blue LED, turned on by CAN
// unless we are in power saving mode
set_led(LED_BLUE, (tcnt&1) && power_save_status == POWER_SAVE_STATUS_ENABLED);
// on to the next one
tcnt += 1;
}
TIM3->SR = 0;
} }
int main() { int main() {
@ -531,21 +602,19 @@ int main() {
// detect the revision and init the GPIOs // detect the revision and init the GPIOs
puts("config:\n"); puts("config:\n");
#ifdef PANDA puts((revision == PANDA_REV_C) ? " panda rev c\n" : " panda rev a or b\n");
puts(revision == PANDA_REV_C ? " panda rev c\n" : " panda rev a or b\n");
#else
puts(" legacy\n");
#endif
puts(has_external_debug_serial ? " real serial\n" : " USB serial\n"); puts(has_external_debug_serial ? " real serial\n" : " USB serial\n");
puts(is_giant_panda ? " GIANTpanda detected\n" : " not GIANTpanda\n"); puts(is_giant_panda ? " GIANTpanda detected\n" : " not GIANTpanda\n");
puts(is_grey_panda ? " gray panda detected!\n" : " white panda\n"); puts(is_grey_panda ? " gray panda detected!\n" : " white panda\n");
puts(is_entering_bootmode ? " ESP wants bootmode\n" : " no bootmode\n"); puts(is_entering_bootmode ? " ESP wants bootmode\n" : " no bootmode\n");
// non rev c panda are no longer supported
while (revision != PANDA_REV_C);
gpio_init(); gpio_init();
#ifdef PANDA
// panda has an FPU, let's use it! // panda has an FPU, let's use it!
enable_fpu(); enable_fpu();
#endif
// enable main uart if it's connected // enable main uart if it's connected
if (has_external_debug_serial) { if (has_external_debug_serial) {
@ -554,22 +623,18 @@ int main() {
uart_init(USART2, 115200); uart_init(USART2, 115200);
} }
#ifdef PANDA
if (is_grey_panda) { if (is_grey_panda) {
uart_init(USART1, 9600); uart_init(USART1, 9600);
} else { } else {
// enable ESP uart // enable ESP uart
uart_init(USART1, 115200); uart_init(USART1, 115200);
#ifdef EON
set_esp_mode(ESP_DISABLED);
#endif
} }
// enable LIN // enable LIN
uart_init(UART5, 10400); uart_init(UART5, 10400);
UART5->CR2 |= USART_CR2_LINEN; UART5->CR2 |= USART_CR2_LINEN;
uart_init(USART3, 10400); uart_init(USART3, 10400);
USART3->CR2 |= USART_CR2_LINEN; USART3->CR2 |= USART_CR2_LINEN;
#endif
// init microsecond system timer // init microsecond system timer
// increments 1000000 times per second // increments 1000000 times per second
@ -585,136 +650,65 @@ int main() {
// default to silent mode to prevent issues with Ford // default to silent mode to prevent issues with Ford
// hardcode a specific safety mode if you want to force the panda to be in a specific mode // hardcode a specific safety mode if you want to force the panda to be in a specific mode
safety_set_mode(SAFETY_NOOUTPUT, 0); safety_set_mode(SAFETY_NOOUTPUT, 0);
#ifdef EON
// if we're on an EON, it's fine for CAN to be live for fingerprinting
can_silent = ALL_CAN_LIVE;
#else
can_silent = ALL_CAN_SILENT; can_silent = ALL_CAN_SILENT;
#endif
can_init_all(); can_init_all();
adc_init(); adc_init();
#ifdef PANDA
spi_init(); spi_init();
#ifdef EON
// have to save power
if (!is_grey_panda) {
set_esp_mode(ESP_DISABLED);
}
// only enter power save after the first cycle
/*if (is_gpio_started() == 0) {
power_save_enable();
}*/
// interrupt on started line
started_interrupt_init();
#endif #endif
// 48mhz / 65536 ~= 732 / 732 = 1
timer_init(TIM3, 732);
NVIC_EnableIRQ(TIM3_IRQn);
#ifdef DEBUG #ifdef DEBUG
puts("DEBUG ENABLED\n"); puts("DEBUG ENABLED\n");
#endif #endif
// set PWM
fan_init();
fan_set_speed(0);
puts("**** INTERRUPTS ON ****\n"); puts("**** INTERRUPTS ON ****\n");
__enable_irq(); __enable_irq();
power_save_init();
// if the error interrupt is enabled to quickly when the CAN bus is active
// something bad happens and you can't connect to the device over USB
delay(10000000);
CAN1->IER |= CAN_IER_ERRIE | CAN_IER_LECIE;
// LED should keep on blinking all the time // LED should keep on blinking all the time
uint64_t cnt = 0; uint64_t cnt = 0;
#ifdef PANDA
uint64_t marker = 0;
#define CURRENT_THRESHOLD 0xF00
#define CLICKS 8
#endif
for (cnt=0;;cnt++) { for (cnt=0;;cnt++) {
can_live = pending_can_live; if (power_save_status == POWER_SAVE_STATUS_DISABLED) {
int div_mode = ((usb_power_mode == USB_POWER_DCP) ? 4 : 1);
//puth(usart1_dma); puts(" "); puth(DMA2_Stream5->M0AR); puts(" "); puth(DMA2_Stream5->NDTR); puts("\n");
// useful for debugging, fade breaks = panda is overloaded
#ifdef PANDA for (int div_mode_loop = 0; div_mode_loop < div_mode; div_mode_loop++) {
uint32_t current = adc_get(ADCCHAN_CURRENT); for (int fade = 0; fade < 1024; fade += 8) {
for (int i = 0; i < (128/div_mode); i++) {
switch (usb_power_mode) { set_led(LED_RED, 1);
case USB_POWER_CLIENT: if (fade < 512) { delay(fade); } else { delay(1024-fade); }
if ((cnt-marker) >= CLICKS) { set_led(LED_RED, 0);
if (!is_enumerated) { if (fade < 512) { delay(512-fade); } else { delay(fade-512); }
puts("USBP: didn't enumerate, switching to CDP mode\n");
// switch to CDP
set_usb_power_mode(USB_POWER_CDP);
marker = cnt;
}
}
// keep resetting the timer if it's enumerated
if (is_enumerated) {
marker = cnt;
}
break;
case USB_POWER_CDP:
#ifndef EON
// been CLICKS clicks since we switched to CDP
if ((cnt-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");
set_usb_power_mode(USB_POWER_DCP);
marker = cnt;
}
}
// keep resetting the timer if there's no current draw in CDP
if (current >= CURRENT_THRESHOLD) {
marker = cnt;
}
#endif
break;
case USB_POWER_DCP:
// been at least CLICKS clicks since we switched to DCP
if ((cnt-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");
set_usb_power_mode(USB_POWER_CDP);
marker = cnt;
}
}
// keep resetting the timer if there's current draw in DCP
if (current < CURRENT_THRESHOLD) {
marker = cnt;
} }
break;
}
// ~0x9a = 500 ma
/*puth(current);
puts("\n");*/
#endif
// reset this every 16th pass
if ((cnt&0xF) == 0) pending_can_live = 0;
#ifdef DEBUG
puts("** blink ");
puth(can_rx_q.r_ptr); puts(" "); puth(can_rx_q.w_ptr); puts(" ");
puth(can_tx1_q.r_ptr); puts(" "); puth(can_tx1_q.w_ptr); puts(" ");
puth(can_tx2_q.r_ptr); puts(" "); puth(can_tx2_q.w_ptr); puts("\n");
#endif
// set green LED to be controls allowed
set_led(LED_GREEN, controls_allowed);
// blink the red LED
int div_mode = ((usb_power_mode == USB_POWER_DCP) ? 4 : 1);
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++) {
set_led(LED_RED, 0);
if (fade < 512) { delay(512-fade); } else { delay(fade-512); }
set_led(LED_RED, 1);
if (fade < 512) { delay(fade); } else { delay(1024-fade); }
} }
} }
} else {
__WFI();
} }
// turn off the blue LED, turned on by CAN
#ifdef PANDA
set_led(LED_BLUE, 0);
#endif
} }
return 0; return 0;
} }

@ -1,29 +1,26 @@
//#define DEBUG
//#define CAN_LOOPBACK_MODE
//#define USE_INTERNAL_OSC
#include "../config.h" #include "../config.h"
#include "drivers/drivers.h" #include "drivers/llcan.h"
#include "drivers/llgpio.h" #include "drivers/llgpio.h"
#include "gpio.h" #include "drivers/clock.h"
#define CUSTOM_CAN_INTERRUPTS
#include "libc.h"
#include "safety.h"
#include "drivers/adc.h" #include "drivers/adc.h"
#include "drivers/uart.h"
#include "drivers/dac.h" #include "drivers/dac.h"
#include "drivers/can.h"
#include "drivers/timer.h" #include "drivers/timer.h"
#include "gpio.h"
#include "libc.h"
#define CAN CAN1 #define CAN CAN1
//#define PEDAL_USB //#define PEDAL_USB
#ifdef PEDAL_USB #ifdef PEDAL_USB
#include "drivers/uart.h"
#include "drivers/usb.h" #include "drivers/usb.h"
#else
// no serial either
int puts(const char *a) { return 0; }
void puth(unsigned int i) {}
#endif #endif
#define ENTER_BOOTLOADER_MAGIC 0xdeadbeef #define ENTER_BOOTLOADER_MAGIC 0xdeadbeef
@ -35,6 +32,8 @@ void __initialize_hardware_early() {
// ********************* serial debugging ********************* // ********************* serial debugging *********************
#ifdef PEDAL_USB
void debug_ring_callback(uart_ring *ring) { void debug_ring_callback(uart_ring *ring) {
char rcv; char rcv;
while (getc(ring, &rcv)) { while (getc(ring, &rcv)) {
@ -42,8 +41,6 @@ void debug_ring_callback(uart_ring *ring) {
} }
} }
#ifdef PEDAL_USB
int usb_cb_ep1_in(uint8_t *usbdata, int len, int hardwired) { return 0; } int usb_cb_ep1_in(uint8_t *usbdata, int len, int hardwired) { return 0; }
void usb_cb_ep2_out(uint8_t *usbdata, int len, int hardwired) {} void usb_cb_ep2_out(uint8_t *usbdata, int len, int hardwired) {}
void usb_cb_ep3_out(uint8_t *usbdata, int len, int hardwired) {} void usb_cb_ep3_out(uint8_t *usbdata, int len, int hardwired) {}
@ -185,7 +182,7 @@ void CAN1_RX0_IRQHandler() {
void CAN1_SCE_IRQHandler() { void CAN1_SCE_IRQHandler() {
state = FAULT_SCE; state = FAULT_SCE;
can_sce(CAN); llcan_clear_send(CAN);
} }
int pdl0 = 0, pdl1 = 0; int pdl0 = 0, pdl1 = 0;
@ -256,8 +253,7 @@ void pedal() {
dac_set(1, pdl1); dac_set(1, pdl1);
} }
// feed the watchdog watchdog_feed();
IWDG->KR = 0xAAAA;
} }
int main() { int main() {
@ -278,24 +274,18 @@ int main() {
adc_init(); adc_init();
// init can // init can
can_silent = ALL_CAN_LIVE; llcan_set_speed(CAN1, 5000, false, false);
can_init(0); llcan_init(CAN1);
// 48mhz / 65536 ~= 732 // 48mhz / 65536 ~= 732
timer_init(TIM3, 15); timer_init(TIM3, 15);
NVIC_EnableIRQ(TIM3_IRQn); NVIC_EnableIRQ(TIM3_IRQn);
// setup watchdog watchdog_init();
IWDG->KR = 0x5555;
IWDG->PR = 0; // divider /4
// 0 = 0.125 ms, let's have a 50ms watchdog
IWDG->RLR = 400 - 1;
IWDG->KR = 0xCCCC;
puts("**** INTERRUPTS ON ****\n"); puts("**** INTERRUPTS ON ****\n");
__enable_irq(); __enable_irq();
// main pedal loop // main pedal loop
while (1) { while (1) {
pedal(); pedal();

@ -1,157 +1,57 @@
#define POWER_SAVE_STATUS_DISABLED 0 #define POWER_SAVE_STATUS_DISABLED 0
//Moving to enabled, but can wakeup not yet enabled #define POWER_SAVE_STATUS_ENABLED 1
#define POWER_SAVE_STATUS_SWITCHING 1
#define POWER_SAVE_STATUS_ENABLED 2
volatile int power_save_status = POWER_SAVE_STATUS_DISABLED; int power_save_status = POWER_SAVE_STATUS_DISABLED;
void power_save_enable(void) { void power_save_enable(void) {
power_save_status = POWER_SAVE_STATUS_SWITCHING; if (power_save_status == POWER_SAVE_STATUS_ENABLED) return;
puts("Saving power\n"); puts("enable power savings\n");
//Turn off can transciever
// turn off can
set_can_enable(CAN1, 0); set_can_enable(CAN1, 0);
set_can_enable(CAN2, 0); set_can_enable(CAN2, 0);
#ifdef PANDA
set_can_enable(CAN3, 0); set_can_enable(CAN3, 0);
#endif
//Turn off GMLAN // turn off GMLAN
set_gpio_output(GPIOB, 14, 0); set_gpio_output(GPIOB, 14, 0);
set_gpio_output(GPIOB, 15, 0); set_gpio_output(GPIOB, 15, 0);
#ifdef PANDA // turn off LIN
//Turn off LIN K set_gpio_output(GPIOB, 7, 0);
if (revision == PANDA_REV_C) {
set_gpio_output(GPIOB, 7, 0); // REV C
} else {
set_gpio_output(GPIOB, 4, 0); // REV AB
}
// LIN L
set_gpio_output(GPIOA, 14, 0); set_gpio_output(GPIOA, 14, 0);
#endif
if (is_grey_panda) { if (is_grey_panda) {
char* UBLOX_SLEEP_MSG = "\xb5\x62\x06\x04\x04\x00\x01\x00\x08\x00\x17\x78"; char UBLOX_SLEEP_MSG[] = "\xb5\x62\x06\x04\x04\x00\x01\x00\x08\x00\x17\x78";
int len = 12;
uart_ring *ur = get_ring_by_number(1); uart_ring *ur = get_ring_by_number(1);
for (int i = 0; i < len; i++) while (!putc(ur, UBLOX_SLEEP_MSG[i])); for (int i = 0; i < sizeof(UBLOX_SLEEP_MSG)-1; i++) while (!putc(ur, UBLOX_SLEEP_MSG[i]));
} }
//Setup timer for can enable
TIM6->PSC = 48-1; // tick on 1 us
TIM6->ARR = 12; // 12us
// Enable, One-Pulse Mode, Only overflow interrupt
TIM6->CR1 = TIM_CR1_CEN | TIM_CR1_OPM | TIM_CR1_URS;
TIM6->EGR = TIM_EGR_UG;
TIM6->CR1 |= TIM_CR1_CEN;
}
void power_save_enable_can_wake(void) {
// CAN Automatic Wake must be done a little while after the sleep
// On some cars turning off the can transciver can trigger the wakeup
power_save_status = POWER_SAVE_STATUS_ENABLED; power_save_status = POWER_SAVE_STATUS_ENABLED;
puts("Turning can off\n");
CAN1->MCR |= CAN_MCR_SLEEP;
CAN1->MCR |= CAN_MCR_AWUM;
CAN2->MCR |= CAN_MCR_SLEEP;
CAN2->MCR |= CAN_MCR_AWUM;
#ifdef PANDA
CAN3->MCR |= CAN_MCR_SLEEP;
CAN3->MCR |= CAN_MCR_AWUM;
#endif
//set timer back
TIM6->PSC = 48000-1; // tick on 1 ms
TIM6->ARR = 10000; // 10s
// Enable, One-Pulse Mode, Only overflow interrupt
TIM6->CR1 = TIM_CR1_OPM | TIM_CR1_URS;
TIM6->EGR = TIM_EGR_UG;
} }
void power_save_disable(void) { void power_save_disable(void) {
power_save_status = POWER_SAVE_STATUS_DISABLED; if (power_save_status == POWER_SAVE_STATUS_DISABLED) return;
puts("not Saving power\n"); puts("disable power savings\n");
TIM6->CR1 |= TIM_CR1_CEN; //Restart timer
TIM6->CNT = 0;
//Turn on can // turn on can
set_can_enable(CAN1, 1); set_can_enable(CAN1, 1);
set_can_enable(CAN2, 1); set_can_enable(CAN2, 1);
#ifdef PANDA
set_can_enable(CAN3, 1); set_can_enable(CAN3, 1);
#endif
//Turn on GMLAN // turn on GMLAN
set_gpio_output(GPIOB, 14, 1); set_gpio_output(GPIOB, 14, 1);
set_gpio_output(GPIOB, 15, 1); set_gpio_output(GPIOB, 15, 1);
#ifdef PANDA // turn on LIN
//Turn on LIN K set_gpio_output(GPIOB, 7, 1);
if (revision == PANDA_REV_C) {
set_gpio_output(GPIOB, 7, 1); // REV C
} else {
set_gpio_output(GPIOB, 4, 1); // REV AB
}
// LIN L
set_gpio_output(GPIOA, 14, 1); set_gpio_output(GPIOA, 14, 1);
#endif
if (is_grey_panda) { if (is_grey_panda) {
char* UBLOX_WAKE_MSG = "\xb5\x62\x06\x04\x04\x00\x01\x00\x09\x00\x18\x7a"; char UBLOX_WAKE_MSG[] = "\xb5\x62\x06\x04\x04\x00\x01\x00\x09\x00\x18\x7a";
int len = 12;
uart_ring *ur = get_ring_by_number(1); uart_ring *ur = get_ring_by_number(1);
for (int i = 0; i < len; i++) while (!putc(ur, UBLOX_WAKE_MSG[i])); for (int i = 0; i < sizeof(UBLOX_WAKE_MSG)-1; i++) while (!putc(ur, UBLOX_WAKE_MSG[i]));
}
//set timer back
TIM6->PSC = 48000-1; // tick on 1 ms
TIM6->ARR = 10000; // 10s
// Enable, One-Pulse Mode, Only overflow interrupt
TIM6->CR1 = TIM_CR1_CEN | TIM_CR1_OPM | TIM_CR1_URS;
TIM6->EGR = TIM_EGR_UG;
TIM6->CR1 |= TIM_CR1_CEN;
}
// Reset timer when activity
void power_save_reset_timer() {
TIM6->CNT = 0;
if (power_save_status != POWER_SAVE_STATUS_DISABLED){
power_save_disable();
} }
}
void power_save_init(void) { power_save_status = POWER_SAVE_STATUS_DISABLED;
puts("Saving power init\n");
TIM6->PSC = 48000-1; // tick on 1 ms
TIM6->ARR = 10000; // 10s
// Enable, One-Pulse Mode, Only overflow interrupt
TIM6->CR1 = TIM_CR1_CEN | TIM_CR1_OPM | TIM_CR1_URS;
TIM6->EGR = TIM_EGR_UG;
NVIC_EnableIRQ(TIM6_DAC_IRQn);
puts("Saving power init done\n");
TIM6->DIER = TIM_DIER_UIE;
TIM6->CR1 |= TIM_CR1_CEN;
} }
void TIM6_DAC_IRQHandler(void) {
//Timeout switch to power saving mode.
if (TIM6->SR & TIM_SR_UIF) {
TIM6->SR = 0;
#ifdef EON
if (power_save_status == POWER_SAVE_STATUS_DISABLED) {
power_save_enable();
} else if (power_save_status == POWER_SAVE_STATUS_SWITCHING) {
power_save_enable_can_wake();
}
#endif
} else {
TIM6->CR1 |= TIM_CR1_CEN;
}
}

@ -5,13 +5,11 @@ struct sample_t {
int max; int max;
} sample_t_default = {{0}, 0, 0}; } sample_t_default = {{0}, 0, 0};
// no float support in STM32F2 micros (cortex-m3) // safety code requires floats
#ifdef PANDA
struct lookup_t { struct lookup_t {
float x[3]; float x[3];
float y[3]; float y[3];
}; };
#endif
void safety_rx_hook(CAN_FIFOMailBox_TypeDef *to_push); void safety_rx_hook(CAN_FIFOMailBox_TypeDef *to_push);
int safety_tx_hook(CAN_FIFOMailBox_TypeDef *to_send); int safety_tx_hook(CAN_FIFOMailBox_TypeDef *to_send);
@ -27,21 +25,14 @@ int driver_limit_check(int val, int val_last, struct sample_t *val_driver,
const int MAX, const int MAX_RATE_UP, const int MAX_RATE_DOWN, const int MAX, const int MAX_RATE_UP, const int MAX_RATE_DOWN,
const int MAX_ALLOWANCE, const int DRIVER_FACTOR); const int MAX_ALLOWANCE, const int DRIVER_FACTOR);
int rt_rate_limit_check(int val, int val_last, const int MAX_RT_DELTA); int rt_rate_limit_check(int val, int val_last, const int MAX_RT_DELTA);
#ifdef PANDA
float interpolate(struct lookup_t xy, float x); float interpolate(struct lookup_t xy, float x);
void lline_relay_init (void);
void lline_relay_release (void);
void set_lline_output(int to_set);
#endif
typedef void (*safety_hook_init)(int16_t param); typedef void (*safety_hook_init)(int16_t param);
typedef void (*rx_hook)(CAN_FIFOMailBox_TypeDef *to_push); typedef void (*rx_hook)(CAN_FIFOMailBox_TypeDef *to_push);
typedef int (*tx_hook)(CAN_FIFOMailBox_TypeDef *to_send); typedef int (*tx_hook)(CAN_FIFOMailBox_TypeDef *to_send);
typedef int (*tx_lin_hook)(int lin_num, uint8_t *data, int len); typedef int (*tx_lin_hook)(int lin_num, uint8_t *data, int len);
typedef int (*ign_hook)(); typedef int (*ign_hook)();
typedef int (*fwd_hook)(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd); typedef int (*fwd_hook)(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd);
typedef int (*relay_hook)();
typedef struct { typedef struct {
safety_hook_init init; safety_hook_init init;
@ -50,21 +41,23 @@ typedef struct {
tx_hook tx; tx_hook tx;
tx_lin_hook tx_lin; tx_lin_hook tx_lin;
fwd_hook fwd; fwd_hook fwd;
relay_hook relay;
} safety_hooks; } safety_hooks;
// This can be set by the safety hooks. // This can be set by the safety hooks.
int controls_allowed = 0; int controls_allowed = 0;
int gas_interceptor_detected = 0;
int gas_interceptor_prev = 0;
// This is set by USB command 0xdf
int long_controls_allowed = 1;
// Include the actual safety policies. // Include the actual safety policies.
#include "safety/safety_defaults.h" #include "safety/safety_defaults.h"
#include "safety/safety_honda.h" #include "safety/safety_honda.h"
#include "safety/safety_toyota.h" #include "safety/safety_toyota.h"
#ifdef PANDA
#include "safety/safety_toyota_ipas.h" #include "safety/safety_toyota_ipas.h"
#include "safety/safety_tesla.h" #include "safety/safety_tesla.h"
#include "safety/safety_gm_ascm.h" #include "safety/safety_gm_ascm.h"
#endif
#include "safety/safety_gm.h" #include "safety/safety_gm.h"
#include "safety/safety_ford.h" #include "safety/safety_ford.h"
#include "safety/safety_cadillac.h" #include "safety/safety_cadillac.h"
@ -97,10 +90,6 @@ int safety_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
return current_hooks->fwd(bus_num, to_fwd); return current_hooks->fwd(bus_num, to_fwd);
} }
int safety_relay_hook(void) {
return current_hooks->relay();
}
typedef struct { typedef struct {
uint16_t id; uint16_t id;
const safety_hooks *hooks; const safety_hooks *hooks;
@ -119,7 +108,6 @@ typedef struct {
#define SAFETY_SUBARU 10 #define SAFETY_SUBARU 10
#define SAFETY_GM_ASCM 0x1334 #define SAFETY_GM_ASCM 0x1334
#define SAFETY_TOYOTA_IPAS 0x1335 #define SAFETY_TOYOTA_IPAS 0x1335
#define SAFETY_TOYOTA_NOLIMITS 0x1336
#define SAFETY_ALLOUTPUT 0x1337 #define SAFETY_ALLOUTPUT 0x1337
#define SAFETY_ELM327 0xE327 #define SAFETY_ELM327 0xE327
@ -134,12 +122,9 @@ const safety_hook_config safety_hook_registry[] = {
{SAFETY_HYUNDAI, &hyundai_hooks}, {SAFETY_HYUNDAI, &hyundai_hooks},
{SAFETY_CHRYSLER, &chrysler_hooks}, {SAFETY_CHRYSLER, &chrysler_hooks},
{SAFETY_SUBARU, &subaru_hooks}, {SAFETY_SUBARU, &subaru_hooks},
{SAFETY_TOYOTA_NOLIMITS, &toyota_nolimits_hooks},
#ifdef PANDA
{SAFETY_TOYOTA_IPAS, &toyota_ipas_hooks}, {SAFETY_TOYOTA_IPAS, &toyota_ipas_hooks},
{SAFETY_GM_ASCM, &gm_ascm_hooks}, {SAFETY_GM_ASCM, &gm_ascm_hooks},
{SAFETY_TESLA, &tesla_hooks}, {SAFETY_TESLA, &tesla_hooks},
#endif
{SAFETY_ALLOUTPUT, &alloutput_hooks}, {SAFETY_ALLOUTPUT, &alloutput_hooks},
{SAFETY_ELM327, &elm327_hooks}, {SAFETY_ELM327, &elm327_hooks},
}; };
@ -239,7 +224,6 @@ int rt_rate_limit_check(int val, int val_last, const int MAX_RT_DELTA) {
} }
#ifdef PANDA
// interp function that holds extreme values // interp function that holds extreme values
float interpolate(struct lookup_t xy, float x) { float interpolate(struct lookup_t xy, float x) {
int size = sizeof(xy.x) / sizeof(xy.x[0]); int size = sizeof(xy.x) / sizeof(xy.x[0]);
@ -264,4 +248,3 @@ float interpolate(struct lookup_t xy, float x) {
return xy.y[size - 1]; return xy.y[size - 1];
} }
} }
#endif

@ -115,9 +115,6 @@ static int cadillac_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
static void cadillac_init(int16_t param) { static void cadillac_init(int16_t param) {
controls_allowed = 0; controls_allowed = 0;
cadillac_ign = 0; cadillac_ign = 0;
#ifdef PANDA
lline_relay_release();
#endif
} }
static int cadillac_ign_hook() { static int cadillac_ign_hook() {
@ -131,5 +128,4 @@ const safety_hooks cadillac_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = cadillac_ign_hook, .ignition = cadillac_ign_hook,
.fwd = alloutput_fwd_hook, .fwd = alloutput_fwd_hook,
.relay = nooutput_relay_hook,
}; };

@ -127,9 +127,6 @@ static int chrysler_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
static void chrysler_init(int16_t param) { static void chrysler_init(int16_t param) {
chrysler_camera_detected = 0; chrysler_camera_detected = 0;
#ifdef PANDA
lline_relay_release();
#endif
} }
static int chrysler_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { static int chrysler_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
@ -153,5 +150,4 @@ const safety_hooks chrysler_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = chrysler_fwd_hook, .fwd = chrysler_fwd_hook,
.relay = nooutput_relay_hook,
}; };

@ -8,9 +8,6 @@ int default_ign_hook() {
static void nooutput_init(int16_t param) { static void nooutput_init(int16_t param) {
controls_allowed = 0; controls_allowed = 0;
#ifdef PANDA
lline_relay_release();
#endif
} }
static int nooutput_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { static int nooutput_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
@ -25,10 +22,6 @@ static int nooutput_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
return -1; return -1;
} }
static int nooutput_relay_hook(int to_set) {
return false;
}
const safety_hooks nooutput_hooks = { const safety_hooks nooutput_hooks = {
.init = nooutput_init, .init = nooutput_init,
.rx = default_rx_hook, .rx = default_rx_hook,
@ -36,16 +29,12 @@ const safety_hooks nooutput_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = nooutput_fwd_hook, .fwd = nooutput_fwd_hook,
.relay = nooutput_relay_hook,
}; };
// *** all output safety mode *** // *** all output safety mode ***
static void alloutput_init(int16_t param) { static void alloutput_init(int16_t param) {
controls_allowed = 1; controls_allowed = 1;
#ifdef PANDA
lline_relay_release();
#endif
} }
static int alloutput_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { static int alloutput_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
@ -60,10 +49,6 @@ static int alloutput_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
return -1; return -1;
} }
static int alloutput_relay_hook(int to_set) {
return true;
}
const safety_hooks alloutput_hooks = { const safety_hooks alloutput_hooks = {
.init = alloutput_init, .init = alloutput_init,
.rx = default_rx_hook, .rx = default_rx_hook,
@ -71,5 +56,4 @@ const safety_hooks alloutput_hooks = {
.tx_lin = alloutput_tx_lin_hook, .tx_lin = alloutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = alloutput_fwd_hook, .fwd = alloutput_fwd_hook,
.relay = alloutput_relay_hook,
}; };

@ -1,5 +1,3 @@
static void elm327_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {}
static int elm327_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { static int elm327_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
//All ELM traffic must appear on CAN0 //All ELM traffic must appear on CAN0
if(((to_send->RDTR >> 4) & 0xf) != 0) return 0; if(((to_send->RDTR >> 4) & 0xf) != 0) return 0;
@ -27,20 +25,11 @@ static int elm327_tx_lin_hook(int lin_num, uint8_t *data, int len) {
return true; return true;
} }
static void elm327_init(int16_t param) {
controls_allowed = 1;
}
static int elm327_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
return -1;
}
const safety_hooks elm327_hooks = { const safety_hooks elm327_hooks = {
.init = elm327_init, .init = nooutput_init,
.rx = elm327_rx_hook, .rx = default_rx_hook,
.tx = elm327_tx_hook, .tx = elm327_tx_hook,
.tx_lin = elm327_tx_lin_hook, .tx_lin = elm327_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = elm327_fwd_hook, .fwd = nooutput_fwd_hook,
.relay = nooutput_relay_hook,
}; };

@ -90,5 +90,4 @@ const safety_hooks ford_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = nooutput_fwd_hook, .fwd = nooutput_fwd_hook,
.relay = nooutput_relay_hook,
}; };

@ -101,7 +101,7 @@ static void gm_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
// exit controls on rising edge of gas press // exit controls on rising edge of gas press
if (addr == 417) { if (addr == 417) {
int gas = to_push->RDHR & 0xFF0000; int gas = to_push->RDHR & 0xFF0000;
if (gas && !gm_gas_prev) { if (gas && !gm_gas_prev && long_controls_allowed) {
controls_allowed = 0; controls_allowed = 0;
} }
gm_gas_prev = gas; gm_gas_prev = gas;
@ -148,7 +148,7 @@ static int gm_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
int rdlr = to_send->RDLR; int rdlr = to_send->RDLR;
int brake = ((rdlr & 0xF) << 8) + ((rdlr & 0xFF00) >> 8); int brake = ((rdlr & 0xF) << 8) + ((rdlr & 0xFF00) >> 8);
brake = (0x1000 - brake) & 0xFFF; brake = (0x1000 - brake) & 0xFFF;
if (current_controls_allowed) { if (current_controls_allowed && long_controls_allowed) {
if (brake > GM_MAX_BRAKE) return 0; if (brake > GM_MAX_BRAKE) return 0;
} else { } else {
if (brake != 0) return 0; if (brake != 0) return 0;
@ -212,7 +212,7 @@ static int gm_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
int rdlr = to_send->RDLR; int rdlr = to_send->RDLR;
int gas_regen = ((rdlr & 0x7F0000) >> 11) + ((rdlr & 0xF8000000) >> 27); int gas_regen = ((rdlr & 0x7F0000) >> 11) + ((rdlr & 0xF8000000) >> 27);
int apply = rdlr & 1; int apply = rdlr & 1;
if (current_controls_allowed) { if (current_controls_allowed && long_controls_allowed) {
if (gas_regen > GM_MAX_GAS) return 0; if (gas_regen > GM_MAX_GAS) return 0;
} else { } else {
// Disabled message is !engaed with gas // Disabled message is !engaed with gas
@ -228,9 +228,6 @@ static int gm_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
static void gm_init(int16_t param) { static void gm_init(int16_t param) {
controls_allowed = 0; controls_allowed = 0;
gm_ignition_started = 0; gm_ignition_started = 0;
#ifdef PANDA
lline_relay_release();
#endif
} }
static int gm_ign_hook() { static int gm_ign_hook() {
@ -244,5 +241,4 @@ const safety_hooks gm_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = gm_ign_hook, .ignition = gm_ign_hook,
.fwd = nooutput_fwd_hook, .fwd = nooutput_fwd_hook,
.relay = nooutput_relay_hook,
}; };

@ -48,6 +48,5 @@ const safety_hooks gm_ascm_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = gm_ascm_fwd_hook, .fwd = gm_ascm_fwd_hook,
.relay = nooutput_relay_hook,
}; };

@ -7,15 +7,11 @@
// brake rising edge // brake rising edge
// brake > 0mph // brake > 0mph
// these are set in the Honda safety hooks...this is the wrong place const int HONDA_GAS_INTERCEPTOR_THRESHOLD = 328; // ratio between offset and gain from dbc file
const int gas_interceptor_threshold = 328; int honda_brake_prev = 0;
int gas_interceptor_detected = 0; int honda_gas_prev = 0;
int brake_prev = 0; int honda_ego_speed = 0;
int gas_prev = 0; bool honda_bosch_hardware = false;
int gas_interceptor_prev = 0;
int ego_speed = 0;
// TODO: auto-detect bosch hardware based on CAN messages?
bool bosch_hardware = false;
bool honda_alt_brake_msg = false; bool honda_alt_brake_msg = false;
static void honda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { static void honda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
@ -23,7 +19,7 @@ static void honda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
// sample speed // sample speed
if ((to_push->RIR>>21) == 0x158) { if ((to_push->RIR>>21) == 0x158) {
// first 2 bytes // first 2 bytes
ego_speed = to_push->RDLR & 0xFFFF; honda_ego_speed = to_push->RDLR & 0xFFFF;
} }
// state machine to enter and exit controls // state machine to enter and exit controls
@ -49,10 +45,10 @@ static void honda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
// speed > 0 // speed > 0
if (IS_USER_BRAKE_MSG(to_push)) { if (IS_USER_BRAKE_MSG(to_push)) {
int brake = USER_BRAKE_VALUE(to_push); int brake = USER_BRAKE_VALUE(to_push);
if (brake && (!(brake_prev) || ego_speed)) { if (brake && (!(honda_brake_prev) || honda_ego_speed)) {
controls_allowed = 0; controls_allowed = 0;
} }
brake_prev = brake; honda_brake_prev = brake;
} }
// exit controls on rising edge of gas press if interceptor (0x201 w/ len = 6) // exit controls on rising edge of gas press if interceptor (0x201 w/ len = 6)
@ -60,8 +56,9 @@ static void honda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
if ((to_push->RIR>>21) == 0x201 && (to_push->RDTR & 0xf) == 6) { if ((to_push->RIR>>21) == 0x201 && (to_push->RDTR & 0xf) == 6) {
gas_interceptor_detected = 1; gas_interceptor_detected = 1;
int gas_interceptor = ((to_push->RDLR & 0xFF) << 8) | ((to_push->RDLR & 0xFF00) >> 8); int gas_interceptor = ((to_push->RDLR & 0xFF) << 8) | ((to_push->RDLR & 0xFF00) >> 8);
if ((gas_interceptor > gas_interceptor_threshold) && if ((gas_interceptor > HONDA_GAS_INTERCEPTOR_THRESHOLD) &&
(gas_interceptor_prev <= gas_interceptor_threshold)) { (gas_interceptor_prev <= HONDA_GAS_INTERCEPTOR_THRESHOLD) &&
long_controls_allowed) {
controls_allowed = 0; controls_allowed = 0;
} }
gas_interceptor_prev = gas_interceptor; gas_interceptor_prev = gas_interceptor;
@ -71,10 +68,10 @@ static void honda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
if (!gas_interceptor_detected) { if (!gas_interceptor_detected) {
if ((to_push->RIR>>21) == 0x17C) { if ((to_push->RIR>>21) == 0x17C) {
int gas = to_push->RDLR & 0xFF; int gas = to_push->RDLR & 0xFF;
if (gas && !(gas_prev)) { if (gas && !(honda_gas_prev) && long_controls_allowed) {
controls_allowed = 0; controls_allowed = 0;
} }
gas_prev = gas; honda_gas_prev = gas;
} }
} }
} }
@ -89,13 +86,13 @@ static int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
// disallow actuator commands if gas or brake (with vehicle moving) are pressed // disallow actuator commands if gas or brake (with vehicle moving) are pressed
// and the the latching controls_allowed flag is True // and the the latching controls_allowed flag is True
int pedal_pressed = gas_prev || (gas_interceptor_prev > gas_interceptor_threshold) || int pedal_pressed = honda_gas_prev || (gas_interceptor_prev > HONDA_GAS_INTERCEPTOR_THRESHOLD) ||
(brake_prev && ego_speed); (honda_brake_prev && honda_ego_speed);
int current_controls_allowed = controls_allowed && !(pedal_pressed); int current_controls_allowed = controls_allowed && !(pedal_pressed);
// BRAKE: safety check // BRAKE: safety check
if ((to_send->RIR>>21) == 0x1FA) { if ((to_send->RIR>>21) == 0x1FA) {
if (current_controls_allowed) { if (current_controls_allowed && long_controls_allowed) {
if ((to_send->RDLR & 0xFFFFFF3F) != to_send->RDLR) return 0; if ((to_send->RDLR & 0xFFFFFF3F) != to_send->RDLR) return 0;
} else { } else {
if ((to_send->RDLR & 0xFFFF0000) != to_send->RDLR) return 0; if ((to_send->RDLR & 0xFFFF0000) != to_send->RDLR) return 0;
@ -113,7 +110,7 @@ static int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
// GAS: safety check // GAS: safety check
if ((to_send->RIR>>21) == 0x200) { if ((to_send->RIR>>21) == 0x200) {
if (current_controls_allowed) { if (current_controls_allowed && long_controls_allowed) {
// all messages are fine here // all messages are fine here
} else { } else {
if ((to_send->RDLR & 0xFFFF0000) != to_send->RDLR) return 0; if ((to_send->RDLR & 0xFFFF0000) != to_send->RDLR) return 0;
@ -123,7 +120,7 @@ static int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
// FORCE CANCEL: safety check only relevant when spamming the cancel button in Bosch HW // FORCE CANCEL: safety check only relevant when spamming the cancel button in Bosch HW
// ensuring that only the cancel button press is sent (VAL 2) when controls are off. // ensuring that only the cancel button press is sent (VAL 2) when controls are off.
// This avoids unintended engagements while still allowing resume spam // This avoids unintended engagements while still allowing resume spam
if (((to_send->RIR>>21) == 0x296) && bosch_hardware && if (((to_send->RIR>>21) == 0x296) && honda_bosch_hardware &&
!current_controls_allowed && ((to_send->RDTR >> 4) & 0xFF) == 0) { !current_controls_allowed && ((to_send->RDTR >> 4) & 0xFF) == 0) {
if (((to_send->RDLR >> 5) & 0x7) != 2) return 0; if (((to_send->RDLR >> 5) & 0x7) != 2) return 0;
} }
@ -134,21 +131,15 @@ static int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
static void honda_init(int16_t param) { static void honda_init(int16_t param) {
controls_allowed = 0; controls_allowed = 0;
bosch_hardware = false; honda_bosch_hardware = false;
honda_alt_brake_msg = false; honda_alt_brake_msg = false;
#ifdef PANDA
lline_relay_release();
#endif
} }
static void honda_bosch_init(int16_t param) { static void honda_bosch_init(int16_t param) {
controls_allowed = 0; controls_allowed = 0;
bosch_hardware = true; honda_bosch_hardware = true;
// Checking for alternate brake override from safety parameter // Checking for alternate brake override from safety parameter
honda_alt_brake_msg = param == 1 ? true : false; honda_alt_brake_msg = param == 1 ? true : false;
#ifdef PANDA
lline_relay_release();
#endif
} }
static int honda_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { static int honda_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
@ -159,11 +150,15 @@ static int honda_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
int addr = to_fwd->RIR>>21; int addr = to_fwd->RIR>>21;
if (bus_num == 0) { if (bus_num == 0) {
return 2; return 2;
} else if (bus_num == 2 && addr != 0xE4 && addr != 0x194 && addr != 0x1FA && } else if (bus_num == 2) {
addr != 0x30C && addr != 0x33D && addr != 0x39F) { // block stock lkas messages and stock acc messages (if OP is doing ACC)
int is_lkas_msg = (addr == 0xE4 || addr == 0x194 || addr == 0x33D);
int is_acc_msg = (addr == 0x1FA || addr == 0x30C || addr == 0x39F);
if (is_lkas_msg || (is_acc_msg && long_controls_allowed)) {
return -1;
}
return 0; return 0;
} }
return -1; return -1;
} }
@ -182,7 +177,6 @@ const safety_hooks honda_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = honda_fwd_hook, .fwd = honda_fwd_hook,
.relay = nooutput_relay_hook,
}; };
const safety_hooks honda_bosch_hooks = { const safety_hooks honda_bosch_hooks = {
@ -192,5 +186,4 @@ const safety_hooks honda_bosch_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = honda_bosch_fwd_hook, .fwd = honda_bosch_fwd_hook,
.relay = nooutput_relay_hook,
}; };

@ -152,9 +152,6 @@ static int hyundai_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
static void hyundai_init(int16_t param) { static void hyundai_init(int16_t param) {
controls_allowed = 0; controls_allowed = 0;
hyundai_giraffe_switch_2 = 0; hyundai_giraffe_switch_2 = 0;
#ifdef PANDA
lline_relay_release();
#endif
} }
const safety_hooks hyundai_hooks = { const safety_hooks hyundai_hooks = {
@ -164,5 +161,4 @@ const safety_hooks hyundai_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = hyundai_fwd_hook, .fwd = hyundai_fwd_hook,
.relay = nooutput_relay_hook,
}; };

@ -15,9 +15,6 @@ uint32_t subaru_ts_last = 0;
struct sample_t subaru_torque_driver; // last few driver torques measured struct sample_t subaru_torque_driver; // last few driver torques measured
static void subaru_init(int16_t param) { static void subaru_init(int16_t param) {
#ifdef PANDA
lline_relay_init();
#endif
} }
static void subaru_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { static void subaru_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
@ -142,5 +139,4 @@ const safety_hooks subaru_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = subaru_fwd_hook, .fwd = subaru_fwd_hook,
.relay = alloutput_relay_hook,
}; };

@ -219,20 +219,11 @@ static int tesla_tx_hook(CAN_FIFOMailBox_TypeDef *to_send)
return true; return true;
} }
static int tesla_tx_lin_hook(int lin_num, uint8_t *data, int len)
{
// LIN is not used on the Tesla
return false;
}
static void tesla_init(int16_t param) static void tesla_init(int16_t param)
{ {
controls_allowed = 0; controls_allowed = 0;
tesla_ignition_started = 0; tesla_ignition_started = 0;
gmlan_switch_init(1); //init the gmlan switch with 1s timeout enabled gmlan_switch_init(1); //init the gmlan switch with 1s timeout enabled
#ifdef PANDA
lline_relay_release();
#endif
} }
static int tesla_ign_hook() static int tesla_ign_hook()
@ -281,11 +272,10 @@ static int tesla_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd)
} }
const safety_hooks tesla_hooks = { const safety_hooks tesla_hooks = {
.init = tesla_init, .init = tesla_init,
.rx = tesla_rx_hook, .rx = tesla_rx_hook,
.tx = tesla_tx_hook, .tx = tesla_tx_hook,
.tx_lin = tesla_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = tesla_ign_hook, .ignition = tesla_ign_hook,
.fwd = tesla_fwd_hook, .fwd = tesla_fwd_hook,
.relay = nooutput_relay_hook,
}; };

@ -1,6 +1,3 @@
int toyota_giraffe_switch_1 = 0; // is giraffe switch 1 high?
int toyota_camera_forwarded = 0; // should we forward the camera bus?
// global torque limit // global torque limit
const int TOYOTA_MAX_TORQUE = 1500; // max torque cmd allowed ever const int TOYOTA_MAX_TORQUE = 1500; // max torque cmd allowed ever
@ -19,15 +16,19 @@ const int TOYOTA_RT_INTERVAL = 250000; // 250ms between real time checks
const int TOYOTA_MAX_ACCEL = 1500; // 1.5 m/s2 const int TOYOTA_MAX_ACCEL = 1500; // 1.5 m/s2
const int TOYOTA_MIN_ACCEL = -3000; // 3.0 m/s2 const int TOYOTA_MIN_ACCEL = -3000; // 3.0 m/s2
// global actuation limit state const int TOYOTA_GAS_INTERCEPTOR_THRESHOLD = 475; // ratio between offset and gain from dbc file
int toyota_actuation_limits = 1; // by default steer limits are imposed
// global actuation limit states
int toyota_dbc_eps_torque_factor = 100; // conversion factor for STEER_TORQUE_EPS in %: see dbc file int toyota_dbc_eps_torque_factor = 100; // conversion factor for STEER_TORQUE_EPS in %: see dbc file
// state of torque limits // 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_desired_torque_last = 0; // last desired steer torque
int toyota_rt_torque_last = 0; // last desired torque for real time check int toyota_rt_torque_last = 0; // last desired torque for real time check
uint32_t toyota_ts_last = 0; uint32_t toyota_ts_last = 0;
int toyota_cruise_engaged_last = 0; // cruise state int toyota_cruise_engaged_last = 0; // cruise state
int toyota_gas_prev = 0;
struct sample_t toyota_torque_meas; // last 3 motor torques produced by the eps struct sample_t toyota_torque_meas; // last 3 motor torques produced by the eps
@ -40,23 +41,40 @@ static void toyota_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
// scale by dbc_factor // scale by dbc_factor
torque_meas_new = (torque_meas_new * toyota_dbc_eps_torque_factor) / 100; torque_meas_new = (torque_meas_new * toyota_dbc_eps_torque_factor) / 100;
// increase torque_meas by 1 to be conservative on rounding
torque_meas_new += (torque_meas_new > 0 ? 1 : -1);
// update array of sample // update array of sample
update_sample(&toyota_torque_meas, torque_meas_new); update_sample(&toyota_torque_meas, torque_meas_new);
// increase torque_meas by 1 to be conservative on rounding
toyota_torque_meas.min--;
toyota_torque_meas.max++;
} }
// enter controls on rising edge of ACC, exit controls on ACC off // enter controls on rising edge of ACC, exit controls on ACC off
if ((to_push->RIR>>21) == 0x1D2) { if ((to_push->RIR>>21) == 0x1D2) {
// 5th bit is CRUISE_ACTIVE // 5th bit is CRUISE_ACTIVE
int cruise_engaged = to_push->RDLR & 0x20; int cruise_engaged = to_push->RDLR & 0x20;
if (cruise_engaged && !toyota_cruise_engaged_last) { // 4th bit is GAS_RELEASED
controls_allowed = 1; int gas = !(to_push->RDLR & 0x10);
} else if (!cruise_engaged) { if (!cruise_engaged ||
(gas && !toyota_gas_prev && !gas_interceptor_detected && long_controls_allowed)) {
controls_allowed = 0; controls_allowed = 0;
} else if (cruise_engaged && !toyota_cruise_engaged_last) {
controls_allowed = 1;
} }
toyota_cruise_engaged_last = cruise_engaged; toyota_cruise_engaged_last = cruise_engaged;
toyota_gas_prev = gas;
}
// exit controls on rising edge of gas press if interceptor (0x201)
if ((to_push->RIR>>21) == 0x201) {
gas_interceptor_detected = 1;
int gas_interceptor = ((to_push->RDLR & 0xFF) << 8) | ((to_push->RDLR & 0xFF00) >> 8);
if ((gas_interceptor > TOYOTA_GAS_INTERCEPTOR_THRESHOLD) &&
(gas_interceptor_prev <= TOYOTA_GAS_INTERCEPTOR_THRESHOLD) &&
long_controls_allowed) {
controls_allowed = 0;
}
gas_interceptor_prev = gas_interceptor;
} }
int bus = (to_push->RDTR >> 4) & 0xF; int bus = (to_push->RDTR >> 4) & 0xF;
@ -81,7 +99,7 @@ static int toyota_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
// GAS PEDAL: safety check // GAS PEDAL: safety check
if ((to_send->RIR>>21) == 0x200) { if ((to_send->RIR>>21) == 0x200) {
if (controls_allowed && toyota_actuation_limits) { if (controls_allowed && long_controls_allowed) {
// all messages are fine here // all messages are fine here
} else { } else {
if ((to_send->RDLR & 0xFFFF0000) != to_send->RDLR) return 0; if ((to_send->RDLR & 0xFFFF0000) != to_send->RDLR) return 0;
@ -92,10 +110,10 @@ static int toyota_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
if ((to_send->RIR>>21) == 0x343) { if ((to_send->RIR>>21) == 0x343) {
int desired_accel = ((to_send->RDLR & 0xFF) << 8) | ((to_send->RDLR >> 8) & 0xFF); int desired_accel = ((to_send->RDLR & 0xFF) << 8) | ((to_send->RDLR >> 8) & 0xFF);
desired_accel = to_signed(desired_accel, 16); desired_accel = to_signed(desired_accel, 16);
if (controls_allowed && toyota_actuation_limits) { if (controls_allowed && long_controls_allowed) {
int violation = max_limit_check(desired_accel, TOYOTA_MAX_ACCEL, TOYOTA_MIN_ACCEL); int violation = max_limit_check(desired_accel, TOYOTA_MAX_ACCEL, TOYOTA_MIN_ACCEL);
if (violation) return 0; if (violation) return 0;
} else if (!controls_allowed && (desired_accel != 0)) { } else if (desired_accel != 0) {
return 0; return 0;
} }
} }
@ -108,8 +126,7 @@ static int toyota_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
uint32_t ts = TIM2->CNT; uint32_t ts = TIM2->CNT;
// only check if controls are allowed and actuation_limits are imposed if (controls_allowed) {
if (controls_allowed && toyota_actuation_limits) {
// *** global torque limit check *** // *** global torque limit check ***
violation |= max_limit_check(desired_torque, TOYOTA_MAX_TORQUE, -TOYOTA_MAX_TORQUE); violation |= max_limit_check(desired_torque, TOYOTA_MAX_TORQUE, -TOYOTA_MAX_TORQUE);
@ -156,25 +173,27 @@ static int toyota_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
static void toyota_init(int16_t param) { static void toyota_init(int16_t param) {
controls_allowed = 0; controls_allowed = 0;
toyota_actuation_limits = 1;
toyota_giraffe_switch_1 = 0; toyota_giraffe_switch_1 = 0;
toyota_camera_forwarded = 0; toyota_camera_forwarded = 0;
toyota_dbc_eps_torque_factor = param; toyota_dbc_eps_torque_factor = param;
#ifdef PANDA
lline_relay_release();
#endif
} }
static int toyota_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { static int toyota_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
// forward cam to radar and viceversa if car, except lkas cmd and hud if (toyota_camera_forwarded && !toyota_giraffe_switch_1) {
// don't forward when switch 1 is high
if ((bus_num == 0 || bus_num == 2) && toyota_camera_forwarded && !toyota_giraffe_switch_1) {
int addr = to_fwd->RIR>>21; int addr = to_fwd->RIR>>21;
bool is_lkas_msg = (addr == 0x2E4 || addr == 0x412) && bus_num == 2; if (bus_num == 0) {
// in TSSP 2.0 the camera does ACC as well, so filter 0x343 return 2;
bool is_acc_msg = (addr == 0x343 && bus_num == 2); } else if (bus_num == 2) {
return (is_lkas_msg || is_acc_msg)? -1 : (uint8_t)(~bus_num & 0x2); // block stock lkas messages and stock acc messages (if OP is doing ACC)
int is_lkas_msg = (addr == 0x2E4 || addr == 0x412);
// in TSSP 2.0 the camera does ACC as well, so filter 0x343
int is_acc_msg = (addr == 0x343);
if (is_lkas_msg || (is_acc_msg && long_controls_allowed)) {
return -1;
}
return 0;
}
} }
return -1; return -1;
} }
@ -186,26 +205,4 @@ const safety_hooks toyota_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = toyota_fwd_hook, .fwd = toyota_fwd_hook,
.relay = nooutput_relay_hook,
};
static void toyota_nolimits_init(int16_t param) {
controls_allowed = 0;
toyota_actuation_limits = 0;
toyota_giraffe_switch_1 = 0;
toyota_camera_forwarded = 0;
toyota_dbc_eps_torque_factor = param;
#ifdef PANDA
lline_relay_release();
#endif
}
const safety_hooks toyota_nolimits_hooks = {
.init = toyota_nolimits_init,
.rx = toyota_rx_hook,
.tx = toyota_tx_hook,
.tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook,
.fwd = toyota_fwd_hook,
.relay = nooutput_relay_hook,
}; };

@ -152,5 +152,4 @@ const safety_hooks toyota_ipas_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = toyota_fwd_hook, .fwd = toyota_fwd_hook,
.relay = nooutput_relay_hook,
}; };

@ -2,7 +2,9 @@
uint32_t *prog_ptr = NULL; uint32_t *prog_ptr = NULL;
int unlocked = 0; int unlocked = 0;
#ifdef uart_ring
void debug_ring_callback(uart_ring *ring) {} void debug_ring_callback(uart_ring *ring) {}
#endif
int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) { int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) {
int resp_len = 0; int resp_len = 0;
@ -46,7 +48,7 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) {
break; break;
// **** 0xd0: fetch serial number // **** 0xd0: fetch serial number
case 0xd0: case 0xd0:
#ifdef PANDA #ifdef STM32F4
// addresses are OTP // addresses are OTP
if (setup->b.wValue.w == 1) { if (setup->b.wValue.w == 1) {
memcpy(resp, (void *)0x1fff79c0, 0x10); memcpy(resp, (void *)0x1fff79c0, 0x10);
@ -132,6 +134,7 @@ int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) {
#ifdef PEDAL #ifdef PEDAL
#include "drivers/llcan.h"
#define CAN CAN1 #define CAN CAN1
#define CAN_BL_INPUT 0x1 #define CAN_BL_INPUT 0x1
@ -239,7 +242,7 @@ void CAN1_RX0_IRQHandler() {
} }
void CAN1_SCE_IRQHandler() { void CAN1_SCE_IRQHandler() {
can_sce(CAN); llcan_clear_send(CAN);
} }
#endif #endif
@ -264,8 +267,8 @@ void soft_flasher_start() {
set_can_enable(CAN1, 1); set_can_enable(CAN1, 1);
// init can // init can
can_silent = ALL_CAN_LIVE; llcan_set_speed(CAN1, 5000, false, false);
can_init(0); llcan_init(CAN1);
#endif #endif
// A4,A5,A6,A7: setup SPI // A4,A5,A6,A7: setup SPI

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 12 KiB

@ -3,7 +3,7 @@ import time
import struct import struct
from panda import Panda from panda import Panda
from hexdump import hexdump from hexdump import hexdump
from panda.isotp import isotp_send, isotp_recv from panda.python.isotp import isotp_send, isotp_recv
# 0x7e0 = Toyota # 0x7e0 = Toyota
# 0x18DB33F1 for Honda? # 0x18DB33F1 for Honda?
@ -33,7 +33,7 @@ if __name__ == "__main__":
panda.can_clear(0) panda.can_clear(0)
# 09 02 = Get VIN # 09 02 = Get VIN
isotp_send(panda, "\x09\x02", 0x7e0) isotp_send(panda, "\x09\x02", 0x7df)
ret = isotp_recv(panda, 0x7e8) ret = isotp_recv(panda, 0x7e8)
hexdump(ret) hexdump(ret)
print "VIN: %s" % ret[2:] print "VIN: %s" % ret[2:]

@ -392,9 +392,6 @@ class Panda(object):
elif bus in [Panda.GMLAN_CAN2, Panda.GMLAN_CAN3]: elif bus in [Panda.GMLAN_CAN2, Panda.GMLAN_CAN3]:
self._handle.controlWrite(Panda.REQUEST_OUT, 0xdb, 1, bus, b'') self._handle.controlWrite(Panda.REQUEST_OUT, 0xdb, 1, bus, b'')
def set_lline_relay(self, enable):
self._handle.controlWrite(Panda.REQUEST_OUT, 0xf3, int(enable), 0, b'')
def set_can_loopback(self, enable): def set_can_loopback(self, enable):
# set can loopback mode for all buses # set can loopback mode for all buses
self._handle.controlWrite(Panda.REQUEST_OUT, 0xe5, int(enable), 0, b'') self._handle.controlWrite(Panda.REQUEST_OUT, 0xe5, int(enable), 0, b'')

@ -6,4 +6,9 @@ else
TESTSUITE_NAME="Panda_Test-DEV" TESTSUITE_NAME="Panda_Test-DEV"
fi fi
PYTHONPATH="." nosetests -v --with-xunit --xunit-file=./$TEST_FILENAME --xunit-testsuite-name=$TESTSUITE_NAME -s tests/automated/$1*.py cd boardesp
make flashall
cd ..
PYTHONPATH="." python $(which nosetests) -v --with-xunit --xunit-file=./$TEST_FILENAME --xunit-testsuite-name=$TESTSUITE_NAME -s tests/automated/$1*.py

@ -1,12 +1,6 @@
import os import os
from panda import build_st from panda import build_st
def test_build_legacy():
build_st("obj/comma.bin", "Makefile.legacy")
def test_build_bootstub_legacy():
build_st("obj/bootstub.comma.bin", "Makefile.legacy")
def test_build_panda(): def test_build_panda():
build_st("obj/panda.bin") build_st("obj/panda.bin")

@ -29,7 +29,7 @@ def test_connect_wifi(serial=None):
@panda_color_to_serial @panda_color_to_serial
def test_flash_wifi(serial=None): def test_flash_wifi(serial=None):
connect_wifi(serial) connect_wifi(serial)
assert Panda.flash_ota_wifi(release=True), "OTA Wifi Flash Failed" assert Panda.flash_ota_wifi(release=False), "OTA Wifi Flash Failed"
connect_wifi(serial) connect_wifi(serial)
@test_white @test_white

@ -0,0 +1,9 @@
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y gcc-arm-none-eabi libnewlib-arm-none-eabi python python-pip gcc g++
RUN pip install pycrypto==2.6.1
COPY . /panda
WORKDIR /panda

@ -0,0 +1,6 @@
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y make python python-pip git
COPY tests/safety/requirements.txt /panda/tests/safety/requirements.txt
RUN pip install -r /panda/tests/safety/requirements.txt
COPY . /panda

@ -0,0 +1,8 @@
#!/bin/bash -e
git clone https://github.com/danmar/cppcheck.git || true
cd cppcheck
git checkout 29e5992e51ecf1ddba469c73a0eed0b28b131de5
make -j4
cd ../../../
tests/misra/cppcheck/cppcheck --dump board/main.c
python tests/misra/cppcheck/addons/misra.py board/main.c.dump 2>/tmp/misra/output.txt || true

@ -32,6 +32,11 @@ typedef struct
void set_controls_allowed(int c); void set_controls_allowed(int c);
int get_controls_allowed(void); int get_controls_allowed(void);
void set_long_controls_allowed(int c);
int get_long_controls_allowed(void);
void set_gas_interceptor_detected(int c);
int get_gas_interceptor_detetcted(void);
int get_gas_interceptor_prev(void);
void set_timer(int t); void set_timer(int t);
void reset_angle_control(void); void reset_angle_control(void);
@ -41,19 +46,20 @@ int toyota_tx_hook(CAN_FIFOMailBox_TypeDef *to_send);
void toyota_init(int16_t param); void toyota_init(int16_t param);
int get_toyota_torque_meas_min(void); int get_toyota_torque_meas_min(void);
int get_toyota_torque_meas_max(void); int get_toyota_torque_meas_max(void);
int get_toyota_gas_prev(void);
void set_toyota_torque_meas(int min, int max); void set_toyota_torque_meas(int min, int max);
void set_toyota_desired_torque_last(int t); void set_toyota_desired_torque_last(int t);
void set_toyota_rt_torque_last(int t); void set_toyota_rt_torque_last(int t);
void init_tests_honda(void); void init_tests_honda(void);
int get_ego_speed(void); int get_honda_ego_speed(void);
void honda_init(int16_t param); void honda_init(int16_t param);
void honda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push); void honda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push);
int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send); int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send);
int get_brake_prev(void); int get_honda_brake_prev(void);
int get_gas_prev(void); int get_honda_gas_prev(void);
void set_honda_alt_brake_msg(bool); void set_honda_alt_brake_msg(bool);
void set_bosch_hardware(bool); void set_honda_bosch_hardware(bool);
void init_tests_cadillac(void); void init_tests_cadillac(void);
void cadillac_init(int16_t param); void cadillac_init(int16_t param);

@ -51,6 +51,14 @@ void set_controls_allowed(int c){
controls_allowed = c; controls_allowed = c;
} }
void set_long_controls_allowed(int c){
long_controls_allowed = c;
}
void set_gas_interceptor_detected(int c){
gas_interceptor_detected = c;
}
void reset_angle_control(void){ void reset_angle_control(void){
angle_control = 0; angle_control = 0;
} }
@ -59,6 +67,18 @@ int get_controls_allowed(void){
return controls_allowed; return controls_allowed;
} }
int get_long_controls_allowed(void){
return long_controls_allowed;
}
int get_gas_interceptor_detected(void){
return gas_interceptor_detected;
}
int get_gas_interceptor_prev(void){
return gas_interceptor_prev;
}
void set_timer(int t){ void set_timer(int t){
timer.CNT = t; timer.CNT = t;
} }
@ -101,6 +121,10 @@ int get_chrysler_torque_meas_max(void){
return chrysler_torque_meas.max; return chrysler_torque_meas.max;
} }
int get_toyota_gas_prev(void){
return toyota_gas_prev;
}
int get_toyota_torque_meas_min(void){ int get_toyota_torque_meas_min(void){
return toyota_torque_meas.min; return toyota_torque_meas.min;
} }
@ -157,24 +181,24 @@ void set_subaru_desired_torque_last(int t){
subaru_desired_torque_last = t; subaru_desired_torque_last = t;
} }
int get_ego_speed(void){ int get_honda_ego_speed(void){
return ego_speed; return honda_ego_speed;
} }
int get_brake_prev(void){ int get_honda_brake_prev(void){
return brake_prev; return honda_brake_prev;
} }
int get_gas_prev(void){ int get_honda_gas_prev(void){
return gas_prev; return honda_gas_prev;
} }
void set_honda_alt_brake_msg(bool c){ void set_honda_alt_brake_msg(bool c){
honda_alt_brake_msg = c; honda_alt_brake_msg = c;
} }
void set_bosch_hardware(bool c){ void set_honda_bosch_hardware(bool c){
bosch_hardware = c; honda_bosch_hardware = c;
} }
void init_tests_toyota(void){ void init_tests_toyota(void){
@ -232,10 +256,9 @@ void init_tests_subaru(void){
} }
void init_tests_honda(void){ void init_tests_honda(void){
ego_speed = 0; honda_ego_speed = 0;
gas_interceptor_detected = 0; honda_brake_prev = 0;
brake_prev = 0; honda_gas_prev = 0;
gas_prev = 0;
} }
void set_gmlan_digital_output(int to_set){ void set_gmlan_digital_output(int to_set){
@ -247,11 +270,3 @@ void reset_gmlan_switch_timeout(void){
void gmlan_switch_init(int timeout_enable){ void gmlan_switch_init(int timeout_enable){
} }
void lline_relay_init (void) {
}
void lline_relay_release (void) {
}
void set_lline_output(int to_set) {
}

@ -138,10 +138,15 @@ class TestGmSafety(unittest.TestCase):
self.safety.gm_rx_hook(self._brake_msg(False)) self.safety.gm_rx_hook(self._brake_msg(False))
def test_disengage_on_gas(self): def test_disengage_on_gas(self):
self.safety.set_controls_allowed(1) for long_controls_allowed in [0, 1]:
self.safety.gm_rx_hook(self._gas_msg(True)) self.safety.set_long_controls_allowed(long_controls_allowed)
self.assertFalse(self.safety.get_controls_allowed()) self.safety.set_controls_allowed(1)
self.safety.gm_rx_hook(self._gas_msg(False)) self.safety.gm_rx_hook(self._gas_msg(True))
if long_controls_allowed:
self.assertFalse(self.safety.get_controls_allowed())
else:
self.assertTrue(self.safety.get_controls_allowed())
self.safety.gm_rx_hook(self._gas_msg(False))
def test_allow_engage_with_gas_pressed(self): def test_allow_engage_with_gas_pressed(self):
self.safety.gm_rx_hook(self._gas_msg(True)) self.safety.gm_rx_hook(self._gas_msg(True))
@ -151,22 +156,28 @@ class TestGmSafety(unittest.TestCase):
self.safety.gm_rx_hook(self._gas_msg(False)) self.safety.gm_rx_hook(self._gas_msg(False))
def test_brake_safety_check(self): def test_brake_safety_check(self):
for enabled in [0, 1]: for long_controls_allowed in [0, 1]:
for b in range(0, 500): self.safety.set_long_controls_allowed(long_controls_allowed)
self.safety.set_controls_allowed(enabled) for enabled in [0, 1]:
if abs(b) > MAX_BRAKE or (not enabled and b != 0): for b in range(0, 500):
self.assertFalse(self.safety.gm_tx_hook(self._send_brake_msg(b))) self.safety.set_controls_allowed(enabled)
else: if abs(b) > MAX_BRAKE or ((not enabled or not long_controls_allowed) and b != 0):
self.assertTrue(self.safety.gm_tx_hook(self._send_brake_msg(b))) self.assertFalse(self.safety.gm_tx_hook(self._send_brake_msg(b)))
else:
self.assertTrue(self.safety.gm_tx_hook(self._send_brake_msg(b)))
self.safety.set_long_controls_allowed(True)
def test_gas_safety_check(self): def test_gas_safety_check(self):
for enabled in [0, 1]: for long_controls_allowed in [0, 1]:
for g in range(0, 2**12-1): self.safety.set_long_controls_allowed(long_controls_allowed)
self.safety.set_controls_allowed(enabled) for enabled in [0, 1]:
if abs(g) > MAX_GAS or (not enabled and g != MAX_REGEN): for g in range(0, 2**12-1):
self.assertFalse(self.safety.gm_tx_hook(self._send_gas_msg(g))) self.safety.set_controls_allowed(enabled)
else: if abs(g) > MAX_GAS or ((not enabled or not long_controls_allowed) and g != MAX_REGEN):
self.assertTrue(self.safety.gm_tx_hook(self._send_gas_msg(g))) self.assertFalse(self.safety.gm_tx_hook(self._send_gas_msg(g)))
else:
self.assertTrue(self.safety.gm_tx_hook(self._send_gas_msg(g)))
self.safety.set_long_controls_allowed(True)
def test_steer_safety_check(self): def test_steer_safety_check(self):
for enabled in [0, 1]: for enabled in [0, 1]:

@ -3,6 +3,7 @@ import unittest
import numpy as np import numpy as np
import libpandasafety_py import libpandasafety_py
MAX_BRAKE = 255
class TestHondaSafety(unittest.TestCase): class TestHondaSafety(unittest.TestCase):
@classmethod @classmethod
@ -49,14 +50,15 @@ class TestHondaSafety(unittest.TestCase):
def _send_brake_msg(self, brake): def _send_brake_msg(self, brake):
to_send = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *') to_send = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *')
to_send[0].RIR = 0x1FA << 21 to_send[0].RIR = 0x1FA << 21
to_send[0].RDLR = brake to_send[0].RDLR = ((brake & 0x3) << 8) | ((brake & 0x3FF) >> 2)
return to_send return to_send
def _send_gas_msg(self, gas): def _send_interceptor_msg(self, gas, addr):
to_send = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *') to_send = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *')
to_send[0].RIR = 0x200 << 21 to_send[0].RIR = addr << 21
to_send[0].RDLR = gas to_send[0].RDTR = 6
to_send[0].RDLR = ((gas & 0xff) << 8) | ((gas & 0xff00) >> 8)
return to_send return to_send
@ -89,14 +91,14 @@ class TestHondaSafety(unittest.TestCase):
self.assertFalse(self.safety.get_controls_allowed()) self.assertFalse(self.safety.get_controls_allowed())
def test_sample_speed(self): def test_sample_speed(self):
self.assertEqual(0, self.safety.get_ego_speed()) self.assertEqual(0, self.safety.get_honda_ego_speed())
self.safety.honda_rx_hook(self._speed_msg(100)) self.safety.honda_rx_hook(self._speed_msg(100))
self.assertEqual(100, self.safety.get_ego_speed()) self.assertEqual(100, self.safety.get_honda_ego_speed())
def test_prev_brake(self): def test_prev_brake(self):
self.assertFalse(self.safety.get_brake_prev()) self.assertFalse(self.safety.get_honda_brake_prev())
self.safety.honda_rx_hook(self._brake_msg(True)) self.safety.honda_rx_hook(self._brake_msg(True))
self.assertTrue(self.safety.get_brake_prev()) self.assertTrue(self.safety.get_honda_brake_prev())
def test_disengage_on_brake(self): def test_disengage_on_brake(self):
self.safety.set_controls_allowed(1) self.safety.set_controls_allowed(1)
@ -133,14 +135,30 @@ class TestHondaSafety(unittest.TestCase):
self.assertFalse(self.safety.get_controls_allowed()) self.assertFalse(self.safety.get_controls_allowed())
def test_prev_gas(self): def test_prev_gas(self):
self.assertFalse(self.safety.get_gas_prev()) self.safety.honda_rx_hook(self._gas_msg(False))
self.assertFalse(self.safety.get_honda_gas_prev())
self.safety.honda_rx_hook(self._gas_msg(True)) self.safety.honda_rx_hook(self._gas_msg(True))
self.assertTrue(self.safety.get_gas_prev()) self.assertTrue(self.safety.get_honda_gas_prev())
def test_prev_gas_interceptor(self):
self.safety.honda_rx_hook(self._send_interceptor_msg(0x0, 0x201))
self.assertFalse(self.safety.get_gas_interceptor_prev())
self.safety.honda_rx_hook(self._send_interceptor_msg(0x1000, 0x201))
self.assertTrue(self.safety.get_gas_interceptor_prev())
self.safety.honda_rx_hook(self._send_interceptor_msg(0x0, 0x201))
self.safety.set_gas_interceptor_detected(False)
def test_disengage_on_gas(self): def test_disengage_on_gas(self):
self.safety.set_controls_allowed(1) for long_controls_allowed in [0, 1]:
self.safety.honda_rx_hook(self._gas_msg(1)) self.safety.set_long_controls_allowed(long_controls_allowed)
self.assertFalse(self.safety.get_controls_allowed()) self.safety.honda_rx_hook(self._gas_msg(0))
self.safety.set_controls_allowed(1)
self.safety.honda_rx_hook(self._gas_msg(1))
if long_controls_allowed:
self.assertFalse(self.safety.get_controls_allowed())
else:
self.assertTrue(self.safety.get_controls_allowed())
self.safety.set_long_controls_allowed(True)
def test_allow_engage_with_gas_pressed(self): def test_allow_engage_with_gas_pressed(self):
self.safety.honda_rx_hook(self._gas_msg(1)) self.safety.honda_rx_hook(self._gas_msg(1))
@ -148,18 +166,53 @@ class TestHondaSafety(unittest.TestCase):
self.safety.honda_rx_hook(self._gas_msg(1)) self.safety.honda_rx_hook(self._gas_msg(1))
self.assertTrue(self.safety.get_controls_allowed()) self.assertTrue(self.safety.get_controls_allowed())
def test_brake_safety_check(self): def test_disengage_on_gas_interceptor(self):
self.assertTrue(self.safety.honda_tx_hook(self._send_brake_msg(0x0000))) for long_controls_allowed in [0, 1]:
self.assertFalse(self.safety.honda_tx_hook(self._send_brake_msg(0x1000))) self.safety.set_long_controls_allowed(long_controls_allowed)
self.safety.honda_rx_hook(self._send_interceptor_msg(0, 0x201))
self.safety.set_controls_allowed(1)
self.safety.honda_rx_hook(self._send_interceptor_msg(0x1000, 0x201))
if long_controls_allowed:
self.assertFalse(self.safety.get_controls_allowed())
else:
self.assertTrue(self.safety.get_controls_allowed())
self.safety.honda_rx_hook(self._send_interceptor_msg(0, 0x201))
self.safety.set_gas_interceptor_detected(False)
self.safety.set_long_controls_allowed(True)
def test_allow_engage_with_gas_interceptor_pressed(self):
self.safety.honda_rx_hook(self._send_interceptor_msg(0x1000, 0x201))
self.safety.set_controls_allowed(1) self.safety.set_controls_allowed(1)
self.assertTrue(self.safety.honda_tx_hook(self._send_brake_msg(0x1000))) self.safety.honda_rx_hook(self._send_interceptor_msg(0x1000, 0x201))
self.assertFalse(self.safety.honda_tx_hook(self._send_brake_msg(0x00F0))) self.assertTrue(self.safety.get_controls_allowed())
self.safety.honda_rx_hook(self._send_interceptor_msg(0, 0x201))
self.safety.set_gas_interceptor_detected(False)
def test_gas_safety_check(self): def test_brake_safety_check(self):
self.safety.set_controls_allowed(0) for long_controls_allowed in [0, 1]:
self.assertTrue(self.safety.honda_tx_hook(self._send_gas_msg(0x0000))) self.safety.set_long_controls_allowed(long_controls_allowed)
self.assertFalse(self.safety.honda_tx_hook(self._send_gas_msg(0x1000))) for brake in np.arange(0, MAX_BRAKE + 10, 1):
for controls_allowed in [True, False]:
self.safety.set_controls_allowed(controls_allowed)
if controls_allowed and long_controls_allowed:
send = MAX_BRAKE >= brake >= 0
else:
send = brake == 0
self.assertEqual(send, self.safety.honda_tx_hook(self._send_brake_msg(brake)))
self.safety.set_long_controls_allowed(True)
def test_gas_interceptor_safety_check(self):
for long_controls_allowed in [0, 1]:
self.safety.set_long_controls_allowed(long_controls_allowed)
for gas in np.arange(0, 4000, 100):
for controls_allowed in [True, False]:
self.safety.set_controls_allowed(controls_allowed)
if controls_allowed and long_controls_allowed:
send = True
else:
send = gas == 0
self.assertEqual(send, self.safety.honda_tx_hook(self._send_interceptor_msg(gas, 0x200)))
self.safety.set_long_controls_allowed(True)
def test_steer_safety_check(self): def test_steer_safety_check(self):
self.safety.set_controls_allowed(0) self.safety.set_controls_allowed(0)
@ -171,7 +224,7 @@ class TestHondaSafety(unittest.TestCase):
SET_BTN = 3 SET_BTN = 3
CANCEL_BTN = 2 CANCEL_BTN = 2
BUTTON_MSG = 0x296 BUTTON_MSG = 0x296
self.safety.set_bosch_hardware(1) self.safety.set_honda_bosch_hardware(1)
self.safety.set_controls_allowed(0) self.safety.set_controls_allowed(0)
self.assertTrue(self.safety.honda_tx_hook(self._button_msg(CANCEL_BTN, BUTTON_MSG))) self.assertTrue(self.safety.honda_tx_hook(self._button_msg(CANCEL_BTN, BUTTON_MSG)))
self.assertFalse(self.safety.honda_tx_hook(self._button_msg(RESUME_BTN, BUTTON_MSG))) self.assertFalse(self.safety.honda_tx_hook(self._button_msg(RESUME_BTN, BUTTON_MSG)))

@ -119,13 +119,28 @@ class TestToyotaSafety(unittest.TestCase):
to_send[0].RDLR = (a & 0xFF) << 8 | (a >> 8) to_send[0].RDLR = (a & 0xFF) << 8 | (a >> 8)
return to_send return to_send
def _gas_msg(self, gas): def _send_gas_msg(self, gas):
to_send = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *') to_send = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *')
to_send[0].RIR = 0x200 << 21 to_send[0].RIR = 0x200 << 21
to_send[0].RDLR = gas to_send[0].RDLR = gas
return to_send return to_send
def _send_interceptor_msg(self, gas, addr):
to_send = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *')
to_send[0].RIR = addr << 21
to_send[0].RDTR = 6
to_send[0].RDLR = ((gas & 0xff) << 8) | ((gas & 0xff00) >> 8)
return to_send
def _pcm_cruise_msg(self, cruise_on, gas_pressed):
to_send = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *')
to_send[0].RIR = 0x1D2 << 21
to_send[0].RDLR = (cruise_on << 5) | ((not gas_pressed) << 4 )
return to_send
def test_default_controls_not_allowed(self): def test_default_controls_not_allowed(self):
self.assertFalse(self.safety.get_controls_allowed()) self.assertFalse(self.safety.get_controls_allowed())
@ -134,32 +149,84 @@ class TestToyotaSafety(unittest.TestCase):
self.assertTrue(self.safety.get_controls_allowed()) self.assertTrue(self.safety.get_controls_allowed())
def test_enable_control_allowed_from_cruise(self): def test_enable_control_allowed_from_cruise(self):
to_push = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *') self.safety.toyota_rx_hook(self._pcm_cruise_msg(False, False))
to_push[0].RIR = 0x1D2 << 21 self.assertFalse(self.safety.get_controls_allowed())
to_push[0].RDLR = 0x20 self.safety.toyota_rx_hook(self._pcm_cruise_msg(True, False))
self.safety.toyota_rx_hook(to_push)
self.assertTrue(self.safety.get_controls_allowed()) self.assertTrue(self.safety.get_controls_allowed())
def test_disable_control_allowed_from_cruise(self): def test_disable_control_allowed_from_cruise(self):
to_push = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *')
to_push[0].RIR = 0x1D2 << 21
to_push[0].RDLR = 0
self.safety.set_controls_allowed(1) self.safety.set_controls_allowed(1)
self.safety.toyota_rx_hook(to_push) self.safety.toyota_rx_hook(self._pcm_cruise_msg(False, False))
self.assertFalse(self.safety.get_controls_allowed()) self.assertFalse(self.safety.get_controls_allowed())
def test_accel_actuation_limits(self): def test_prev_gas(self):
for accel in np.arange(MIN_ACCEL - 1000, MAX_ACCEL + 1000, 100): self.safety.toyota_rx_hook(self._pcm_cruise_msg(False, False))
for controls_allowed in [True, False]: self.assertFalse(self.safety.get_toyota_gas_prev())
self.safety.set_controls_allowed(controls_allowed) self.safety.toyota_rx_hook(self._pcm_cruise_msg(False, True))
self.assertTrue(self.safety.get_toyota_gas_prev())
def test_prev_gas_interceptor(self):
self.safety.toyota_rx_hook(self._send_interceptor_msg(0x0, 0x201))
self.assertFalse(self.safety.get_gas_interceptor_prev())
self.safety.toyota_rx_hook(self._send_interceptor_msg(0x1000, 0x201))
self.assertTrue(self.safety.get_gas_interceptor_prev())
self.safety.toyota_rx_hook(self._send_interceptor_msg(0x0, 0x201))
self.safety.set_gas_interceptor_detected(False)
def test_disengage_on_gas(self):
for long_controls_allowed in [0, 1]:
self.safety.set_long_controls_allowed(long_controls_allowed)
self.safety.toyota_rx_hook(self._pcm_cruise_msg(False, False))
self.safety.toyota_rx_hook(self._pcm_cruise_msg(True, False))
self.assertTrue(self.safety.get_controls_allowed())
self.safety.toyota_rx_hook(self._pcm_cruise_msg(True, True))
if long_controls_allowed:
self.assertFalse(self.safety.get_controls_allowed())
else:
self.assertTrue(self.safety.get_controls_allowed())
self.safety.set_long_controls_allowed(True)
if controls_allowed: def test_allow_engage_with_gas_pressed(self):
send = MIN_ACCEL <= accel <= MAX_ACCEL self.safety.toyota_rx_hook(self._pcm_cruise_msg(False, True))
else: self.safety.toyota_rx_hook(self._pcm_cruise_msg(True, True))
send = accel == 0 self.assertTrue(self.safety.get_controls_allowed())
self.assertEqual(send, self.safety.toyota_tx_hook(self._accel_msg(accel))) self.safety.toyota_rx_hook(self._pcm_cruise_msg(True, True))
self.assertTrue(self.safety.get_controls_allowed())
def test_disengage_on_gas_interceptor(self):
for long_controls_allowed in [0, 1]:
self.safety.set_long_controls_allowed(long_controls_allowed)
self.safety.toyota_rx_hook(self._send_interceptor_msg(0, 0x201))
self.safety.set_controls_allowed(1)
self.safety.toyota_rx_hook(self._send_interceptor_msg(0x1000, 0x201))
if long_controls_allowed:
self.assertFalse(self.safety.get_controls_allowed())
else:
self.assertTrue(self.safety.get_controls_allowed())
self.safety.toyota_rx_hook(self._send_interceptor_msg(0, 0x201))
self.safety.set_gas_interceptor_detected(False)
self.safety.set_long_controls_allowed(True)
def test_allow_engage_with_gas_interceptor_pressed(self):
self.safety.toyota_rx_hook(self._send_interceptor_msg(0x1000, 0x201))
self.safety.set_controls_allowed(1)
self.safety.toyota_rx_hook(self._send_interceptor_msg(0x1000, 0x201))
self.assertTrue(self.safety.get_controls_allowed())
self.safety.toyota_rx_hook(self._send_interceptor_msg(0, 0x201))
self.safety.set_gas_interceptor_detected(False)
def test_accel_actuation_limits(self):
for long_controls_allowed in [0, 1]:
self.safety.set_long_controls_allowed(long_controls_allowed)
for accel in np.arange(MIN_ACCEL - 1000, MAX_ACCEL + 1000, 100):
for controls_allowed in [True, False]:
self.safety.set_controls_allowed(controls_allowed)
if controls_allowed and long_controls_allowed:
send = MIN_ACCEL <= accel <= MAX_ACCEL
else:
send = accel == 0
self.assertEqual(send, self.safety.toyota_tx_hook(self._accel_msg(accel)))
self.safety.set_long_controls_allowed(True)
def test_torque_absolute_limits(self): def test_torque_absolute_limits(self):
for controls_allowed in [True, False]: for controls_allowed in [True, False]:
@ -244,11 +311,11 @@ class TestToyotaSafety(unittest.TestCase):
self.assertEqual(51, self.safety.get_toyota_torque_meas_max()) self.assertEqual(51, self.safety.get_toyota_torque_meas_max())
self.safety.toyota_rx_hook(self._torque_meas_msg(0)) self.safety.toyota_rx_hook(self._torque_meas_msg(0))
self.assertEqual(-1, self.safety.get_toyota_torque_meas_max()) self.assertEqual(1, self.safety.get_toyota_torque_meas_max())
self.assertEqual(-51, self.safety.get_toyota_torque_meas_min()) self.assertEqual(-51, self.safety.get_toyota_torque_meas_min())
self.safety.toyota_rx_hook(self._torque_meas_msg(0)) self.safety.toyota_rx_hook(self._torque_meas_msg(0))
self.assertEqual(-1, self.safety.get_toyota_torque_meas_max()) self.assertEqual(1, self.safety.get_toyota_torque_meas_max())
self.assertEqual(-1, self.safety.get_toyota_torque_meas_min()) self.assertEqual(-1, self.safety.get_toyota_torque_meas_min())
def test_ipas_override(self): def test_ipas_override(self):
@ -416,12 +483,13 @@ class TestToyotaSafety(unittest.TestCase):
# reset no angle control at the end of the test # reset no angle control at the end of the test
self.safety.reset_angle_control() self.safety.reset_angle_control()
def test_gas_safety_check(self): def test_gas_interceptor_safety_check(self):
self.safety.set_controls_allowed(0) self.safety.set_controls_allowed(0)
self.assertTrue(self.safety.honda_tx_hook(self._gas_msg(0x0000))) self.assertTrue(self.safety.toyota_tx_hook(self._send_interceptor_msg(0, 0x200)))
self.assertFalse(self.safety.honda_tx_hook(self._gas_msg(0x1000))) self.assertFalse(self.safety.toyota_tx_hook(self._send_interceptor_msg(0x1000, 0x200)))
self.safety.set_controls_allowed(1) self.safety.set_controls_allowed(1)
self.assertTrue(self.safety.honda_tx_hook(self._gas_msg(0x1000))) self.assertTrue(self.safety.toyota_tx_hook(self._send_interceptor_msg(0x1000, 0x200)))
if __name__ == "__main__": if __name__ == "__main__":

Loading…
Cancel
Save