Squashed 'panda/' changes from 3e199cb..7f8babb

7f8babb Much more thorough limit safety tests on Honda, also switching long_controls_allowed
71099ef AddedToyota safety test around long_controls_allowed logic and fixed a bug
07fd31e added long_controls_allowed tests in GM
6ce580a added function to get/set long_controls_allowed
a2f93d4 update VERSION
380b7c7 Long allowed (#202)
09714e3 Toyota gas cancellation (#200)
436b203 Honda safety: fixed bug and properly abstracted gas_interceptor_detected variable
220cc8f Honda safety: this concludes the proper re-naming
a00a50c Honda safety: better naming
95b0109 Toyota: fixed regression safety tests
192fd05 Toyota safety: fixed rounding logic
0c5b220 Merge pull request #194 from commaai/refactor
b35f6ff legacy build is no longer supported
a06af9f always LIVE on EON
dc5979f LIVE on EON
0b26645 no EON by default
1906a4b panda now draws below 100mw in power save mode
e70b44a move that to main.c
dfce5f6 minor fixes, and no more autobaud
7f303e8 bump version to 1.3.0
96a7e31 a soothing blue in power save mode
a74f001 refactor power savings to depend on car started bit
386d5df can wake from sleep is removed, didn't work in the first place
881b1f4 not on pedal chip
0a9f8eb remove many ifdef PANDA
5069005 remove nested includes and include guards
3810452 WTF WHY WAS THIS SHIT PUT EVERYWHERE
3cf8db9 can.h always has CAN3
1f97c21 refactor pedal bootstub to use llcan
58ec63b oops, backward
6255097 new style power savings
6b282f1 tesla doesn't need a special LIN hook
1d24677 refactor #ifdef EON
d9306c5 NEO are no longer supported
4af036e fixup puts
2c1e5f6 the refactor continues
7517f2c remove ifdef PANDA from main
aec40ae remove fan, as it was only for NEO board
605bb27 fix bootstub build
c0f1f6e move things around for simplicity
f32f039 factor out clear_send
8221927 this is probably broken. refactor out llcan and clock
1114cb1 ELM327 safety mode: re use existing functions
cd104e2 Vin query msg is 0x7df
223323a Examples: fixed import bug
533d239 update price
4396fb9 Update jenkinsfile (#193)
1aa00c9 Misra c2012 (#192)
047bd72 fix tests and remove rev b support

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