Merge panda subtree

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

@ -12,6 +12,37 @@ jobs:
name: Run safety test
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

5
panda/.gitignore vendored

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

@ -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

2
panda/Jenkinsfile vendored

@ -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}")
}

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

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

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

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

@ -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"

@ -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;
}

@ -0,0 +1,40 @@
void clock_init() {
// enable external oscillator
RCC->CR |= RCC_CR_HSEON;
while ((RCC->CR & RCC_CR_HSERDY) == 0);
// divide shit
RCC->CFGR = RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE2_DIV2 | RCC_CFGR_PPRE1_DIV4;
// 16mhz crystal
RCC->PLLCFGR = RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 |
RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLN_5 | RCC_PLLCFGR_PLLSRC_HSE;
// start PLL
RCC->CR |= RCC_CR_PLLON;
while ((RCC->CR & RCC_CR_PLLRDY) == 0);
// Configure Flash prefetch, Instruction cache, Data cache and wait state
// *** without this, it breaks ***
FLASH->ACR = FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_5WS;
// switch to PLL
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
// *** running on PLL ***
}
void watchdog_init() {
// setup watchdog
IWDG->KR = 0x5555;
IWDG->PR = 0; // divider /4
// 0 = 0.125 ms, let's have a 50ms watchdog
IWDG->RLR = 400 - 1;
IWDG->KR = 0xCCCC;
}
void watchdog_feed() {
IWDG->KR = 0xAAAA;
}

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

@ -114,8 +114,6 @@ int get_bit_message(char *out, CAN_FIFOMailBox_TypeDef *to_bang) {
return len;
}
#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

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

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

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

@ -1,5 +1,10 @@
// IRQs: DMA2_Stream2, DMA2_Stream3, EXTI4
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

@ -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

@ -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);

@ -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 *********************

@ -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;
}

@ -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();

@ -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;
}
}

@ -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

@ -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,
};

@ -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,
};

@ -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,
};

@ -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,
};

@ -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,
};

@ -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,
};

@ -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,
};

@ -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,
};

@ -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,
};

@ -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,
};

@ -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,
};

@ -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,
};

@ -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,
};

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 12 KiB

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

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

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

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

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

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

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

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

@ -32,6 +32,11 @@ typedef struct
void set_controls_allowed(int c);
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);

@ -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) {
}

@ -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]:

@ -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)))

@ -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__":

Loading…
Cancel
Save