diff --git a/.circleci/config.yml b/.circleci/config.yml index 2c7805a5bb6c78..2289ad8aa725e1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -29,9 +29,13 @@ jobs: command: | docker run panda_build /bin/bash -c "cd /panda/board; make bin" - run: - name: Build Pedal STM image + name: Build Honda Pedal STM image command: | - docker run panda_build /bin/bash -c "cd /panda/board/pedal; make obj/comma.bin" + docker run panda_build /bin/bash -c "cd /panda/board/pedal_honda; make obj/comma.bin" + - run: + name: Build Toyota Pedal STM image + command: | + docker run panda_build /bin/bash -c "cd /panda/board/pedal_toyota; make obj/comma.bin" - run: name: Build NEO STM image command: | diff --git a/VERSION b/VERSION index 02e8c95da5fd8a..0408c30b42460f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v1.1.8 \ No newline at end of file +v1.2.0 \ No newline at end of file diff --git a/board/main.c b/board/main.c index b1033bb732e2df..16d64916a2ef36 100644 --- a/board/main.c +++ b/board/main.c @@ -559,6 +559,7 @@ int main() { usb_init(); // 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); can_silent = ALL_CAN_SILENT; can_init_all(); diff --git a/board/pedal/.gitignore b/board/pedal_honda/.gitignore similarity index 100% rename from board/pedal/.gitignore rename to board/pedal_honda/.gitignore diff --git a/board/pedal/Makefile b/board/pedal_honda/Makefile similarity index 100% rename from board/pedal/Makefile rename to board/pedal_honda/Makefile diff --git a/board/pedal/README b/board/pedal_honda/README similarity index 100% rename from board/pedal/README rename to board/pedal_honda/README diff --git a/board/pedal/main.c b/board/pedal_honda/main.c similarity index 100% rename from board/pedal/main.c rename to board/pedal_honda/main.c diff --git a/board/pedal/obj/.gitkeep b/board/pedal_honda/obj/.gitkeep similarity index 100% rename from board/pedal/obj/.gitkeep rename to board/pedal_honda/obj/.gitkeep diff --git a/board/pedal_toyota/.gitignore b/board/pedal_toyota/.gitignore new file mode 100644 index 00000000000000..94053f2925089b --- /dev/null +++ b/board/pedal_toyota/.gitignore @@ -0,0 +1 @@ +obj/* diff --git a/board/pedal_toyota/Makefile b/board/pedal_toyota/Makefile new file mode 100644 index 00000000000000..1235cc7156ed9f --- /dev/null +++ b/board/pedal_toyota/Makefile @@ -0,0 +1,58 @@ +# :set noet +PROJ_NAME = comma + +CFLAGS = -O2 -Wall -std=gnu11 -DPEDAL +CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m3 +CFLAGS += -msoft-float -DSTM32F2 -DSTM32F205xx +CFLAGS += -I ../inc -I ../ -I ../../ -nostdlib +CFLAGS += -T../stm32_flash.ld + +STARTUP_FILE = startup_stm32f205xx + +CC = arm-none-eabi-gcc +OBJCOPY = arm-none-eabi-objcopy +OBJDUMP = arm-none-eabi-objdump +DFU_UTIL = "dfu-util" + +# pedal only uses the debug cert +CERT = ../../certs/debug +CFLAGS += "-DALLOW_DEBUG" + +canflash: obj/$(PROJ_NAME).bin + ../../tests/pedal/enter_canloader.py $< + +usbflash: obj/$(PROJ_NAME).bin + ../../tests/pedal/enter_canloader.py; sleep 0.5 + PYTHONPATH=../../ python -c "from python import Panda; p = [x for x in [Panda(x) for x in Panda.list()] if x.bootstub]; assert(len(p)==1); p[0].flash('obj/$(PROJ_NAME).bin', reconnect=False)" + +recover: obj/bootstub.bin obj/$(PROJ_NAME).bin + ../../tests/pedal/enter_canloader.py --recover; sleep 0.5 + $(DFU_UTIL) -d 0483:df11 -a 0 -s 0x08004000 -D obj/$(PROJ_NAME).bin + $(DFU_UTIL) -d 0483:df11 -a 0 -s 0x08000000:leave -D obj/bootstub.bin + +obj/main.o: main.c ../*.h + mkdir -p obj + $(CC) $(CFLAGS) -o $@ -c $< + +obj/bootstub.o: ../bootstub.c ../*.h + mkdir -p obj + $(CC) $(CFLAGS) -o $@ -c $< + +obj/$(STARTUP_FILE).o: ../$(STARTUP_FILE).s + $(CC) $(CFLAGS) -o $@ -c $< + +obj/%.o: ../../crypto/%.c + $(CC) $(CFLAGS) -o $@ -c $< + +obj/$(PROJ_NAME).bin: obj/$(STARTUP_FILE).o obj/main.o + # hack + $(CC) -Wl,--section-start,.isr_vector=0x8004000 $(CFLAGS) -o obj/$(PROJ_NAME).elf $^ + $(OBJCOPY) -v -O binary obj/$(PROJ_NAME).elf obj/code.bin + SETLEN=1 ../../crypto/sign.py obj/code.bin $@ $(CERT) + +obj/bootstub.bin: obj/$(STARTUP_FILE).o obj/bootstub.o obj/sha.o obj/rsa.o + $(CC) $(CFLAGS) -o obj/bootstub.$(PROJ_NAME).elf $^ + $(OBJCOPY) -v -O binary obj/bootstub.$(PROJ_NAME).elf $@ + +clean: + rm -f obj/* diff --git a/board/pedal_toyota/README b/board/pedal_toyota/README new file mode 100644 index 00000000000000..f7c56c3bf40279 --- /dev/null +++ b/board/pedal_toyota/README @@ -0,0 +1,30 @@ +MOVE ALL FILES TO board/pedal TO FLASH + + +This is the firmware for the comma pedal. It borrows a lot from panda. + +The comma pedal is a gas pedal interceptor for Honda/Acura. It allows you to "virtually" press the pedal. + +This is the open source software. Note that it is not ready to use yet. + +== Test Plan == + +* Startup +** Confirm STATE_FAULT_STARTUP +* Timeout +** Send value +** Confirm value is output +** Stop sending messages +** Confirm value is passthru after 100ms +** Confirm STATE_FAULT_TIMEOUT +* Random values +** Send random 6 byte messages +** Confirm random values cause passthru +** Confirm STATE_FAULT_BAD_CHECKSUM +* Same message lockout +** Send same message repeated +** Confirm timeout behavior +* Don't set enable +** Confirm no output +* Set enable and values +** Confirm output diff --git a/board/pedal_toyota/main.c b/board/pedal_toyota/main.c new file mode 100644 index 00000000000000..a9b6cec46732f2 --- /dev/null +++ b/board/pedal_toyota/main.c @@ -0,0 +1,291 @@ +//#define DEBUG +//#define CAN_LOOPBACK_MODE +//#define USE_INTERNAL_OSC + +#include "../config.h" + +#include "drivers/drivers.h" +#include "drivers/llgpio.h" +#include "gpio.h" + +#define CUSTOM_CAN_INTERRUPTS + +#include "libc.h" +#include "safety.h" +#include "drivers/adc.h" +#include "drivers/uart.h" +#include "drivers/dac.h" +#include "drivers/can.h" +#include "drivers/timer.h" + +#define CAN CAN1 + +//#define PEDAL_USB + +#ifdef PEDAL_USB + #include "drivers/usb.h" +#endif + +#define ENTER_BOOTLOADER_MAGIC 0xdeadbeef +uint32_t enter_bootloader_mode; + +void __initialize_hardware_early() { + early(); +} + +// ********************* serial debugging ********************* + +void debug_ring_callback(uart_ring *ring) { + char rcv; + while (getc(ring, &rcv)) { + putc(ring, rcv); + } +} + +#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) {} +void usb_cb_enumeration_complete() {} + +int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) { + int resp_len = 0; + uart_ring *ur = NULL; + switch (setup->b.bRequest) { + // **** 0xe0: uart read + case 0xe0: + ur = get_ring_by_number(setup->b.wValue.w); + if (!ur) break; + if (ur == &esp_ring) uart_dma_drain(); + // read + while ((resp_len < min(setup->b.wLength.w, MAX_RESP_LEN)) && + getc(ur, (char*)&resp[resp_len])) { + ++resp_len; + } + break; + } + return resp_len; +} + +#endif + +// ***************************** toyota can checksum **************************** + +int can_cksum(uint8_t *dat, uint8_t len, uint16_t addr) +{ + uint8_t checksum = 0; + checksum =((addr & 0xFF00) >> 8) + (addr & 0x00FF) + len + 1; + //uint16_t temp_msg = msg; + + for (int ii = 0; ii < len; ii++) + { + checksum += (dat[ii]); + //temp_msg = temp_msg >> 8; + } + //return ((msg & ~0xFF) & (checksum & 0xFF)); + return checksum; +} + +// ***************************** can port ***************************** + +// addresses to be used on CAN +#define CAN_GAS_INPUT 0x200 +#define CAN_GAS_OUTPUT 0x201 + +void CAN1_TX_IRQHandler() { + // clear interrupt + CAN->TSR |= CAN_TSR_RQCP0; +} + +// two independent values +uint16_t gas_set_0 = 0; +uint16_t gas_set_1 = 0; + +#define MAX_TIMEOUT 10 +uint32_t timeout = 0; + +#define NO_FAULT 0 +#define FAULT_BAD_CHECKSUM 1 +#define FAULT_SEND 2 +#define FAULT_SCE 3 +#define FAULT_STARTUP 4 +#define FAULT_TIMEOUT 5 +#define FAULT_INVALID 6 +uint8_t state = FAULT_STARTUP; + +void CAN1_RX0_IRQHandler() { + while (CAN->RF0R & CAN_RF0R_FMP0) { + #ifdef DEBUG + puts("CAN RX\n"); + #endif + uint32_t address = CAN->sFIFOMailBox[0].RIR>>21; + if (address == CAN_GAS_INPUT) { + // softloader entry + if (CAN->sFIFOMailBox[0].RDLR == 0xdeadface) { + if (CAN->sFIFOMailBox[0].RDHR == 0x0ab00b1e) { + enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC; + NVIC_SystemReset(); + } else if (CAN->sFIFOMailBox[0].RDHR == 0x02b00b1e) { + enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC; + NVIC_SystemReset(); + } + } + + // normal packet + uint8_t *dat = (uint8_t *)&CAN->sFIFOMailBox[0].RDLR; + uint8_t *dat2 = (uint8_t *)&CAN->sFIFOMailBox[0].RDHR; + uint16_t value_0 = (dat[0] << 8) | dat[1]; + uint16_t value_1 = (dat[2] << 8) | dat[3]; + uint8_t enable = (dat2[0] >> 7) & 1; + uint8_t index = 0; + if (can_cksum(dat, 5, CAN_GAS_INPUT) == dat2[1]) { + if (index == 0) { + #ifdef DEBUG + puts("setting gas "); + puth(value); + puts("\n"); + #endif + if (enable) { + gas_set_0 = value_0; + gas_set_1 = value_1; + } else { + // clear the fault state if values are 0 + if (value_0 == 0 && value_1 == 0) { + state = NO_FAULT; + } else { + state = FAULT_INVALID; + } + gas_set_0 = gas_set_1 = 0; + } + // clear the timeout + timeout = 0; + } + + } else { + // wrong checksum = fault + state = FAULT_BAD_CHECKSUM; + } + } + // next + CAN->RF0R |= CAN_RF0R_RFOM0; + } +} + +void CAN1_SCE_IRQHandler() { + state = FAULT_SCE; + can_sce(CAN); +} + +int pdl0 = 0, pdl1 = 0; + + +int led_value = 0; + +void TIM3_IRQHandler() { + #ifdef DEBUG + puth(TIM3->CNT); + puts(" "); + puth(pdl0); + puts(" "); + puth(pdl1); + puts("\n"); + #endif + + // check timer for sending the user pedal and clearing the CAN + if ((CAN->TSR & CAN_TSR_TME0) == CAN_TSR_TME0) { + uint8_t dat[8]; + dat[0] = (pdl0>>8)&0xFF; + dat[1] = (pdl0>>0)&0xFF; + dat[2] = (pdl1>>8)&0xFF; + dat[3] = (pdl1>>0)&0xFF; + dat[4] = state; + dat[5] = can_cksum(dat, 5, CAN_GAS_OUTPUT); + CAN->sTxMailBox[0].TDLR = dat[0] | (dat[1]<<8) | (dat[2]<<16) | (dat[3]<<24); + CAN->sTxMailBox[0].TDHR = dat[4] | (dat[5]<<8); + CAN->sTxMailBox[0].TDTR = 6; // len of packet is 5 + CAN->sTxMailBox[0].TIR = (CAN_GAS_OUTPUT << 21) | 1; + } else { + // old can packet hasn't sent! + state = FAULT_SEND; + #ifdef DEBUG + puts("CAN MISS\n"); + #endif + } + + // blink the LED + set_led(LED_GREEN, led_value); + led_value = !led_value; + + TIM3->SR = 0; + + // up timeout for gas set + if (timeout == MAX_TIMEOUT) { + state = FAULT_TIMEOUT; + } else { + timeout += 1; + } +} + +// ***************************** main code ***************************** + +void pedal() { + // read/write + pdl0 = adc_get(ADCCHAN_ACCEL0); + pdl1 = adc_get(ADCCHAN_ACCEL1); + + // write the pedal to the DAC + if (state == NO_FAULT) { + dac_set(0, max(gas_set_0, pdl0)); + dac_set(1, max(gas_set_1, pdl1)); + } else { + dac_set(0, pdl0); + dac_set(1, pdl1); + } + + // feed the watchdog + IWDG->KR = 0xAAAA; +} + +int main() { + __disable_irq(); + + // init devices + clock_init(); + periph_init(); + gpio_init(); + +#ifdef PEDAL_USB + // enable USB + usb_init(); +#endif + + // pedal stuff + dac_init(); + adc_init(); + + // init can + can_silent = ALL_CAN_LIVE; + can_init(0); + + // 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; + + puts("**** INTERRUPTS ON ****\n"); + __enable_irq(); + + // main pedal loop + while (1) { + pedal(); + } + + return 0; +} \ No newline at end of file diff --git a/board/pedal_toyota/obj/.gitkeep b/board/pedal_toyota/obj/.gitkeep new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/board/safety.h b/board/safety.h index 4d2b46899f7969..6e5dc8e36f62b2 100644 --- a/board/safety.h +++ b/board/safety.h @@ -57,12 +57,14 @@ int controls_allowed = 0; #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" #include "safety/safety_hyundai.h" #include "safety/safety_chrysler.h" +#include "safety/safety_subaru.h" #include "safety/safety_elm327.h" const safety_hooks *current_hooks = &nooutput_hooks; @@ -104,6 +106,8 @@ typedef struct { #define SAFETY_HYUNDAI 7 #define SAFETY_TESLA 8 #define SAFETY_CHRYSLER 9 +#define SAFETY_SUBARU 10 +#define SAFETY_GM_ASCM 0x1334 #define SAFETY_TOYOTA_IPAS 0x1335 #define SAFETY_TOYOTA_NOLIMITS 0x1336 #define SAFETY_ALLOUTPUT 0x1337 @@ -119,9 +123,11 @@ const safety_hook_config safety_hook_registry[] = { {SAFETY_CADILLAC, &cadillac_hooks}, {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}, diff --git a/board/safety/safety_gm_ascm.h b/board/safety/safety_gm_ascm.h new file mode 100644 index 00000000000000..70a042ec514a69 --- /dev/null +++ b/board/safety/safety_gm_ascm.h @@ -0,0 +1,52 @@ +// BUS 0 is on the LKAS module (ASCM) side +// BUS 2 is on the actuator (EPS) side + +static int gm_ascm_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { + + uint32_t addr = to_fwd->RIR>>21; + + if (bus_num == 0) { + + // do not propagate lkas messages from ascm to actuators + // block 0x152 and 0x154, which are the lkas command from ASCM1 and ASCM2 + // block 0x315 and 0x2cb, which are the brake and accel commands from ASCM1 + //if ((addr == 0x152) || (addr == 0x154) || (addr == 0x315) || (addr == 0x2cb)) { + if ((addr == 0x152) || (addr == 0x154)) { + int supercruise_on = (to_fwd->RDHR>>4) & 0x1; // bit 36 + if (!supercruise_on) return -1; + } + + // on the chassis bus, the OBDII port is on the module side, so we need to read + // the lkas messages sent by openpilot (put on unused 0x151 ane 0x153 addrs) and send it to + // the actuator as 0x152 and 0x154 + if (addr == 0x151) { + to_fwd->RIR = (0x152 << 21) | (to_fwd->RIR & 0x1fffff); + } + if (addr == 0x153) { + to_fwd->RIR = (0x154 << 21) | (to_fwd->RIR & 0x1fffff); + } + + // brake + if (addr == 0x314) { + to_fwd->RIR = (0x315 << 21) | (to_fwd->RIR & 0x1fffff); + } + + return 2; + } + + if (bus_num == 2) { + return 0; + } + + return -1; +} + +const safety_hooks gm_ascm_hooks = { + .init = nooutput_init, + .rx = default_rx_hook, + .tx = alloutput_tx_hook, + .tx_lin = nooutput_tx_lin_hook, + .ignition = default_ign_hook, + .fwd = gm_ascm_fwd_hook, +}; + diff --git a/board/safety/safety_hyundai.h b/board/safety/safety_hyundai.h index caac727303716e..b67632141d8365 100644 --- a/board/safety/safety_hyundai.h +++ b/board/safety/safety_hyundai.h @@ -1,4 +1,4 @@ -const int HYUNDAI_MAX_STEER = 250; +const int HYUNDAI_MAX_STEER = 255; // like stock const int HYUNDAI_MAX_RT_DELTA = 112; // max delta torque allowed for real time checks const int32_t HYUNDAI_RT_INTERVAL = 250000; // 250ms between real time checks const int HYUNDAI_MAX_RATE_UP = 3; diff --git a/board/safety/safety_subaru.h b/board/safety/safety_subaru.h new file mode 100644 index 00000000000000..3d21d2269a733e --- /dev/null +++ b/board/safety/safety_subaru.h @@ -0,0 +1,49 @@ +void subaru_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {} + +// FIXME +// *** all output safety mode *** + +static void subaru_init(int16_t param) { + controls_allowed = 1; +} + +static int subaru_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { + return true; +} + +static int subaru_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { + + // shifts bits 29 > 11 + int32_t addr = to_fwd->RIR >> 21; + + // forward CAN 0 > 1 + if (bus_num == 0) { + return 1; // ES CAN + } + // forward CAN 1 > 0, except ES_LKAS + else if (bus_num == 1) { + + // outback 2015 + if (addr == 0x164) { + return -1; + } + // global platform + if (addr == 0x122) { + return -1; + } + + return 0; // Main CAN + } + + // fallback to do not forward + return -1; +} + +const safety_hooks subaru_hooks = { + .init = subaru_init, + .rx = subaru_rx_hook, + .tx = subaru_tx_hook, + .tx_lin = nooutput_tx_lin_hook, + .ignition = default_ign_hook, + .fwd = subaru_fwd_hook, +}; \ No newline at end of file diff --git a/crypto/sha.c b/crypto/sha.c index 47676df4b6d8a6..8e1715525c68a2 100644 --- a/crypto/sha.c +++ b/crypto/sha.c @@ -127,10 +127,36 @@ const uint8_t* SHA_final(SHA_CTX* ctx) { while ((ctx->count & 63) != 56) { SHA_update(ctx, (uint8_t*)"\0", 1); } - for (i = 0; i < 8; ++i) { - uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8)); - SHA_update(ctx, &tmp, 1); - } + + /* Hack - right shift operator with non const argument requires + * libgcc.a which is missing in EON + * thus expanding for loop from + + for (i = 0; i < 8; ++i) { + uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8)); + SHA_update(ctx, &tmp, 1); + } + + to + */ + + uint8_t tmp = 0; + tmp = (uint8_t) (cnt >> ((7 - 0) * 8)); + SHA_update(ctx, &tmp, 1); + tmp = (uint8_t) (cnt >> ((7 - 1) * 8)); + SHA_update(ctx, &tmp, 1); + tmp = (uint8_t) (cnt >> ((7 - 2) * 8)); + SHA_update(ctx, &tmp, 1); + tmp = (uint8_t) (cnt >> ((7 - 3) * 8)); + SHA_update(ctx, &tmp, 1); + tmp = (uint8_t) (cnt >> ((7 - 4) * 8)); + SHA_update(ctx, &tmp, 1); + tmp = (uint8_t) (cnt >> ((7 - 5) * 8)); + SHA_update(ctx, &tmp, 1); + tmp = (uint8_t) (cnt >> ((7 - 6) * 8)); + SHA_update(ctx, &tmp, 1); + tmp = (uint8_t) (cnt >> ((7 - 7) * 8)); + SHA_update(ctx, &tmp, 1); for (i = 0; i < 5; i++) { uint32_t tmp = ctx->state[i]; diff --git a/tests/safety/test_hyundai.py b/tests/safety/test_hyundai.py index 0a6ce0f91f3d03..bcf9b761189d55 100644 --- a/tests/safety/test_hyundai.py +++ b/tests/safety/test_hyundai.py @@ -5,7 +5,7 @@ MAX_RATE_UP = 3 MAX_RATE_DOWN = 7 -MAX_STEER = 250 +MAX_STEER = 255 MAX_RT_DELTA = 112 RT_INTERVAL = 250000