From 9a143c5ab2b86bd5dbfa0e86ac85c2d48f1de4f3 Mon Sep 17 00:00:00 2001 From: Vehicle Researcher Date: Thu, 6 Jun 2019 04:31:45 +0000 Subject: [PATCH] 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 --- .circleci/config.yml | 37 ++- .gitignore | 5 +- Dockerfile | 2 - Jenkinsfile | 2 - VERSION | 2 +- board/Makefile.legacy | 9 - board/Makefile.strict | 8 + board/README.md | 6 - board/bootstub.c | 16 +- board/drivers/can.h | 277 ++++------------- board/drivers/clock.h | 40 +++ board/drivers/drivers.h | 141 --------- board/drivers/gmlan_alt.h | 3 - board/drivers/llcan.h | 80 +++++ board/drivers/llgpio.h | 9 + board/drivers/lline_relay.h | 88 ------ board/drivers/spi.h | 11 +- board/drivers/uart.h | 22 ++ board/drivers/usb.h | 48 +-- board/gpio.h | 77 +---- board/main.c | 488 +++++++++++++++--------------- board/pedal/main.c | 44 ++- board/power_saving.h | 140 ++------- board/safety.h | 29 +- board/safety/safety_cadillac.h | 4 - board/safety/safety_chrysler.h | 4 - board/safety/safety_defaults.h | 16 - board/safety/safety_elm327.h | 17 +- board/safety/safety_ford.h | 1 - board/safety/safety_gm.h | 10 +- board/safety/safety_gm_ascm.h | 1 - board/safety/safety_honda.h | 61 ++-- board/safety/safety_hyundai.h | 4 - board/safety/safety_subaru.h | 4 - board/safety/safety_tesla.h | 22 +- board/safety/safety_toyota.h | 97 +++--- board/safety/safety_toyota_ipas.h | 1 - board/spi_flasher.h | 11 +- buy.png | Bin 4264 -> 12200 bytes examples/query_vin_and_stats.py | 4 +- python/__init__.py | 3 - run_automated_tests.sh | 7 +- tests/automated/0_builds.py | 6 - tests/automated/3_wifi.py | 2 +- tests/build_strict/Dockerfile | 9 + tests/misra/Dockerfile | 6 + tests/misra/test_misra.sh | 8 + tests/safety/libpandasafety_py.py | 14 +- tests/safety/test.c | 55 ++-- tests/safety/test_gm.py | 47 +-- tests/safety/test_honda.py | 101 +++++-- tests/safety/test_toyota.py | 120 ++++++-- 52 files changed, 970 insertions(+), 1249 deletions(-) delete mode 100644 board/Makefile.legacy create mode 100644 board/Makefile.strict create mode 100644 board/drivers/clock.h delete mode 100644 board/drivers/drivers.h create mode 100644 board/drivers/llcan.h delete mode 100644 board/drivers/lline_relay.h create mode 100644 tests/build_strict/Dockerfile create mode 100644 tests/misra/Dockerfile create mode 100755 tests/misra/test_misra.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 6b98610c50..06dae5735b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,6 +12,37 @@ jobs: name: Run safety test command: | 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: machine: docker_layer_caching: true @@ -40,10 +71,6 @@ jobs: name: Build Pedal STM bootstub image command: | 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: name: Build ESP image command: | @@ -54,4 +81,6 @@ workflows: main: jobs: - safety + - misra-c2012 + - strict-compiler - build diff --git a/.gitignore b/.gitignore index 7b7762ef49..70d010fabf 100644 --- a/.gitignore +++ b/.gitignore @@ -10,5 +10,6 @@ a.out dist/ pandacan.egg-info/ board/obj/ -examples/output.csv -.DS_Store +examples/output.csv +.DS_Store +nosetests.xml diff --git a/Dockerfile b/Dockerfile index 100509f514..1a0d924661 100644 --- a/Dockerfile +++ b/Dockerfile @@ -59,6 +59,4 @@ USER pandauser RUN cd /tmp/panda/boardesp && ./get_sdk_ci.sh USER root -COPY ./xx/pandaextra /tmp/pandaextra - ADD ./panda.tar.gz /tmp/panda diff --git a/Jenkinsfile b/Jenkinsfile index c67a100515..0a861a5fa1 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -14,8 +14,6 @@ pipeline { steps { timeout(time: 60, unit: 'MINUTES') { 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' dockerImage = docker.build("${env.DOCKER_IMAGE_TAG}") } diff --git a/VERSION b/VERSION index 24e56e03c0..23c38c2411 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v1.2.1 \ No newline at end of file +v1.3.1 \ No newline at end of file diff --git a/board/Makefile.legacy b/board/Makefile.legacy deleted file mode 100644 index f6f9f9f328..0000000000 --- a/board/Makefile.legacy +++ /dev/null @@ -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 diff --git a/board/Makefile.strict b/board/Makefile.strict new file mode 100644 index 0000000000..b2ff83d309 --- /dev/null +++ b/board/Makefile.strict @@ -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 diff --git a/board/README.md b/board/README.md index b3be654be3..5fe2e4b238 100644 --- a/board/README.md +++ b/board/README.md @@ -23,12 +23,6 @@ Programming make ``` -**NEO** - -``` -make -f Makefile.legacy -``` - Troubleshooting ---- diff --git a/board/bootstub.c b/board/bootstub.c index e44986c29e..6fcb386dea 100644 --- a/board/bootstub.c +++ b/board/bootstub.c @@ -12,11 +12,14 @@ #include "stm32f2xx_hal_gpio_ex.h" #endif +// default since there's no serial +int puts(const char *a) { return 0; } +void puth(unsigned int i) {} + #include "libc.h" #include "provision.h" -#include "drivers/drivers.h" - +#include "drivers/clock.h" #include "drivers/llgpio.h" #include "gpio.h" @@ -24,15 +27,6 @@ #include "drivers/usb.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/sha.h" diff --git a/board/drivers/can.h b/board/drivers/can.h index 9f02c2eba7..43e4d41de8 100644 --- a/board/drivers/can.h +++ b/board/drivers/can.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_BUT_MAIN_SILENT 0xFE #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; // ********************* 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(tx1_q, 0x100) can_buffer(tx2_q, 0x100) - -#ifdef PANDA - can_buffer(tx3_q, 0x100) - 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 +can_buffer(tx3_q, 0x100) +can_buffer(txgmlan_q, 0x100) +can_ring *can_queues[] = {&can_tx1_q, &can_tx2_q, &can_tx3_q, &can_txgmlan_q}; // ********************* interrupt safe queue ********************* @@ -85,76 +103,20 @@ int can_tx_cnt = 0; int can_txd_cnt = 0; int can_err_cnt = 0; -// NEO: Bus 1=CAN1 Bus 2=CAN2 // Panda: Bus 0=CAN1 Bus 1=CAN2 Bus 2=CAN3 -#ifdef PANDA - CAN_TypeDef *cans[] = {CAN1, CAN2, CAN3}; - uint8_t bus_lookup[] = {0,1,2}; - uint8_t can_num_lookup[] = {0,1,2,-1}; - int8_t can_forwarding[] = {-1,-1,-1,-1}; - uint32_t can_speed[] = {5000, 5000, 5000, 333}; - 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])) +CAN_TypeDef *cans[] = {CAN1, CAN2, CAN3}; +uint8_t bus_lookup[] = {0,1,2}; +uint8_t can_num_lookup[] = {0,1,2,-1}; +int8_t can_forwarding[] = {-1,-1,-1,-1}; +uint32_t can_speed[] = {5000, 5000, 5000, 333}; +#define CAN_MAX 3 #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_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 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 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); while (true) { - // 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(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) { + if (llcan_set_speed(CAN, can_speed[bus_number], can_loopback, can_silent & (1 << can_number))) { return; } - if (can_autobaud_enabled[bus_number]) { - can_autobaud_speed_increment(can_number); - } else { - puts("CAN init FAILED!!!!!\n"); - puth(can_number); puts(" "); - puth(BUS_NUM_FROM_CAN_NUM(can_number)); puts("\n"); - return; - } + puts("CAN init FAILED!!!!!\n"); + 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); can_set_speed(can_number); - // 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; - - 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 - } + llcan_init(CAN); // in case there are queued up messages process_can(can_number); @@ -253,7 +155,6 @@ void can_init_all() { } void can_set_gmlan(int bus) { - #ifdef PANDA if (bus == -1 || bus != can_num_lookup[3]) { // GMLAN OFF switch (can_num_lookup[3]) { @@ -284,7 +185,7 @@ void can_set_gmlan(int bus) { can_num_lookup[1] = -1; can_num_lookup[3] = 1; can_init(1); - } else if (bus == 2 && revision == PANDA_REV_C) { + } else if (bus == 2) { puts("GMLAN on CAN3\n"); // GMLAN on CAN3 set_can_mode(2, 1); @@ -293,7 +194,6 @@ void can_set_gmlan(int bus) { can_num_lookup[3] = 2; can_init(2); } - #endif } // CAN error @@ -319,34 +219,8 @@ void can_sce(CAN_TypeDef *CAN) { puts("\n"); #endif - uint8_t can_number = CAN_NUM_FROM_CANIF(CAN); - uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number); - - 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; - } + can_err_cnt += 1; + llcan_clear_send(CAN); exit_critical_section(); } @@ -354,9 +228,6 @@ void can_sce(CAN_TypeDef *CAN) { void process_can(uint8_t can_number) { if (can_number == 0xff) return; -#ifdef PANDA - power_save_reset_timer(); -#endif enter_critical_section(); @@ -422,22 +293,9 @@ void process_can(uint8_t can_number) { // CAN receive handlers // blink blue when we are receiving CAN messages void can_rx(uint8_t can_number) { - #ifdef PANDA - power_save_reset_timer(); - #endif CAN_TypeDef *CAN = CANIF_FROM_CAN_NUM(can_number); uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number); 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 is live @@ -454,25 +312,19 @@ void can_rx(uint8_t can_number) { to_push.RDTR = (to_push.RDTR & 0xFFFF000F) | (bus_number << 4); // forwarding (panda only) - #ifdef PANDA - if ((get_lline_status() != 0) || !relay_control) { //Relay engaged or relay isn't controlled, allow fwd - int bus_fwd_num = can_forwarding[bus_number] != -1 ? can_forwarding[bus_number] : safety_fwd_hook(bus_number, &to_push); - if (bus_fwd_num != -1) { - CAN_FIFOMailBox_TypeDef to_send; - to_send.RIR = to_push.RIR | 1; // TXRQ - to_send.RDTR = to_push.RDTR; - to_send.RDLR = to_push.RDLR; - to_send.RDHR = to_push.RDHR; - can_send(&to_send, bus_fwd_num); - } - } - #endif + int bus_fwd_num = can_forwarding[bus_number] != -1 ? can_forwarding[bus_number] : safety_fwd_hook(bus_number, &to_push); + if (bus_fwd_num != -1) { + CAN_FIFOMailBox_TypeDef to_send; + to_send.RIR = to_push.RIR | 1; // TXRQ + to_send.RDTR = to_push.RDTR; + to_send.RDLR = to_push.RDLR; + to_send.RDHR = to_push.RDHR; + can_send(&to_send, bus_fwd_num); + } safety_rx_hook(&to_push); - #ifdef PANDA - set_led(LED_BLUE, 1); - #endif + set_led(LED_BLUE, 1); can_push(&can_rx_q, &to_push); // 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_RX0_IRQHandler() { can_rx(0); } 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_SCE_IRQHandler() { can_sce(CAN2); } -#ifdef CAN3 void CAN3_TX_IRQHandler() { process_can(2); } void CAN3_RX0_IRQHandler() { can_rx(2); } void CAN3_SCE_IRQHandler() { can_sce(CAN3); } -#endif - -#endif 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) { // add CAN packet to send queue // bus number isn't passed through to_push->RDTR &= 0xF; if (bus_number == 3 && can_num_lookup[3] == 0xFF) { - #ifdef PANDA // TODO: why uint8 bro? only int8? bitbang_gmlan(to_push); - #endif } else { can_push(can_queues[bus_number], to_push); 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) { can_forwarding[from] = to; } + diff --git a/board/drivers/clock.h b/board/drivers/clock.h new file mode 100644 index 0000000000..c999c3f597 --- /dev/null +++ b/board/drivers/clock.h @@ -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; +} + diff --git a/board/drivers/drivers.h b/board/drivers/drivers.h deleted file mode 100644 index d3409d6099..0000000000 --- a/board/drivers/drivers.h +++ /dev/null @@ -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 - diff --git a/board/drivers/gmlan_alt.h b/board/drivers/gmlan_alt.h index 8521100a88..d24833a8fb 100644 --- a/board/drivers/gmlan_alt.h +++ b/board/drivers/gmlan_alt.h @@ -114,8 +114,6 @@ int get_bit_message(char *out, CAN_FIFOMailBox_TypeDef *to_bang) { return len; } -#ifdef PANDA - void setup_timer4() { // setup TIM4->PSC = 48-1; // tick on 1 us @@ -273,4 +271,3 @@ void bitbang_gmlan(CAN_FIFOMailBox_TypeDef *to_bang) { setup_timer4(); } -#endif diff --git a/board/drivers/llcan.h b/board/drivers/llcan.h new file mode 100644 index 0000000000..5c771f76f0 --- /dev/null +++ b/board/drivers/llcan.h @@ -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; +} + diff --git a/board/drivers/llgpio.h b/board/drivers/llgpio.h index e1835ec0f4..9841276312 100644 --- a/board/drivers/llgpio.h +++ b/board/drivers/llgpio.h @@ -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) { uint32_t tmp = GPIO->MODER; tmp &= ~(3 << (pin*2)); diff --git a/board/drivers/lline_relay.h b/board/drivers/lline_relay.h deleted file mode 100644 index 217e7dfe30..0000000000 --- a/board/drivers/lline_relay.h +++ /dev/null @@ -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 diff --git a/board/drivers/spi.h b/board/drivers/spi.h index 7a5945d372..f31f20590d 100644 --- a/board/drivers/spi.h +++ b/board/drivers/spi.h @@ -1,5 +1,10 @@ // 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 uint8_t spi_buf[SPI_BUF_SIZE]; int spi_buf_count = 0; @@ -23,8 +28,8 @@ void spi_init() { // setup interrupt on falling edge of SPI enable (on PA4) SYSCFG->EXTICR[2] = SYSCFG_EXTICR2_EXTI4_PA; - EXTI->IMR = (1 << 4); - EXTI->FTSR = (1 << 4); + EXTI->IMR |= (1 << 4); + EXTI->FTSR |= (1 << 4); NVIC_EnableIRQ(EXTI4_IRQn); } @@ -108,7 +113,7 @@ void DMA2_Stream3_IRQHandler(void) { } void EXTI4_IRQHandler(void) { - volatile int pr = EXTI->PR; + volatile int pr = EXTI->PR & (1 << 4); #ifdef DEBUG_SPI puts("exti4\n"); #endif diff --git a/board/drivers/uart.h b/board/drivers/uart.h index 5ca82888d4..baba42e343 100644 --- a/board/drivers/uart.h +++ b/board/drivers/uart.h @@ -1,5 +1,27 @@ // 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 ***************************** // esp = USART1 diff --git a/board/drivers/usb.h b/board/drivers/usb.h index f2cffa1416..606c8c6b86 100644 --- a/board/drivers/usb.h +++ b/board/drivers/usb.h @@ -1,5 +1,35 @@ // 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 **** typedef struct @@ -186,17 +216,10 @@ uint16_t string_manufacturer_desc[] = { 'c', 'o', 'm', 'm', 'a', '.', 'a', 'i' }; -#ifdef PANDA uint16_t string_product_desc[] = { STRING_DESCRIPTOR_HEADER(5), '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 uint16_t string_serial_desc[] = { @@ -210,7 +233,6 @@ uint16_t string_configuration_desc[] = { '0', '1' // "01" }; -#ifdef PANDA // WCID (auto install WinUSB driver) // 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 @@ -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 }; -#endif - // current packet USB_Setup_TypeDef setup; 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); break; case STRING_OFFSET_ISERIAL: - #ifdef PANDA + #ifdef UID_BASE resp[0] = 0x02 + 12*4; 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); #endif break; - #ifdef PANDA case STRING_OFFSET_ICONFIGURATION: USB_WritePacket((uint8_t*)string_configuration_desc, min(sizeof(string_configuration_desc), setup.b.wLength.w), 0); break; case 238: USB_WritePacket((uint8_t*)string_238_desc, min(sizeof(string_238_desc), setup.b.wLength.w), 0); break; - #endif default: // nothing USB_WritePacket(0, 0, 0); @@ -583,12 +601,10 @@ void usb_setup() { } USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; break; - #ifdef PANDA case USB_DESC_TYPE_BINARY_OBJECT_STORE: 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; break; - #endif default: // nothing here? USB_WritePacket(0, 0, 0); @@ -609,7 +625,6 @@ void usb_setup() { USB_WritePacket(0, 0, 0); USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; break; - #ifdef PANDA case WEBUSB_VENDOR_CODE: switch (setup.b.wIndex.w) { case WEBUSB_REQ_GET_URL: @@ -641,7 +656,6 @@ void usb_setup() { USB_WritePacket_EP0(0, 0); } break; - #endif default: resp_len = usb_cb_control_msg(&setup, resp, 1); USB_WritePacket(resp, min(resp_len, setup.b.wLength.w), 0); diff --git a/board/gpio.h b/board/gpio.h index ede6c9b3e9..7ba0dff58f 100644 --- a/board/gpio.h +++ b/board/gpio.h @@ -1,3 +1,5 @@ +// this is last place with ifdef PANDA + #ifdef STM32F4 #include "stm32f4xx_hal_gpio_ex.h" #else @@ -61,43 +63,6 @@ void detect() { // ********************* 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() { // enable GPIOB, UART2, CAN, USB clock RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; @@ -117,18 +82,16 @@ void periph_init() { RCC->APB1ENR |= RCC_APB1ENR_CAN3EN; #endif RCC->APB1ENR |= RCC_APB1ENR_DACEN; - RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; - RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; - RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; - RCC->APB1ENR |= RCC_APB1ENR_TIM5EN; - RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; + RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // main counter + RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // slow loop and pedal + RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; // gmlan_alt + //RCC->APB1ENR |= RCC_APB1ENR_TIM5EN; + //RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; RCC->APB2ENR |= RCC_APB2ENR_USART1EN; RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN; - RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; + //RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; - - // needed? 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, 13, GPIO_AF9_CAN2); #ifdef CAN3 - } else if (revision == PANDA_REV_C && can == 2) { + } else if (can == 2) { // A8,A15: disable normal mode set_gpio_mode(GPIOA, 8, 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); #ifdef CAN3 } else if (can == 2) { - if(revision == PANDA_REV_C){ - // B3,B4: disable gmlan mode - set_gpio_mode(GPIOB, 3, MODE_INPUT); - set_gpio_mode(GPIOB, 4, MODE_INPUT); - } + // B3,B4: disable gmlan mode + set_gpio_mode(GPIOB, 3, MODE_INPUT); + set_gpio_mode(GPIOB, 4, MODE_INPUT); // A8,A15: normal mode set_gpio_alternate(GPIOA, 8, GPIO_AF11_CAN3); set_gpio_alternate(GPIOA, 15, GPIO_AF11_CAN3); @@ -377,11 +338,7 @@ void gpio_init() { #ifdef PANDA // 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 - } else { - set_gpio_output(GPIOB, 4, 1); // REV AB - } + set_gpio_output(GPIOB, 7, 1); // REV C // C12,D2: K-Line setup on UART 5 set_gpio_alternate(GPIOC, 12, GPIO_AF8_UART5); @@ -392,16 +349,12 @@ void gpio_init() { set_gpio_output(GPIOA, 14, 1); // C10,C11: L-Line setup on USART 3 - // LLine now used for relay output - set_gpio_output(GPIOC, 10, 1); - //set_gpio_alternate(GPIOC, 10, GPIO_AF7_USART3); + set_gpio_alternate(GPIOC, 10, GPIO_AF7_USART3); set_gpio_alternate(GPIOC, 11, GPIO_AF7_USART3); set_gpio_pullup(GPIOC, 11, PULL_UP); #endif - if (revision == PANDA_REV_C) { - set_usb_power_mode(USB_POWER_CLIENT); - } + set_usb_power_mode(USB_POWER_CLIENT); } // ********************* early bringup ********************* diff --git a/board/main.c b/board/main.c index 4fb5e9ff04..c80a3b9bad 100644 --- a/board/main.c +++ b/board/main.c @@ -1,14 +1,15 @@ +//#define EON + #include "config.h" #include "obj/gitversion.h" // ********************* includes ********************* + #include "libc.h" -#include "safety.h" #include "provision.h" -#include "drivers/drivers.h" - +#include "drivers/llcan.h" #include "drivers/llgpio.h" #include "gpio.h" @@ -16,25 +17,13 @@ #include "drivers/adc.h" #include "drivers/usb.h" #include "drivers/gmlan_alt.h" -#include "drivers/can.h" #include "drivers/spi.h" #include "drivers/timer.h" +#include "drivers/clock.h" #include "power_saving.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; -} +#include "safety.h" +#include "drivers/can.h" // ********************* 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 ***************************** int get_health_pkt(void *dat) { @@ -85,40 +109,25 @@ int get_health_pkt(void *dat) { //Voltage will be measured in mv. 5000 = 5V 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); int safety_ignition = safety_ignition_hook(); if (safety_ignition < 0) { //Use the GPIO pin to determine ignition - health->started = (GPIOA->IDR & (1 << 1)) == 0; + health->started = is_gpio_started(); } else { //Current safety hooks want to determine ignition (ex: GM) health->started = safety_ignition; } -#else - health->current = 0; - health->started = (GPIOC->IDR & (1 << 13)) != 0; -#endif health->controls_allowed = controls_allowed; 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]); if (!ur) return; 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])); } } @@ -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; 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; // **** 0xd0: fetch serial number case 0xd0: - #ifdef PANDA - // addresses are OTP - if (setup->b.wValue.w == 1) { - memcpy(resp, (void *)0x1fff79c0, 0x10); - resp_len = 0x10; - } else { - get_provision_chunk(resp); - resp_len = PROVISION_CHUNK_LEN; - } - #endif + // addresses are OTP + if (setup->b.wValue.w == 1) { + memcpy(resp, (void *)0x1fff79c0, 0x10); + resp_len = 0x10; + } else { + get_provision_chunk(resp); + resp_len = PROVISION_CHUNK_LEN; + } break; // **** 0xd1: enter bootloader mode case 0xd1: @@ -235,10 +233,6 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) { case 0xd2: resp_len = get_health_pkt(resp); break; - // **** 0xd3: set fan speed - case 0xd3: - fan_set_speed(setup->b.wValue.w); - break; // **** 0xd6: get version case 0xd6: 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; // **** 0xdb: set GMLAN multiplexing mode case 0xdb: - #ifdef PANDA - if (setup->b.wValue.w == 1) { - // GMLAN ON - if (setup->b.wIndex.w == 1) { - can_set_gmlan(1); - } else if (setup->b.wIndex.w == 2) { - // might be ignored on rev b panda - can_set_gmlan(2); - } - } else { - can_set_gmlan(-1); + if (setup->b.wValue.w == 1) { + // GMLAN ON + if (setup->b.wIndex.w == 1) { + can_set_gmlan(1); + } else if (setup->b.wIndex.w == 2) { + can_set_gmlan(2); } - #endif + } else { + can_set_gmlan(-1); + } break; // **** 0xdc: set safety mode case 0xdc: // this is the only way to leave silent mode // and it's blocked 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); - switch (setup->b.wValue.w) { - case SAFETY_NOOUTPUT: - can_silent = ALL_CAN_SILENT; - break; - 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; + if (safety_ignition_hook() != -1) { + // if the ignition hook depends on something other than the started GPIO + // we have to disable power savings (fix for GM and Tesla) + power_save_disable(); } + #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(); } break; @@ -318,21 +311,26 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) { case 0xdd: // wValue = Can Bus Num to forward from // wIndex = Can Bus Num to forward to - if (setup->b.wValue.w < BUS_MAX && setup->b.wIndex.w < BUS_MAX && - setup->b.wValue.w != setup->b.wIndex.w) { // set forwarding + if ((setup->b.wValue.w < BUS_MAX) && (setup->b.wIndex.w < BUS_MAX) && + (setup->b.wValue.w != setup->b.wIndex.w)) { // set forwarding can_set_forwarding(setup->b.wValue.w, setup->b.wIndex.w & CAN_BUS_NUM_MASK); - } else if(setup->b.wValue.w < BUS_MAX && setup->b.wIndex.w == 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); } break; // **** 0xde: set can bitrate case 0xde: 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_init(CAN_NUM_FROM_BUS_NUM(setup->b.wValue.w)); } break; + // **** 0xdf: set long controls allowed + case 0xdf: + if (hardwired) { + long_controls_allowed = setup->b.wValue.w & 1; + } + break; // **** 0xe0: uart read case 0xe0: 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; // **** 0xe6: set USB power case 0xe6: - if (revision == PANDA_REV_C) { - if (setup->b.wValue.w == 1) { - puts("user setting CDP mode\n"); - set_usb_power_mode(USB_POWER_CDP); - } else if (setup->b.wValue.w == 2) { - puts("user setting DCP mode\n"); - set_usb_power_mode(USB_POWER_DCP); - } else { - puts("user setting CLIENT mode\n"); - set_usb_power_mode(USB_POWER_CLIENT); - } + if (setup->b.wValue.w == 1) { + puts("user setting CDP mode\n"); + set_usb_power_mode(USB_POWER_CDP); + } else if (setup->b.wValue.w == 2) { + puts("user setting DCP mode\n"); + set_usb_power_mode(USB_POWER_DCP); + } else { + puts("user setting CLIENT mode\n"); + set_usb_power_mode(USB_POWER_CLIENT); } break; // **** 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; } - // **** 0xf3: set l-line relay - case 0xf3: - { - #ifdef PANDA - if (safety_relay_hook()) { - set_lline_output(setup->b.wValue.w == 1); - } - #endif - break; - } default: puts("NO HANDLER "); 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; } -#ifdef PANDA int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) { // data[0] = endpoint // data[2] = length @@ -499,12 +484,6 @@ int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) { return resp_len; } -#else - -int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) { return 0; }; - -#endif - // ***************************** main code ***************************** @@ -514,7 +493,99 @@ void __initialize_hardware_early() { void __attribute__ ((noinline)) enable_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() { @@ -531,21 +602,19 @@ int main() { // detect the revision and init the GPIOs puts("config:\n"); - #ifdef PANDA - puts(revision == PANDA_REV_C ? " panda rev c\n" : " panda rev a or b\n"); - #else - puts(" legacy\n"); - #endif + puts((revision == PANDA_REV_C) ? " panda rev c\n" : " panda rev a or b\n"); puts(has_external_debug_serial ? " real serial\n" : " USB serial\n"); puts(is_giant_panda ? " GIANTpanda detected\n" : " not GIANTpanda\n"); puts(is_grey_panda ? " gray panda detected!\n" : " white panda\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(); -#ifdef PANDA // panda has an FPU, let's use it! enable_fpu(); -#endif // enable main uart if it's connected if (has_external_debug_serial) { @@ -554,22 +623,18 @@ int main() { uart_init(USART2, 115200); } -#ifdef PANDA if (is_grey_panda) { uart_init(USART1, 9600); } else { // enable ESP uart uart_init(USART1, 115200); - #ifdef EON - set_esp_mode(ESP_DISABLED); - #endif } + // enable LIN uart_init(UART5, 10400); UART5->CR2 |= USART_CR2_LINEN; uart_init(USART3, 10400); USART3->CR2 |= USART_CR2_LINEN; -#endif // init microsecond system timer // increments 1000000 times per second @@ -585,136 +650,65 @@ int main() { // 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 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; +#endif can_init_all(); adc_init(); - -#ifdef PANDA 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 + + // 48mhz / 65536 ~= 732 / 732 = 1 + timer_init(TIM3, 732); + NVIC_EnableIRQ(TIM3_IRQn); + #ifdef DEBUG puts("DEBUG ENABLED\n"); #endif - // set PWM - fan_init(); - fan_set_speed(0); - puts("**** INTERRUPTS ON ****\n"); __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 uint64_t cnt = 0; - #ifdef PANDA - uint64_t marker = 0; - #define CURRENT_THRESHOLD 0xF00 - #define CLICKS 8 - #endif - for (cnt=0;;cnt++) { - can_live = pending_can_live; - - //puth(usart1_dma); puts(" "); puth(DMA2_Stream5->M0AR); puts(" "); puth(DMA2_Stream5->NDTR); puts("\n"); - - #ifdef PANDA - uint32_t current = adc_get(ADCCHAN_CURRENT); - - switch (usb_power_mode) { - case USB_POWER_CLIENT: - if ((cnt-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 = 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; + if (power_save_status == POWER_SAVE_STATUS_DISABLED) { + int div_mode = ((usb_power_mode == USB_POWER_DCP) ? 4 : 1); + + // useful for debugging, fade breaks = panda is overloaded + for (int div_mode_loop = 0; div_mode_loop < div_mode; div_mode_loop++) { + for (int fade = 0; fade < 1024; fade += 8) { + for (int i = 0; i < (128/div_mode); i++) { + set_led(LED_RED, 1); + if (fade < 512) { delay(fade); } else { delay(1024-fade); } + set_led(LED_RED, 0); + if (fade < 512) { delay(512-fade); } else { delay(fade-512); } } - 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; } + diff --git a/board/pedal/main.c b/board/pedal/main.c index 6b55ca780c..df3219e32c 100644 --- a/board/pedal/main.c +++ b/board/pedal/main.c @@ -1,29 +1,26 @@ -//#define DEBUG -//#define CAN_LOOPBACK_MODE -//#define USE_INTERNAL_OSC - #include "../config.h" -#include "drivers/drivers.h" +#include "drivers/llcan.h" #include "drivers/llgpio.h" -#include "gpio.h" - -#define CUSTOM_CAN_INTERRUPTS - -#include "libc.h" -#include "safety.h" +#include "drivers/clock.h" #include "drivers/adc.h" -#include "drivers/uart.h" #include "drivers/dac.h" -#include "drivers/can.h" #include "drivers/timer.h" +#include "gpio.h" +#include "libc.h" + #define CAN CAN1 //#define PEDAL_USB #ifdef PEDAL_USB + #include "drivers/uart.h" #include "drivers/usb.h" +#else + // no serial either + int puts(const char *a) { return 0; } + void puth(unsigned int i) {} #endif #define ENTER_BOOTLOADER_MAGIC 0xdeadbeef @@ -35,6 +32,8 @@ void __initialize_hardware_early() { // ********************* serial debugging ********************* +#ifdef PEDAL_USB + void debug_ring_callback(uart_ring *ring) { char 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; } void usb_cb_ep2_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() { state = FAULT_SCE; - can_sce(CAN); + llcan_clear_send(CAN); } int pdl0 = 0, pdl1 = 0; @@ -256,8 +253,7 @@ void pedal() { dac_set(1, pdl1); } - // feed the watchdog - IWDG->KR = 0xAAAA; + watchdog_feed(); } int main() { @@ -278,24 +274,18 @@ int main() { adc_init(); // init can - can_silent = ALL_CAN_LIVE; - can_init(0); + llcan_set_speed(CAN1, 5000, false, false); + llcan_init(CAN1); // 48mhz / 65536 ~= 732 timer_init(TIM3, 15); NVIC_EnableIRQ(TIM3_IRQn); - // 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; + watchdog_init(); puts("**** INTERRUPTS ON ****\n"); __enable_irq(); - // main pedal loop while (1) { pedal(); diff --git a/board/power_saving.h b/board/power_saving.h index c6f83457ff..3f40bce28f 100644 --- a/board/power_saving.h +++ b/board/power_saving.h @@ -1,157 +1,57 @@ #define POWER_SAVE_STATUS_DISABLED 0 -//Moving to enabled, but can wakeup not yet enabled -#define POWER_SAVE_STATUS_SWITCHING 1 -#define POWER_SAVE_STATUS_ENABLED 2 +#define POWER_SAVE_STATUS_ENABLED 1 -volatile int power_save_status = POWER_SAVE_STATUS_DISABLED; +int power_save_status = POWER_SAVE_STATUS_DISABLED; void power_save_enable(void) { - power_save_status = POWER_SAVE_STATUS_SWITCHING; - puts("Saving power\n"); - //Turn off can transciever + if (power_save_status == POWER_SAVE_STATUS_ENABLED) return; + puts("enable power savings\n"); + + // turn off can set_can_enable(CAN1, 0); set_can_enable(CAN2, 0); -#ifdef PANDA set_can_enable(CAN3, 0); -#endif - //Turn off GMLAN + // turn off GMLAN set_gpio_output(GPIOB, 14, 0); set_gpio_output(GPIOB, 15, 0); -#ifdef PANDA - //Turn off LIN K - if (revision == PANDA_REV_C) { - set_gpio_output(GPIOB, 7, 0); // REV C - } else { - set_gpio_output(GPIOB, 4, 0); // REV AB - } - // LIN L + // turn off LIN + set_gpio_output(GPIOB, 7, 0); set_gpio_output(GPIOA, 14, 0); -#endif if (is_grey_panda) { - char* UBLOX_SLEEP_MSG = "\xb5\x62\x06\x04\x04\x00\x01\x00\x08\x00\x17\x78"; - int len = 12; + char UBLOX_SLEEP_MSG[] = "\xb5\x62\x06\x04\x04\x00\x01\x00\x08\x00\x17\x78"; 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; - 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) { - power_save_status = POWER_SAVE_STATUS_DISABLED; - puts("not Saving power\n"); - TIM6->CR1 |= TIM_CR1_CEN; //Restart timer - TIM6->CNT = 0; + if (power_save_status == POWER_SAVE_STATUS_DISABLED) return; + puts("disable power savings\n"); - //Turn on can + // turn on can set_can_enable(CAN1, 1); set_can_enable(CAN2, 1); - -#ifdef PANDA set_can_enable(CAN3, 1); -#endif - //Turn on GMLAN + // turn on GMLAN set_gpio_output(GPIOB, 14, 1); set_gpio_output(GPIOB, 15, 1); -#ifdef PANDA - //Turn on LIN K - if (revision == PANDA_REV_C) { - set_gpio_output(GPIOB, 7, 1); // REV C - } else { - set_gpio_output(GPIOB, 4, 1); // REV AB - } - // LIN L + // turn on LIN + set_gpio_output(GPIOB, 7, 1); set_gpio_output(GPIOA, 14, 1); -#endif if (is_grey_panda) { - char* UBLOX_WAKE_MSG = "\xb5\x62\x06\x04\x04\x00\x01\x00\x09\x00\x18\x7a"; - int len = 12; + char UBLOX_WAKE_MSG[] = "\xb5\x62\x06\x04\x04\x00\x01\x00\x09\x00\x18\x7a"; uart_ring *ur = get_ring_by_number(1); - for (int i = 0; i < len; 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(); + for (int i = 0; i < sizeof(UBLOX_WAKE_MSG)-1; i++) while (!putc(ur, UBLOX_WAKE_MSG[i])); } -} -void power_save_init(void) { - 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; + power_save_status = POWER_SAVE_STATUS_DISABLED; } -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; - } -} diff --git a/board/safety.h b/board/safety.h index 5543333e3a..3addc65365 100644 --- a/board/safety.h +++ b/board/safety.h @@ -5,13 +5,11 @@ struct sample_t { int max; } sample_t_default = {{0}, 0, 0}; -// no float support in STM32F2 micros (cortex-m3) -#ifdef PANDA +// safety code requires floats struct lookup_t { float x[3]; float y[3]; }; -#endif void safety_rx_hook(CAN_FIFOMailBox_TypeDef *to_push); 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_ALLOWANCE, const int DRIVER_FACTOR); 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); -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 (*rx_hook)(CAN_FIFOMailBox_TypeDef *to_push); typedef int (*tx_hook)(CAN_FIFOMailBox_TypeDef *to_send); typedef int (*tx_lin_hook)(int lin_num, uint8_t *data, int len); typedef int (*ign_hook)(); typedef int (*fwd_hook)(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd); -typedef int (*relay_hook)(); typedef struct { safety_hook_init init; @@ -50,21 +41,23 @@ typedef struct { tx_hook tx; tx_lin_hook tx_lin; fwd_hook fwd; - relay_hook relay; } safety_hooks; // This can be set by the safety hooks. 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 "safety/safety_defaults.h" #include "safety/safety_honda.h" #include "safety/safety_toyota.h" -#ifdef PANDA #include "safety/safety_toyota_ipas.h" #include "safety/safety_tesla.h" #include "safety/safety_gm_ascm.h" -#endif #include "safety/safety_gm.h" #include "safety/safety_ford.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); } -int safety_relay_hook(void) { - return current_hooks->relay(); -} - typedef struct { uint16_t id; const safety_hooks *hooks; @@ -119,7 +108,6 @@ typedef struct { #define SAFETY_SUBARU 10 #define SAFETY_GM_ASCM 0x1334 #define SAFETY_TOYOTA_IPAS 0x1335 -#define SAFETY_TOYOTA_NOLIMITS 0x1336 #define SAFETY_ALLOUTPUT 0x1337 #define SAFETY_ELM327 0xE327 @@ -134,12 +122,9 @@ const safety_hook_config safety_hook_registry[] = { {SAFETY_HYUNDAI, &hyundai_hooks}, {SAFETY_CHRYSLER, &chrysler_hooks}, {SAFETY_SUBARU, &subaru_hooks}, - {SAFETY_TOYOTA_NOLIMITS, &toyota_nolimits_hooks}, -#ifdef PANDA {SAFETY_TOYOTA_IPAS, &toyota_ipas_hooks}, {SAFETY_GM_ASCM, &gm_ascm_hooks}, {SAFETY_TESLA, &tesla_hooks}, -#endif {SAFETY_ALLOUTPUT, &alloutput_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 float interpolate(struct lookup_t xy, float x) { 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]; } } -#endif diff --git a/board/safety/safety_cadillac.h b/board/safety/safety_cadillac.h index 0e6636a1a0..2a2d8b9857 100644 --- a/board/safety/safety_cadillac.h +++ b/board/safety/safety_cadillac.h @@ -115,9 +115,6 @@ static int cadillac_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { static void cadillac_init(int16_t param) { controls_allowed = 0; cadillac_ign = 0; - #ifdef PANDA - lline_relay_release(); - #endif } static int cadillac_ign_hook() { @@ -131,5 +128,4 @@ const safety_hooks cadillac_hooks = { .tx_lin = nooutput_tx_lin_hook, .ignition = cadillac_ign_hook, .fwd = alloutput_fwd_hook, - .relay = nooutput_relay_hook, }; diff --git a/board/safety/safety_chrysler.h b/board/safety/safety_chrysler.h index a8826b9154..4af588401e 100644 --- a/board/safety/safety_chrysler.h +++ b/board/safety/safety_chrysler.h @@ -127,9 +127,6 @@ static int chrysler_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { static void chrysler_init(int16_t param) { chrysler_camera_detected = 0; - #ifdef PANDA - lline_relay_release(); - #endif } 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, .ignition = default_ign_hook, .fwd = chrysler_fwd_hook, - .relay = nooutput_relay_hook, }; diff --git a/board/safety/safety_defaults.h b/board/safety/safety_defaults.h index 88d31a7de5..196df65d2f 100644 --- a/board/safety/safety_defaults.h +++ b/board/safety/safety_defaults.h @@ -8,9 +8,6 @@ int default_ign_hook() { static void nooutput_init(int16_t param) { controls_allowed = 0; - #ifdef PANDA - lline_relay_release(); - #endif } 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; } -static int nooutput_relay_hook(int to_set) { - return false; -} - const safety_hooks nooutput_hooks = { .init = nooutput_init, .rx = default_rx_hook, @@ -36,16 +29,12 @@ const safety_hooks nooutput_hooks = { .tx_lin = nooutput_tx_lin_hook, .ignition = default_ign_hook, .fwd = nooutput_fwd_hook, - .relay = nooutput_relay_hook, }; // *** all output safety mode *** static void alloutput_init(int16_t param) { controls_allowed = 1; - #ifdef PANDA - lline_relay_release(); - #endif } 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; } -static int alloutput_relay_hook(int to_set) { - return true; -} - const safety_hooks alloutput_hooks = { .init = alloutput_init, .rx = default_rx_hook, @@ -71,5 +56,4 @@ const safety_hooks alloutput_hooks = { .tx_lin = alloutput_tx_lin_hook, .ignition = default_ign_hook, .fwd = alloutput_fwd_hook, - .relay = alloutput_relay_hook, }; diff --git a/board/safety/safety_elm327.h b/board/safety/safety_elm327.h index e89783bcca..823d553dd7 100644 --- a/board/safety/safety_elm327.h +++ b/board/safety/safety_elm327.h @@ -1,5 +1,3 @@ -static void elm327_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {} - static int elm327_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { //All ELM traffic must appear on CAN0 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; } -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 = { - .init = elm327_init, - .rx = elm327_rx_hook, + .init = nooutput_init, + .rx = default_rx_hook, .tx = elm327_tx_hook, .tx_lin = elm327_tx_lin_hook, .ignition = default_ign_hook, - .fwd = elm327_fwd_hook, - .relay = nooutput_relay_hook, + .fwd = nooutput_fwd_hook, }; diff --git a/board/safety/safety_ford.h b/board/safety/safety_ford.h index 1d3f16d069..075029fb62 100644 --- a/board/safety/safety_ford.h +++ b/board/safety/safety_ford.h @@ -90,5 +90,4 @@ const safety_hooks ford_hooks = { .tx_lin = nooutput_tx_lin_hook, .ignition = default_ign_hook, .fwd = nooutput_fwd_hook, - .relay = nooutput_relay_hook, }; diff --git a/board/safety/safety_gm.h b/board/safety/safety_gm.h index 396fb8770c..996161127b 100644 --- a/board/safety/safety_gm.h +++ b/board/safety/safety_gm.h @@ -101,7 +101,7 @@ static void gm_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { // exit controls on rising edge of gas press if (addr == 417) { int gas = to_push->RDHR & 0xFF0000; - if (gas && !gm_gas_prev) { + if (gas && !gm_gas_prev && long_controls_allowed) { controls_allowed = 0; } gm_gas_prev = gas; @@ -148,7 +148,7 @@ static int gm_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int rdlr = to_send->RDLR; int brake = ((rdlr & 0xF) << 8) + ((rdlr & 0xFF00) >> 8); brake = (0x1000 - brake) & 0xFFF; - if (current_controls_allowed) { + if (current_controls_allowed && long_controls_allowed) { if (brake > GM_MAX_BRAKE) return 0; } else { 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 gas_regen = ((rdlr & 0x7F0000) >> 11) + ((rdlr & 0xF8000000) >> 27); int apply = rdlr & 1; - if (current_controls_allowed) { + if (current_controls_allowed && long_controls_allowed) { if (gas_regen > GM_MAX_GAS) return 0; } else { // 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) { controls_allowed = 0; gm_ignition_started = 0; - #ifdef PANDA - lline_relay_release(); - #endif } static int gm_ign_hook() { @@ -244,5 +241,4 @@ const safety_hooks gm_hooks = { .tx_lin = nooutput_tx_lin_hook, .ignition = gm_ign_hook, .fwd = nooutput_fwd_hook, - .relay = nooutput_relay_hook, }; diff --git a/board/safety/safety_gm_ascm.h b/board/safety/safety_gm_ascm.h index b145466d9d..70a042ec51 100644 --- a/board/safety/safety_gm_ascm.h +++ b/board/safety/safety_gm_ascm.h @@ -48,6 +48,5 @@ const safety_hooks gm_ascm_hooks = { .tx_lin = nooutput_tx_lin_hook, .ignition = default_ign_hook, .fwd = gm_ascm_fwd_hook, - .relay = nooutput_relay_hook, }; diff --git a/board/safety/safety_honda.h b/board/safety/safety_honda.h index 40c6917b0b..3aeeefe835 100644 --- a/board/safety/safety_honda.h +++ b/board/safety/safety_honda.h @@ -7,15 +7,11 @@ // brake rising edge // brake > 0mph -// these are set in the Honda safety hooks...this is the wrong place -const int gas_interceptor_threshold = 328; -int gas_interceptor_detected = 0; -int brake_prev = 0; -int gas_prev = 0; -int gas_interceptor_prev = 0; -int ego_speed = 0; -// TODO: auto-detect bosch hardware based on CAN messages? -bool bosch_hardware = false; +const int HONDA_GAS_INTERCEPTOR_THRESHOLD = 328; // ratio between offset and gain from dbc file +int honda_brake_prev = 0; +int honda_gas_prev = 0; +int honda_ego_speed = 0; +bool honda_bosch_hardware = false; bool honda_alt_brake_msg = false; 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 if ((to_push->RIR>>21) == 0x158) { // first 2 bytes - ego_speed = to_push->RDLR & 0xFFFF; + honda_ego_speed = to_push->RDLR & 0xFFFF; } // state machine to enter and exit controls @@ -49,10 +45,10 @@ static void honda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { // speed > 0 if (IS_USER_BRAKE_MSG(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; } - brake_prev = brake; + honda_brake_prev = brake; } // 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) { gas_interceptor_detected = 1; int gas_interceptor = ((to_push->RDLR & 0xFF) << 8) | ((to_push->RDLR & 0xFF00) >> 8); - if ((gas_interceptor > gas_interceptor_threshold) && - (gas_interceptor_prev <= gas_interceptor_threshold)) { + if ((gas_interceptor > HONDA_GAS_INTERCEPTOR_THRESHOLD) && + (gas_interceptor_prev <= HONDA_GAS_INTERCEPTOR_THRESHOLD) && + long_controls_allowed) { controls_allowed = 0; } gas_interceptor_prev = gas_interceptor; @@ -71,10 +68,10 @@ static void honda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { if (!gas_interceptor_detected) { if ((to_push->RIR>>21) == 0x17C) { int gas = to_push->RDLR & 0xFF; - if (gas && !(gas_prev)) { + if (gas && !(honda_gas_prev) && long_controls_allowed) { 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 // and the the latching controls_allowed flag is True - int pedal_pressed = gas_prev || (gas_interceptor_prev > gas_interceptor_threshold) || - (brake_prev && ego_speed); + int pedal_pressed = honda_gas_prev || (gas_interceptor_prev > HONDA_GAS_INTERCEPTOR_THRESHOLD) || + (honda_brake_prev && honda_ego_speed); int current_controls_allowed = controls_allowed && !(pedal_pressed); // BRAKE: safety check 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; } else { 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 if ((to_send->RIR>>21) == 0x200) { - if (current_controls_allowed) { + if (current_controls_allowed && long_controls_allowed) { // all messages are fine here } else { 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 // ensuring that only the cancel button press is sent (VAL 2) when controls are off. // 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) { 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) { controls_allowed = 0; - bosch_hardware = false; + honda_bosch_hardware = false; honda_alt_brake_msg = false; - #ifdef PANDA - lline_relay_release(); - #endif } static void honda_bosch_init(int16_t param) { controls_allowed = 0; - bosch_hardware = true; + honda_bosch_hardware = true; // Checking for alternate brake override from safety parameter 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) { @@ -159,11 +150,15 @@ static int honda_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { int addr = to_fwd->RIR>>21; if (bus_num == 0) { return 2; - } else if (bus_num == 2 && addr != 0xE4 && addr != 0x194 && addr != 0x1FA && - addr != 0x30C && addr != 0x33D && addr != 0x39F) { + } else if (bus_num == 2) { + // 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 -1; } @@ -182,7 +177,6 @@ const safety_hooks honda_hooks = { .tx_lin = nooutput_tx_lin_hook, .ignition = default_ign_hook, .fwd = honda_fwd_hook, - .relay = nooutput_relay_hook, }; const safety_hooks honda_bosch_hooks = { @@ -192,5 +186,4 @@ const safety_hooks honda_bosch_hooks = { .tx_lin = nooutput_tx_lin_hook, .ignition = default_ign_hook, .fwd = honda_bosch_fwd_hook, - .relay = nooutput_relay_hook, }; diff --git a/board/safety/safety_hyundai.h b/board/safety/safety_hyundai.h index 9470e34d15..b67632141d 100644 --- a/board/safety/safety_hyundai.h +++ b/board/safety/safety_hyundai.h @@ -152,9 +152,6 @@ static int hyundai_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { static void hyundai_init(int16_t param) { controls_allowed = 0; hyundai_giraffe_switch_2 = 0; - #ifdef PANDA - lline_relay_release(); - #endif } const safety_hooks hyundai_hooks = { @@ -164,5 +161,4 @@ const safety_hooks hyundai_hooks = { .tx_lin = nooutput_tx_lin_hook, .ignition = default_ign_hook, .fwd = hyundai_fwd_hook, - .relay = nooutput_relay_hook, }; diff --git a/board/safety/safety_subaru.h b/board/safety/safety_subaru.h index 5d2bd23d24..e64c777195 100644 --- a/board/safety/safety_subaru.h +++ b/board/safety/safety_subaru.h @@ -15,9 +15,6 @@ uint32_t subaru_ts_last = 0; struct sample_t subaru_torque_driver; // last few driver torques measured static void subaru_init(int16_t param) { - #ifdef PANDA - lline_relay_init(); - #endif } 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, .ignition = default_ign_hook, .fwd = subaru_fwd_hook, - .relay = alloutput_relay_hook, }; diff --git a/board/safety/safety_tesla.h b/board/safety/safety_tesla.h index 882a509f56..430a42ce94 100644 --- a/board/safety/safety_tesla.h +++ b/board/safety/safety_tesla.h @@ -219,20 +219,11 @@ static int tesla_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) 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) { controls_allowed = 0; tesla_ignition_started = 0; gmlan_switch_init(1); //init the gmlan switch with 1s timeout enabled - #ifdef PANDA - lline_relay_release(); - #endif } 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 = { - .init = tesla_init, - .rx = tesla_rx_hook, - .tx = tesla_tx_hook, - .tx_lin = tesla_tx_lin_hook, - .ignition = tesla_ign_hook, - .fwd = tesla_fwd_hook, - .relay = nooutput_relay_hook, + .init = tesla_init, + .rx = tesla_rx_hook, + .tx = tesla_tx_hook, + .tx_lin = nooutput_tx_lin_hook, + .ignition = tesla_ign_hook, + .fwd = tesla_fwd_hook, }; diff --git a/board/safety/safety_toyota.h b/board/safety/safety_toyota.h index cbc8386087..2c9e062f79 100644 --- a/board/safety/safety_toyota.h +++ b/board/safety/safety_toyota.h @@ -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 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_MIN_ACCEL = -3000; // 3.0 m/s2 -// global actuation limit state -int toyota_actuation_limits = 1; // by default steer limits are imposed +const int TOYOTA_GAS_INTERCEPTOR_THRESHOLD = 475; // ratio between offset and gain from dbc file + +// global actuation limit states 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_rt_torque_last = 0; // last desired torque for real time check uint32_t toyota_ts_last = 0; 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 @@ -40,23 +41,40 @@ static void toyota_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { // scale by dbc_factor 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_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 if ((to_push->RIR>>21) == 0x1D2) { // 5th bit is CRUISE_ACTIVE int cruise_engaged = to_push->RDLR & 0x20; - if (cruise_engaged && !toyota_cruise_engaged_last) { - controls_allowed = 1; - } else if (!cruise_engaged) { + // 4th bit is GAS_RELEASED + int gas = !(to_push->RDLR & 0x10); + if (!cruise_engaged || + (gas && !toyota_gas_prev && !gas_interceptor_detected && long_controls_allowed)) { controls_allowed = 0; + } else if (cruise_engaged && !toyota_cruise_engaged_last) { + controls_allowed = 1; } 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; @@ -81,7 +99,7 @@ static int toyota_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { // GAS PEDAL: safety check if ((to_send->RIR>>21) == 0x200) { - if (controls_allowed && toyota_actuation_limits) { + if (controls_allowed && long_controls_allowed) { // all messages are fine here } else { 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) { int desired_accel = ((to_send->RDLR & 0xFF) << 8) | ((to_send->RDLR >> 8) & 0xFF); 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); if (violation) return 0; - } else if (!controls_allowed && (desired_accel != 0)) { + } else if (desired_accel != 0) { return 0; } } @@ -108,8 +126,7 @@ static int toyota_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { uint32_t ts = TIM2->CNT; - // only check if controls are allowed and actuation_limits are imposed - if (controls_allowed && toyota_actuation_limits) { + if (controls_allowed) { // *** global torque limit check *** 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) { controls_allowed = 0; - toyota_actuation_limits = 1; toyota_giraffe_switch_1 = 0; toyota_camera_forwarded = 0; 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) { - // forward cam to radar and viceversa if car, except lkas cmd and hud - // don't forward when switch 1 is high - if ((bus_num == 0 || bus_num == 2) && toyota_camera_forwarded && !toyota_giraffe_switch_1) { + if (toyota_camera_forwarded && !toyota_giraffe_switch_1) { int addr = to_fwd->RIR>>21; - bool is_lkas_msg = (addr == 0x2E4 || addr == 0x412) && bus_num == 2; - // in TSSP 2.0 the camera does ACC as well, so filter 0x343 - bool is_acc_msg = (addr == 0x343 && bus_num == 2); - return (is_lkas_msg || is_acc_msg)? -1 : (uint8_t)(~bus_num & 0x2); + if (bus_num == 0) { + return 2; + } else if (bus_num == 2) { + // 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; } @@ -186,26 +205,4 @@ const safety_hooks toyota_hooks = { .tx_lin = nooutput_tx_lin_hook, .ignition = default_ign_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, }; diff --git a/board/safety/safety_toyota_ipas.h b/board/safety/safety_toyota_ipas.h index 13e664c0f9..2f0b42f649 100644 --- a/board/safety/safety_toyota_ipas.h +++ b/board/safety/safety_toyota_ipas.h @@ -152,5 +152,4 @@ const safety_hooks toyota_ipas_hooks = { .tx_lin = nooutput_tx_lin_hook, .ignition = default_ign_hook, .fwd = toyota_fwd_hook, - .relay = nooutput_relay_hook, }; diff --git a/board/spi_flasher.h b/board/spi_flasher.h index 179a095b97..48e00aa229 100644 --- a/board/spi_flasher.h +++ b/board/spi_flasher.h @@ -2,7 +2,9 @@ uint32_t *prog_ptr = NULL; int unlocked = 0; +#ifdef uart_ring void debug_ring_callback(uart_ring *ring) {} +#endif int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) { int resp_len = 0; @@ -46,7 +48,7 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) { break; // **** 0xd0: fetch serial number case 0xd0: - #ifdef PANDA + #ifdef STM32F4 // addresses are OTP if (setup->b.wValue.w == 1) { memcpy(resp, (void *)0x1fff79c0, 0x10); @@ -132,6 +134,7 @@ int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) { #ifdef PEDAL +#include "drivers/llcan.h" #define CAN CAN1 #define CAN_BL_INPUT 0x1 @@ -239,7 +242,7 @@ void CAN1_RX0_IRQHandler() { } void CAN1_SCE_IRQHandler() { - can_sce(CAN); + llcan_clear_send(CAN); } #endif @@ -264,8 +267,8 @@ void soft_flasher_start() { set_can_enable(CAN1, 1); // init can - can_silent = ALL_CAN_LIVE; - can_init(0); + llcan_set_speed(CAN1, 5000, false, false); + llcan_init(CAN1); #endif // A4,A5,A6,A7: setup SPI diff --git a/buy.png b/buy.png index 72c705742251735c5bec921906b15c7f1303b12a..a4a9e0fd40a4268a6b88b068bd6cdc7dd095ab01 100644 GIT binary patch literal 12200 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 C>W0Js literal 4264 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/tmp/misra/output.txt || true diff --git a/tests/safety/libpandasafety_py.py b/tests/safety/libpandasafety_py.py index d8cb27cf8c..84f3b00d05 100644 --- a/tests/safety/libpandasafety_py.py +++ b/tests/safety/libpandasafety_py.py @@ -32,6 +32,11 @@ typedef struct void set_controls_allowed(int c); 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 reset_angle_control(void); @@ -41,19 +46,20 @@ int toyota_tx_hook(CAN_FIFOMailBox_TypeDef *to_send); void toyota_init(int16_t param); int get_toyota_torque_meas_min(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_desired_torque_last(int t); void set_toyota_rt_torque_last(int t); void init_tests_honda(void); -int get_ego_speed(void); +int get_honda_ego_speed(void); void honda_init(int16_t param); void honda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push); int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send); -int get_brake_prev(void); -int get_gas_prev(void); +int get_honda_brake_prev(void); +int get_honda_gas_prev(void); void set_honda_alt_brake_msg(bool); -void set_bosch_hardware(bool); +void set_honda_bosch_hardware(bool); void init_tests_cadillac(void); void cadillac_init(int16_t param); diff --git a/tests/safety/test.c b/tests/safety/test.c index 04e6576fb8..ce75df82a5 100644 --- a/tests/safety/test.c +++ b/tests/safety/test.c @@ -51,6 +51,14 @@ void set_controls_allowed(int 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){ angle_control = 0; } @@ -59,6 +67,18 @@ int get_controls_allowed(void){ 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){ timer.CNT = t; } @@ -101,6 +121,10 @@ int get_chrysler_torque_meas_max(void){ return chrysler_torque_meas.max; } +int get_toyota_gas_prev(void){ + return toyota_gas_prev; +} + int get_toyota_torque_meas_min(void){ return toyota_torque_meas.min; } @@ -157,24 +181,24 @@ void set_subaru_desired_torque_last(int t){ subaru_desired_torque_last = t; } -int get_ego_speed(void){ - return ego_speed; +int get_honda_ego_speed(void){ + return honda_ego_speed; } -int get_brake_prev(void){ - return brake_prev; +int get_honda_brake_prev(void){ + return honda_brake_prev; } -int get_gas_prev(void){ - return gas_prev; +int get_honda_gas_prev(void){ + return honda_gas_prev; } void set_honda_alt_brake_msg(bool c){ honda_alt_brake_msg = c; } -void set_bosch_hardware(bool c){ - bosch_hardware = c; +void set_honda_bosch_hardware(bool c){ + honda_bosch_hardware = c; } void init_tests_toyota(void){ @@ -232,10 +256,9 @@ void init_tests_subaru(void){ } void init_tests_honda(void){ - ego_speed = 0; - gas_interceptor_detected = 0; - brake_prev = 0; - gas_prev = 0; + honda_ego_speed = 0; + honda_brake_prev = 0; + honda_gas_prev = 0; } 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 lline_relay_init (void) { -} - -void lline_relay_release (void) { -} - -void set_lline_output(int to_set) { -} diff --git a/tests/safety/test_gm.py b/tests/safety/test_gm.py index 299de5a7e9..ecdf40fedd 100644 --- a/tests/safety/test_gm.py +++ b/tests/safety/test_gm.py @@ -138,10 +138,15 @@ class TestGmSafety(unittest.TestCase): self.safety.gm_rx_hook(self._brake_msg(False)) def test_disengage_on_gas(self): - self.safety.set_controls_allowed(1) - self.safety.gm_rx_hook(self._gas_msg(True)) - self.assertFalse(self.safety.get_controls_allowed()) - self.safety.gm_rx_hook(self._gas_msg(False)) + for long_controls_allowed in [0, 1]: + self.safety.set_long_controls_allowed(long_controls_allowed) + self.safety.set_controls_allowed(1) + 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): 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)) def test_brake_safety_check(self): - for enabled in [0, 1]: - for b in range(0, 500): - self.safety.set_controls_allowed(enabled) - if abs(b) > MAX_BRAKE or (not enabled and b != 0): - 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))) + for long_controls_allowed in [0, 1]: + self.safety.set_long_controls_allowed(long_controls_allowed) + for enabled in [0, 1]: + for b in range(0, 500): + self.safety.set_controls_allowed(enabled) + if abs(b) > MAX_BRAKE or ((not enabled or not long_controls_allowed) and b != 0): + 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): - for enabled in [0, 1]: - for g in range(0, 2**12-1): - self.safety.set_controls_allowed(enabled) - if abs(g) > MAX_GAS or (not enabled and g != MAX_REGEN): - 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))) + for long_controls_allowed in [0, 1]: + self.safety.set_long_controls_allowed(long_controls_allowed) + for enabled in [0, 1]: + for g in range(0, 2**12-1): + self.safety.set_controls_allowed(enabled) + if abs(g) > MAX_GAS or ((not enabled or not long_controls_allowed) and g != MAX_REGEN): + 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): for enabled in [0, 1]: diff --git a/tests/safety/test_honda.py b/tests/safety/test_honda.py index 48b678eaae..4e131f2fc0 100755 --- a/tests/safety/test_honda.py +++ b/tests/safety/test_honda.py @@ -3,6 +3,7 @@ import unittest import numpy as np import libpandasafety_py +MAX_BRAKE = 255 class TestHondaSafety(unittest.TestCase): @classmethod @@ -49,14 +50,15 @@ class TestHondaSafety(unittest.TestCase): def _send_brake_msg(self, brake): to_send = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *') to_send[0].RIR = 0x1FA << 21 - to_send[0].RDLR = brake + to_send[0].RDLR = ((brake & 0x3) << 8) | ((brake & 0x3FF) >> 2) 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[0].RIR = 0x200 << 21 - to_send[0].RDLR = gas + to_send[0].RIR = addr << 21 + to_send[0].RDTR = 6 + to_send[0].RDLR = ((gas & 0xff) << 8) | ((gas & 0xff00) >> 8) return to_send @@ -89,14 +91,14 @@ class TestHondaSafety(unittest.TestCase): self.assertFalse(self.safety.get_controls_allowed()) 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.assertEqual(100, self.safety.get_ego_speed()) + self.assertEqual(100, self.safety.get_honda_ego_speed()) 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.assertTrue(self.safety.get_brake_prev()) + self.assertTrue(self.safety.get_honda_brake_prev()) def test_disengage_on_brake(self): self.safety.set_controls_allowed(1) @@ -133,14 +135,30 @@ class TestHondaSafety(unittest.TestCase): self.assertFalse(self.safety.get_controls_allowed()) 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.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): - self.safety.set_controls_allowed(1) - self.safety.honda_rx_hook(self._gas_msg(1)) - self.assertFalse(self.safety.get_controls_allowed()) + for long_controls_allowed in [0, 1]: + self.safety.set_long_controls_allowed(long_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): 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.assertTrue(self.safety.get_controls_allowed()) - def test_brake_safety_check(self): - self.assertTrue(self.safety.honda_tx_hook(self._send_brake_msg(0x0000))) - self.assertFalse(self.safety.honda_tx_hook(self._send_brake_msg(0x1000))) - + 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.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.assertTrue(self.safety.honda_tx_hook(self._send_brake_msg(0x1000))) - self.assertFalse(self.safety.honda_tx_hook(self._send_brake_msg(0x00F0))) + self.safety.honda_rx_hook(self._send_interceptor_msg(0x1000, 0x201)) + 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): - self.safety.set_controls_allowed(0) - self.assertTrue(self.safety.honda_tx_hook(self._send_gas_msg(0x0000))) - self.assertFalse(self.safety.honda_tx_hook(self._send_gas_msg(0x1000))) + def test_brake_safety_check(self): + for long_controls_allowed in [0, 1]: + self.safety.set_long_controls_allowed(long_controls_allowed) + 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): self.safety.set_controls_allowed(0) @@ -171,7 +224,7 @@ class TestHondaSafety(unittest.TestCase): SET_BTN = 3 CANCEL_BTN = 2 BUTTON_MSG = 0x296 - self.safety.set_bosch_hardware(1) + self.safety.set_honda_bosch_hardware(1) self.safety.set_controls_allowed(0) 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))) diff --git a/tests/safety/test_toyota.py b/tests/safety/test_toyota.py index 52c7015af3..9badaec0f6 100644 --- a/tests/safety/test_toyota.py +++ b/tests/safety/test_toyota.py @@ -119,13 +119,28 @@ class TestToyotaSafety(unittest.TestCase): to_send[0].RDLR = (a & 0xFF) << 8 | (a >> 8) 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[0].RIR = 0x200 << 21 to_send[0].RDLR = gas 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): self.assertFalse(self.safety.get_controls_allowed()) @@ -134,32 +149,84 @@ class TestToyotaSafety(unittest.TestCase): self.assertTrue(self.safety.get_controls_allowed()) def test_enable_control_allowed_from_cruise(self): - to_push = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *') - to_push[0].RIR = 0x1D2 << 21 - to_push[0].RDLR = 0x20 - - 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.safety.toyota_rx_hook(self._pcm_cruise_msg(True, False)) self.assertTrue(self.safety.get_controls_allowed()) 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.toyota_rx_hook(to_push) + self.safety.toyota_rx_hook(self._pcm_cruise_msg(False, False)) self.assertFalse(self.safety.get_controls_allowed()) - def test_accel_actuation_limits(self): - 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) + def test_prev_gas(self): + self.safety.toyota_rx_hook(self._pcm_cruise_msg(False, False)) + self.assertFalse(self.safety.get_toyota_gas_prev()) + 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: - send = MIN_ACCEL <= accel <= MAX_ACCEL - else: - send = accel == 0 - self.assertEqual(send, self.safety.toyota_tx_hook(self._accel_msg(accel))) + def test_allow_engage_with_gas_pressed(self): + self.safety.toyota_rx_hook(self._pcm_cruise_msg(False, True)) + self.safety.toyota_rx_hook(self._pcm_cruise_msg(True, True)) + self.assertTrue(self.safety.get_controls_allowed()) + 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): 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.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.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()) def test_ipas_override(self): @@ -416,12 +483,13 @@ class TestToyotaSafety(unittest.TestCase): # reset no angle control at the end of the test 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.assertTrue(self.safety.honda_tx_hook(self._gas_msg(0x0000))) - self.assertFalse(self.safety.honda_tx_hook(self._gas_msg(0x1000))) + self.assertTrue(self.safety.toyota_tx_hook(self._send_interceptor_msg(0, 0x200))) + self.assertFalse(self.safety.toyota_tx_hook(self._send_interceptor_msg(0x1000, 0x200))) 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__":