Merge remote-tracking branch 'upstream/master' into isotp-canfd-support

This commit is contained in:
Shane Smiskol 2024-04-24 14:15:51 -07:00
commit 6027f78cd0
188 changed files with 1330 additions and 12554 deletions

View File

@ -46,7 +46,7 @@ jobs:
run: eval "$BUILD"
- name: Test python package installer
run: ${{ env.RUN }} "python setup.py install"
- name: Build panda + pedal images and bootstub
- name: Build panda images and bootstub
run: ${{ env.RUN }} "scons -j4"
- name: Build panda with SPI support
run: ${{ env.RUN }} "ENABLE_SPI=1 scons -j4"
@ -89,23 +89,6 @@ jobs:
scons -j$(nproc) ${{ matrix.flags }} && \
tests/safety/test.sh"
safety_coverage:
name: safety coverage
runs-on: ubuntu-20.04
timeout-minutes: 20
steps:
- uses: actions/checkout@v2
- name: Build Docker image
run: eval "$BUILD"
- name: Run safety coverage test
timeout-minutes: 5
run: |
${{ env.RUN }} "cd .. && \
scons -c && \
scons -j$(nproc) opendbc/ cereal/ && \
cd panda/tests/safety && \
./test_coverage.sh"
misra:
name: MISRA C:2012
runs-on: ubuntu-20.04
@ -120,8 +103,8 @@ jobs:
timeout-minutes: 1
run: ${{ env.RUN }} "cd tests/misra && ./test_misra.sh"
- name: MISRA mutation tests
timeout-minutes: 3
run: ${{ env.RUN }} "cd tests/misra && ./test_mutation.py"
timeout-minutes: 5
run: ${{ env.RUN }} "cd tests/misra && pytest -n8 test_mutation.py"
python_linter:
name: python linter

View File

@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
rev: v4.6.0
hooks:
- id: check-ast
- id: check-yaml
@ -9,12 +9,12 @@ repos:
- id: check-executables-have-shebangs
- id: check-shebang-scripts-are-executable
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.8.0
rev: v1.9.0
hooks:
- id: mypy
additional_dependencies: ['git+https://github.com/numpy/numpy-stubs', 'types-requests', 'types-atomicwrites',
'types-pycurl']
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.15
rev: v0.4.1
hooks:
- id: ruff

View File

@ -51,8 +51,8 @@ RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-instal
ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}"
ENV PANDA_PATH=/tmp/openpilot/panda
ENV OPENPILOT_REF="5690386d8d731c9bebda536a5c71c890f6dfe98c"
ENV OPENDBC_REF="40d9c723d48496229fecc436046538a53af19c11"
ENV OPENPILOT_REF="bc4b75822a609e6897058bc83688c84004f29093"
ENV OPENDBC_REF="1745ab51825055cd18748013c4a5e3377319e390"
COPY requirements.txt /tmp/
RUN pyenv install 3.11.4 && \
@ -63,6 +63,8 @@ RUN pyenv install 3.11.4 && \
ENV CPPCHECK_DIR=/tmp/cppcheck
COPY tests/misra/install.sh /tmp/
RUN /tmp/install.sh
# don't try to install again
ENV SKIP_CPPCHECK_INSTALL=1
RUN git config --global --add safe.directory /tmp/openpilot/panda
RUN cd /tmp && \

31
Jenkinsfile vendored
View File

@ -82,7 +82,7 @@ pipeline {
["build", "scons -j4"],
["flash", "cd tests/ && ./reflash_internal_panda.py"],
["flash jungle", "cd board/jungle && ./flash.py"],
["test", "cd tests/hitl && HW_TYPES=6 pytest --durations=0 [2-7]*.py -k 'not test_send_recv'"],
["test", "cd tests/hitl && HW_TYPES=6 pytest -n0 --durations=0 [2-9]*.py -k 'not test_send_recv'"],
])
}
}
@ -94,7 +94,7 @@ pipeline {
["build", "scons -j4"],
["flash", "cd tests/ && ./reflash_internal_panda.py"],
["flash jungle", "cd board/jungle && ./flash.py"],
["test", "cd tests/hitl && HW_TYPES=9 pytest --durations=0 2*.py [5-9]*.py"],
["test", "cd tests/hitl && HW_TYPES=9 pytest -n0 --durations=0 2*.py [5-9]*.py"],
])
}
}
@ -126,35 +126,10 @@ pipeline {
stage('bootkick tests') {
steps {
script {
docker_run("test", 10, "pytest ./tests/som/test_bootkick.py")
docker_run("test", 10, "pytest -n0 ./tests/som/test_bootkick.py")
}
}
}
/*
stage('pedal tests') {
steps {
script {
docker_run("test pedal", 1, "PEDAL_JUNGLE=058010800f51363038363036 python ./tests/pedal/test_pedal.py")
}
}
}
stage('HITL tests') {
steps {
script {
docker_run("parallel tests", 5, 'PANDAS_JUNGLE=23002d000851393038373731 PANDAS_EXCLUDE="1d0002000c51303136383232 2f002e000c51303136383232" ./tests/hitl/run_parallel_tests.sh')
docker_run("serial tests", 9, 'PANDAS_JUNGLE=23002d000851393038373731 PANDAS_EXCLUDE="1d0002000c51303136383232 2f002e000c51303136383232" ./tests/hitl/run_serial_tests.sh')
}
}
}
stage('CANFD tests') {
steps {
script {
docker_run("CANFD tets", 6, 'JUNGLE=058010800f51363038363036 H7_PANDAS_EXCLUDE="080021000c51303136383232 33000e001051393133353939" ./tests/canfd/test_canfd.py')
}
}
}
*/
}
}
}

View File

@ -3,7 +3,7 @@
![panda tests](https://github.com/commaai/panda/workflows/tests/badge.svg)
![panda drivers](https://github.com/commaai/panda/workflows/drivers/badge.svg)
panda speaks CAN and CAN FD, and it runs on [STM32F205](https://www.st.com/resource/en/reference_manual/rm0033-stm32f205xx-stm32f207xx-stm32f215xx-and-stm32f217xx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf), [STM32F413](https://www.st.com/resource/en/reference_manual/rm0430-stm32f413423-advanced-armbased-32bit-mcus-stmicroelectronics.pdf), and [STM32H725](https://www.st.com/resource/en/reference_manual/rm0468-stm32h723733-stm32h725735-and-stm32h730-value-line-advanced-armbased-32bit-mcus-stmicroelectronics.pdf).
panda speaks CAN and CAN FD, and it runs on [STM32F413](https://www.st.com/resource/en/reference_manual/rm0430-stm32f413423-advanced-armbased-32bit-mcus-stmicroelectronics.pdf) and [STM32H725](https://www.st.com/resource/en/reference_manual/rm0468-stm32h723733-stm32h725735-and-stm32h730-value-line-advanced-armbased-32bit-mcus-stmicroelectronics.pdf).
## Directory structure

View File

@ -84,7 +84,7 @@ def build_project(project_name, project, extra_flags):
'..',
panda_root,
f"{panda_root}/board/",
f"{panda_root}/board/stm32fx/inc",
f"{panda_root}/board/stm32f4/inc",
f"{panda_root}/board/stm32h7/inc",
]
@ -130,8 +130,8 @@ def build_project(project_name, project, extra_flags):
base_project_f4 = {
"MAIN": "main.c",
"STARTUP_FILE": File("./board/stm32fx/startup_stm32f413xx.s"),
"LINKER_SCRIPT": File("./board/stm32fx/stm32f4_flash.ld"),
"STARTUP_FILE": File("./board/stm32f4/startup_stm32f413xx.s"),
"LINKER_SCRIPT": File("./board/stm32f4/stm32f4_flash.ld"),
"APP_START_ADDRESS": "0x8004000",
"PROJECT_FLAGS": [
"-mcpu=cortex-m4",
@ -180,9 +180,6 @@ with open("board/obj/cert.h", "w") as f:
# panda fw
SConscript('board/SConscript')
# pedal fw
SConscript('board/pedal/SConscript')
# panda jungle fw
SConscript('board/jungle/SConscript')

View File

@ -12,7 +12,7 @@ for project_name, project in build_projects.items():
flags = [
"-DPANDA",
]
if ("ENABLE_SPI" in os.environ or "h7" in project_name) and not project_name.startswith('pedal'):
if ("ENABLE_SPI" in os.environ or "h7" in project_name):
flags.append('-DENABLE_SPI')
if "H723" in os.environ:

View File

@ -1,6 +1,6 @@
// ///////////////////// //
// Black Panda + Harness //
// ///////////////////// //
// /////////////////////////////// //
// Black Panda (STM32F4) + Harness //
// /////////////////////////////// //
void black_enable_can_transceiver(uint8_t transceiver, bool enabled) {
switch (transceiver){
@ -122,8 +122,6 @@ void black_init(void) {
// Initialize harness
harness_init();
// Initialize RTC
rtc_init();
// Enable CAN transceivers
black_enable_can_transceivers(true);
@ -135,11 +133,6 @@ void black_init(void) {
// Set normal CAN mode
black_set_can_mode(CAN_MODE_NORMAL);
// flip CAN0 and CAN2 if we are flipped
if (harness.status == HARNESS_STATUS_FLIPPED) {
can_flip_buses(0, 2);
}
}
void black_init_bootloader(void) {
@ -148,7 +141,7 @@ void black_init_bootloader(void) {
set_gpio_output(GPIOC, 12, 0);
}
const harness_configuration black_harness_config = {
harness_configuration black_harness_config = {
.has_harness = true,
.GPIO_SBU1 = GPIOC,
.GPIO_SBU2 = GPIOC,
@ -162,13 +155,12 @@ const harness_configuration black_harness_config = {
.adc_channel_SBU2 = 13
};
const board board_black = {
board board_black = {
.set_bootkick = unused_set_bootkick,
.harness_config = &black_harness_config,
.has_obd = true,
.has_spi = false,
.has_canfd = false,
.has_rtc_battery = false,
.fan_max_rpm = 0U,
.avdd_mV = 3300U,
.fan_stall_recovery = false,
@ -180,7 +172,8 @@ const board board_black = {
.set_led = black_set_led,
.set_can_mode = black_set_can_mode,
.check_ignition = black_check_ignition,
.read_current = unused_read_current,
.read_voltage_mV = white_read_voltage_mV,
.read_current_mA = unused_read_current,
.set_fan_enabled = unused_set_fan_enabled,
.set_ir_power = unused_set_ir_power,
.set_siren = unused_set_siren,

View File

@ -12,7 +12,8 @@ typedef void (*board_enable_can_transceivers)(bool enabled);
typedef void (*board_set_led)(uint8_t color, bool enabled);
typedef void (*board_set_can_mode)(uint8_t mode);
typedef bool (*board_check_ignition)(void);
typedef uint32_t (*board_read_current)(void);
typedef uint32_t (*board_read_voltage_mV)(void);
typedef uint32_t (*board_read_current_mA)(void);
typedef void (*board_set_ir_power)(uint8_t percentage);
typedef void (*board_set_fan_enabled)(bool enabled);
typedef void (*board_set_siren)(bool enabled);
@ -20,11 +21,10 @@ typedef void (*board_set_bootkick)(BootState state);
typedef bool (*board_read_som_gpio)(void);
struct board {
const harness_configuration *harness_config;
harness_configuration *harness_config;
const bool has_obd;
const bool has_spi;
const bool has_canfd;
const bool has_rtc_battery;
const uint16_t fan_max_rpm;
const uint16_t avdd_mV;
const bool fan_stall_recovery;
@ -36,7 +36,8 @@ struct board {
board_set_led set_led;
board_set_can_mode set_can_mode;
board_check_ignition check_ignition;
board_read_current read_current;
board_read_voltage_mV read_voltage_mV;
board_read_current_mA read_current_mA;
board_set_ir_power set_ir_power;
board_set_fan_enabled set_fan_enabled;
board_set_siren set_siren;
@ -71,6 +72,4 @@ struct board {
// CAN modes
#define CAN_MODE_NORMAL 0U
#define CAN_MODE_GMLAN_CAN2 1U
#define CAN_MODE_GMLAN_CAN3 2U
#define CAN_MODE_OBD_CAN2 3U
#define CAN_MODE_OBD_CAN2 1U

View File

@ -1,3 +1,7 @@
// ////////////////////////// //
// Cuatro (STM32H7) + Harness //
// ////////////////////////// //
void cuatro_set_led(uint8_t color, bool enabled) {
switch (color) {
case LED_RED:
@ -15,29 +19,62 @@ void cuatro_set_led(uint8_t color, bool enabled) {
}
void cuatro_enable_can_transceiver(uint8_t transceiver, bool enabled) {
if (transceiver == 1U) {
set_gpio_output(GPIOB, 7, !enabled);
} else if (transceiver == 3U) {
set_gpio_output(GPIOD, 8, !enabled);
} else {
red_enable_can_transceiver(transceiver, enabled);
switch (transceiver) {
case 1U:
set_gpio_output(GPIOB, 7, !enabled);
break;
case 2U:
set_gpio_output(GPIOB, 10, !enabled);
break;
case 3U:
set_gpio_output(GPIOD, 8, !enabled);
break;
case 4U:
set_gpio_output(GPIOB, 11, !enabled);
break;
default:
break;
}
}
void cuatro_enable_can_transceivers(bool enabled) {
uint8_t main_bus = (harness.status == HARNESS_STATUS_FLIPPED) ? 3U : 1U;
for (uint8_t i=1U; i<=4U; i++) {
// Leave main CAN always on for CAN-based ignition detection
if (i == main_bus) {
cuatro_enable_can_transceiver(i, true);
} else {
cuatro_enable_can_transceiver(i, enabled);
}
}
}
uint32_t cuatro_read_voltage_mV(void) {
return adc_get_mV(8) * 11U;
}
uint32_t cuatro_read_current_mA(void) {
return adc_get_mV(3) * 2U;
}
void cuatro_init(void) {
red_chiplet_init();
// CAN FD 0 transceiver enable (rest are done in red init)
// Power readout
set_gpio_mode(GPIOC, 5, MODE_ANALOG);
set_gpio_mode(GPIOA, 6, MODE_ANALOG);
// CAN transceiver enables
set_gpio_pullup(GPIOB, 7, PULL_NONE);
set_gpio_mode(GPIOB, 7, MODE_OUTPUT);
set_gpio_pullup(GPIOD, 8, PULL_NONE);
set_gpio_mode(GPIOD, 8, MODE_OUTPUT);
// FDCAN2
// FDCAN3, different pins on this package than the rest of the reds
set_gpio_pullup(GPIOD, 12, PULL_NONE);
set_gpio_alternate(GPIOD, 12, GPIO_AF9_FDCAN2);
set_gpio_alternate(GPIOD, 12, GPIO_AF5_FDCAN3);
set_gpio_pullup(GPIOD, 13, PULL_NONE);
set_gpio_alternate(GPIOD, 13, GPIO_AF9_FDCAN2);
set_gpio_alternate(GPIOD, 13, GPIO_AF5_FDCAN3);
// C2: SOM GPIO used as input (fan control at boot)
set_gpio_mode(GPIOC, 2, MODE_INPUT);
@ -66,12 +103,11 @@ void cuatro_init(void) {
clock_source_init();
}
const board board_cuatro = {
board board_cuatro = {
.harness_config = &red_chiplet_harness_config,
.has_obd = true,
.has_spi = true,
.has_canfd = true,
.has_rtc_battery = true,
.fan_max_rpm = 6600U,
.avdd_mV = 1800U,
.fan_stall_recovery = false,
@ -79,11 +115,12 @@ const board board_cuatro = {
.init = cuatro_init,
.init_bootloader = unused_init_bootloader,
.enable_can_transceiver = cuatro_enable_can_transceiver,
.enable_can_transceivers = red_chiplet_enable_can_transceivers,
.enable_can_transceivers = cuatro_enable_can_transceivers,
.set_led = cuatro_set_led,
.set_can_mode = red_chiplet_set_can_mode,
.check_ignition = red_check_ignition,
.read_current = unused_read_current,
.read_voltage_mV = cuatro_read_voltage_mV,
.read_current_mA = cuatro_read_current_mA,
.set_fan_enabled = tres_set_fan_enabled,
.set_ir_power = tres_set_ir_power,
.set_siren = unused_set_siren,

View File

@ -1,6 +1,6 @@
// ///////////// //
// Dos + Harness //
// ///////////// //
// /////////////////////// //
// Dos (STM32F4) + Harness //
// /////////////////////// //
void dos_enable_can_transceiver(uint8_t transceiver, bool enabled) {
switch (transceiver){
@ -90,10 +90,6 @@ bool dos_check_ignition(void){
return harness_check_ignition();
}
void dos_set_usb_switch(bool phone){
set_gpio_output(GPIOB, 3, phone);
}
void dos_set_ir_power(uint8_t percentage){
pwm_set(TIM4, 2, percentage);
}
@ -151,8 +147,6 @@ void dos_init(void) {
// Initialize harness
harness_init();
// Initialize RTC
rtc_init();
// Enable CAN transceivers
dos_enable_can_transceivers(true);
@ -168,16 +162,11 @@ void dos_init(void) {
// Set normal CAN mode
dos_set_can_mode(CAN_MODE_NORMAL);
// flip CAN0 and CAN2 if we are flipped
if (harness.status == HARNESS_STATUS_FLIPPED) {
can_flip_buses(0, 2);
}
// Init clock source (camera strobe) using PWM
clock_source_init();
}
const harness_configuration dos_harness_config = {
harness_configuration dos_harness_config = {
.has_harness = true,
.GPIO_SBU1 = GPIOC,
.GPIO_SBU2 = GPIOC,
@ -191,7 +180,7 @@ const harness_configuration dos_harness_config = {
.adc_channel_SBU2 = 13
};
const board board_dos = {
board board_dos = {
.harness_config = &dos_harness_config,
.has_obd = true,
#ifdef ENABLE_SPI
@ -200,7 +189,6 @@ const board board_dos = {
.has_spi = false,
#endif
.has_canfd = false,
.has_rtc_battery = true,
.fan_max_rpm = 6500U,
.avdd_mV = 3300U,
.fan_stall_recovery = true,
@ -212,7 +200,8 @@ const board board_dos = {
.set_led = dos_set_led,
.set_can_mode = dos_set_can_mode,
.check_ignition = dos_check_ignition,
.read_current = unused_read_current,
.read_voltage_mV = white_read_voltage_mV,
.read_current_mA = unused_read_current,
.set_fan_enabled = dos_set_fan_enabled,
.set_ir_power = dos_set_ir_power,
.set_siren = dos_set_siren,

View File

@ -1,16 +1,15 @@
// ////////// //
// Grey Panda //
// ////////// //
// //////////////////// //
// Grey Panda (STM32F4) //
// //////////////////// //
// Most hardware functionality is similar to white panda
const board board_grey = {
board board_grey = {
.set_bootkick = unused_set_bootkick,
.harness_config = &white_harness_config,
.has_obd = false,
.has_spi = false,
.has_canfd = false,
.has_rtc_battery = false,
.fan_max_rpm = 0U,
.avdd_mV = 3300U,
.fan_stall_recovery = false,
@ -22,7 +21,8 @@ const board board_grey = {
.set_led = white_set_led,
.set_can_mode = white_set_can_mode,
.check_ignition = white_check_ignition,
.read_current = white_read_current,
.read_voltage_mV = white_read_voltage_mV,
.read_current_mA = white_read_current_mA,
.set_fan_enabled = unused_set_fan_enabled,
.set_ir_power = unused_set_ir_power,
.set_siren = unused_set_siren,

View File

@ -1,92 +0,0 @@
// ///// //
// Pedal //
// ///// //
void pedal_enable_can_transceiver(uint8_t transceiver, bool enabled) {
switch (transceiver){
case 1:
set_gpio_output(GPIOB, 3, !enabled);
break;
default:
print("Invalid CAN transceiver ("); puth(transceiver); print("): enabling failed\n");
break;
}
}
void pedal_enable_can_transceivers(bool enabled) {
pedal_enable_can_transceiver(1U, enabled);
}
void pedal_set_led(uint8_t color, bool enabled) {
switch (color){
case LED_RED:
set_gpio_output(GPIOB, 10, !enabled);
break;
case LED_GREEN:
set_gpio_output(GPIOB, 11, !enabled);
break;
default:
break;
}
}
void pedal_set_can_mode(uint8_t mode){
switch (mode) {
case CAN_MODE_NORMAL:
break;
default:
print("Tried to set unsupported CAN mode: "); puth(mode); print("\n");
break;
}
}
bool pedal_check_ignition(void){
// not supported on pedal
return false;
}
void pedal_init(void) {
common_init_gpio();
// C0, C1: Throttle inputs
set_gpio_mode(GPIOC, 0, MODE_ANALOG);
set_gpio_mode(GPIOC, 1, MODE_ANALOG);
// DAC outputs on A4 and A5
// apparently they don't need GPIO setup
// Enable transceiver
pedal_enable_can_transceivers(true);
// Disable LEDs
pedal_set_led(LED_RED, false);
pedal_set_led(LED_GREEN, false);
}
const harness_configuration pedal_harness_config = {
.has_harness = false
};
const board board_pedal = {
.set_bootkick = unused_set_bootkick,
.harness_config = &pedal_harness_config,
.has_obd = false,
.has_spi = false,
.has_canfd = false,
.has_rtc_battery = false,
.fan_max_rpm = 0U,
.avdd_mV = 3300U,
.fan_stall_recovery = false,
.fan_enable_cooldown_time = 0U,
.init = pedal_init,
.init_bootloader = unused_init_bootloader,
.enable_can_transceiver = pedal_enable_can_transceiver,
.enable_can_transceivers = pedal_enable_can_transceivers,
.set_led = pedal_set_led,
.set_can_mode = pedal_set_can_mode,
.check_ignition = pedal_check_ignition,
.read_current = unused_read_current,
.set_fan_enabled = unused_set_fan_enabled,
.set_ir_power = unused_set_ir_power,
.set_siren = unused_set_siren,
.read_som_gpio = unused_read_som_gpio
};

View File

@ -1,6 +1,6 @@
// ///////////////////// //
// Red Panda + Harness //
// ///////////////////// //
// ///////////////////////////// //
// Red Panda (STM32H7) + Harness //
// ///////////////////////////// //
void red_enable_can_transceiver(uint8_t transceiver, bool enabled) {
switch (transceiver) {
@ -96,6 +96,10 @@ bool red_check_ignition(void) {
return harness_check_ignition();
}
uint32_t red_read_voltage_mV(void){
return adc_get_mV(2) * 11U; // TODO: is this correct?
}
void red_init(void) {
common_init_gpio();
@ -136,8 +140,6 @@ void red_init(void) {
// Initialize harness
harness_init();
// Initialize RTC
rtc_init();
// Enable CAN transceivers
red_enable_can_transceivers(true);
@ -149,14 +151,9 @@ void red_init(void) {
// Set normal CAN mode
red_set_can_mode(CAN_MODE_NORMAL);
// flip CAN0 and CAN2 if we are flipped
if (harness.status == HARNESS_STATUS_FLIPPED) {
can_flip_buses(0, 2);
}
}
const harness_configuration red_harness_config = {
harness_configuration red_harness_config = {
.has_harness = true,
.GPIO_SBU1 = GPIOC,
.GPIO_SBU2 = GPIOA,
@ -170,13 +167,12 @@ const harness_configuration red_harness_config = {
.adc_channel_SBU2 = 17 //ADC1_INP17
};
const board board_red = {
board board_red = {
.set_bootkick = unused_set_bootkick,
.harness_config = &red_harness_config,
.has_obd = true,
.has_spi = false,
.has_canfd = true,
.has_rtc_battery = false,
.fan_max_rpm = 0U,
.avdd_mV = 3300U,
.fan_stall_recovery = false,
@ -188,7 +184,8 @@ const board board_red = {
.set_led = red_set_led,
.set_can_mode = red_set_can_mode,
.check_ignition = red_check_ignition,
.read_current = unused_read_current,
.read_voltage_mV = red_read_voltage_mV,
.read_current_mA = unused_read_current,
.set_fan_enabled = unused_set_fan_enabled,
.set_ir_power = unused_set_ir_power,
.set_siren = unused_set_siren,

View File

@ -1,6 +1,6 @@
// ///////////////////// //
// Red Panda chiplet + Harness //
// ///////////////////// //
// ///////////////////////////////////// //
// Red Panda chiplet (STM32H7) + Harness //
// ///////////////////////////////////// //
// Most hardware functionality is similar to red panda
@ -119,8 +119,6 @@ void red_chiplet_init(void) {
// Initialize harness
harness_init();
// Initialize RTC
rtc_init();
// Enable CAN transceivers
red_chiplet_enable_can_transceivers(true);
@ -132,14 +130,9 @@ void red_chiplet_init(void) {
// Set normal CAN mode
red_chiplet_set_can_mode(CAN_MODE_NORMAL);
// flip CAN0 and CAN2 if we are flipped
if (harness.status == HARNESS_STATUS_FLIPPED) {
can_flip_buses(0, 2);
}
}
const harness_configuration red_chiplet_harness_config = {
harness_configuration red_chiplet_harness_config = {
.has_harness = true,
.GPIO_SBU1 = GPIOC,
.GPIO_SBU2 = GPIOA,

View File

@ -1,6 +1,6 @@
// /////////////////
// Tres + Harness //
// /////////////////
// ///////////////////////////
// Tres (STM32H7) + Harness //
// ///////////////////////////
bool tres_ir_enabled;
bool tres_fan_enabled;
@ -33,7 +33,7 @@ void tres_init(void) {
// Enable USB 3.3V LDO for USB block
register_set_bits(&(PWR->CR3), PWR_CR3_USBREGEN);
register_set_bits(&(PWR->CR3), PWR_CR3_USB33DEN);
while ((PWR->CR3 & PWR_CR3_USB33RDY) == 0);
while ((PWR->CR3 & PWR_CR3_USB33RDY) == 0U);
red_chiplet_init();
@ -70,12 +70,11 @@ void tres_init(void) {
clock_source_init();
}
const board board_tres = {
board board_tres = {
.harness_config = &red_chiplet_harness_config,
.has_obd = true,
.has_spi = true,
.has_canfd = true,
.has_rtc_battery = true,
.fan_max_rpm = 6600U,
.avdd_mV = 1800U,
.fan_stall_recovery = false,
@ -87,7 +86,8 @@ const board board_tres = {
.set_led = red_set_led,
.set_can_mode = red_chiplet_set_can_mode,
.check_ignition = red_check_ignition,
.read_current = unused_read_current,
.read_voltage_mV = red_read_voltage_mV,
.read_current_mA = unused_read_current,
.set_fan_enabled = tres_set_fan_enabled,
.set_ir_power = tres_set_ir_power,
.set_siren = fake_siren_set,

View File

@ -1,6 +1,6 @@
// ///////////// //
// Uno + Harness //
// ///////////// //
// /////////////////////// //
// Uno (STM32F4) + Harness //
// /////////////////////// //
void uno_enable_can_transceiver(uint8_t transceiver, bool enabled) {
switch (transceiver){
@ -147,8 +147,6 @@ void uno_init(void) {
// Initialize harness
harness_init();
// Initialize RTC
rtc_init();
// Enable CAN transceivers
uno_enable_can_transceivers(true);
@ -161,13 +159,8 @@ void uno_init(void) {
// Set normal CAN mode
uno_set_can_mode(CAN_MODE_NORMAL);
// flip CAN0 and CAN2 if we are flipped
if (harness.status == HARNESS_STATUS_FLIPPED) {
can_flip_buses(0, 2);
}
// Switch to phone usb mode if harness connection is powered by less than 7V
if((adc_get_mV(ADCCHAN_VIN) * VIN_READOUT_DIVIDER) < 7000U){
if(white_read_voltage_mV() < 7000U){
uno_set_usb_switch(true);
} else {
uno_set_usb_switch(false);
@ -184,7 +177,7 @@ void uno_init_bootloader(void) {
set_gpio_output(GPIOC, 12, 0);
}
const harness_configuration uno_harness_config = {
harness_configuration uno_harness_config = {
.has_harness = true,
.GPIO_SBU1 = GPIOC,
.GPIO_SBU2 = GPIOC,
@ -198,12 +191,11 @@ const harness_configuration uno_harness_config = {
.adc_channel_SBU2 = 13
};
const board board_uno = {
board board_uno = {
.harness_config = &uno_harness_config,
.has_obd = true,
.has_spi = false,
.has_canfd = false,
.has_rtc_battery = true,
.fan_max_rpm = 5100U,
.avdd_mV = 3300U,
.fan_stall_recovery = false,
@ -215,7 +207,8 @@ const board board_uno = {
.set_led = uno_set_led,
.set_can_mode = uno_set_can_mode,
.check_ignition = uno_check_ignition,
.read_current = unused_read_current,
.read_voltage_mV = white_read_voltage_mV,
.read_current_mA = unused_read_current,
.set_fan_enabled = uno_set_fan_enabled,
.set_ir_power = uno_set_ir_power,
.set_siren = unused_set_siren,

View File

@ -1,6 +1,6 @@
// /////////// //
// White Panda //
// /////////// //
// ///////////////////// //
// White Panda (STM32F4) //
// ///////////////////// //
void white_enable_can_transceiver(uint8_t transceiver, bool enabled) {
switch (transceiver){
@ -66,66 +66,32 @@ void white_set_usb_power_mode(uint8_t mode){
}
void white_set_can_mode(uint8_t mode){
switch (mode) {
case CAN_MODE_NORMAL:
// B12,B13: disable GMLAN mode
set_gpio_mode(GPIOB, 12, MODE_INPUT);
set_gpio_mode(GPIOB, 13, MODE_INPUT);
if (mode == CAN_MODE_NORMAL) {
// B12,B13: disable GMLAN mode
set_gpio_mode(GPIOB, 12, MODE_INPUT);
set_gpio_mode(GPIOB, 13, MODE_INPUT);
// 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);
// B5,B6: normal CAN2 mode
set_gpio_alternate(GPIOB, 5, GPIO_AF9_CAN2);
set_gpio_alternate(GPIOB, 6, GPIO_AF9_CAN2);
// B5,B6: normal CAN2 mode
set_gpio_alternate(GPIOB, 5, GPIO_AF9_CAN2);
set_gpio_alternate(GPIOB, 6, GPIO_AF9_CAN2);
// A8,A15: normal CAN3 mode
set_gpio_alternate(GPIOA, 8, GPIO_AF11_CAN3);
set_gpio_alternate(GPIOA, 15, GPIO_AF11_CAN3);
break;
case CAN_MODE_GMLAN_CAN2:
// B5,B6: disable CAN2 mode
set_gpio_mode(GPIOB, 5, MODE_INPUT);
set_gpio_mode(GPIOB, 6, MODE_INPUT);
// B3,B4: disable GMLAN mode
set_gpio_mode(GPIOB, 3, MODE_INPUT);
set_gpio_mode(GPIOB, 4, MODE_INPUT);
// B12,B13: GMLAN mode
set_gpio_alternate(GPIOB, 12, GPIO_AF9_CAN2);
set_gpio_alternate(GPIOB, 13, GPIO_AF9_CAN2);
// A8,A15: normal CAN3 mode
set_gpio_alternate(GPIOA, 8, GPIO_AF11_CAN3);
set_gpio_alternate(GPIOA, 15, GPIO_AF11_CAN3);
break;
case CAN_MODE_GMLAN_CAN3:
// A8,A15: disable CAN3 mode
set_gpio_mode(GPIOA, 8, MODE_INPUT);
set_gpio_mode(GPIOA, 15, MODE_INPUT);
// B12,B13: disable GMLAN mode
set_gpio_mode(GPIOB, 12, MODE_INPUT);
set_gpio_mode(GPIOB, 13, MODE_INPUT);
// B3,B4: GMLAN mode
set_gpio_alternate(GPIOB, 3, GPIO_AF11_CAN3);
set_gpio_alternate(GPIOB, 4, GPIO_AF11_CAN3);
// B5,B6: normal CAN2 mode
set_gpio_alternate(GPIOB, 5, GPIO_AF9_CAN2);
set_gpio_alternate(GPIOB, 6, GPIO_AF9_CAN2);
break;
default:
print("Tried to set unsupported CAN mode: "); puth(mode); print("\n");
break;
// A8,A15: normal CAN3 mode
set_gpio_alternate(GPIOA, 8, GPIO_AF11_CAN3);
set_gpio_alternate(GPIOA, 15, GPIO_AF11_CAN3);
}
}
uint32_t white_read_current(void){
return adc_get_raw(ADCCHAN_CURRENT);
uint32_t white_read_voltage_mV(void){
return adc_get_mV(12) * 11U;
}
uint32_t white_read_current_mA(void){
// This isn't in mA, but we're keeping it for backwards compatibility
return adc_get_raw(13);
}
bool white_check_ignition(void){
@ -163,8 +129,8 @@ void white_grey_init(void) {
0 1 high voltage wakeup
1 1 33kbit (normal)
*/
set_gpio_output(GPIOB, 14, 1);
set_gpio_output(GPIOB, 15, 1);
set_gpio_output(GPIOB, 14, 0);
set_gpio_output(GPIOB, 15, 0);
// B7: K-line enable
set_gpio_output(GPIOB, 7, 1);
@ -182,8 +148,6 @@ void white_grey_init(void) {
set_gpio_alternate(GPIOC, 11, GPIO_AF7_USART3);
set_gpio_pullup(GPIOC, 11, PULL_UP);
// Initialize RTC
rtc_init();
// Enable CAN transceivers
white_enable_can_transceivers(true);
@ -197,10 +161,9 @@ void white_grey_init(void) {
white_set_can_mode(CAN_MODE_NORMAL);
// Init usb power mode
uint32_t voltage = adc_get_mV(ADCCHAN_VIN) * VIN_READOUT_DIVIDER;
// Init in CDP mode only if panda is powered by 12V.
// Otherwise a PC would not be able to flash a standalone panda
if (voltage > 8000U) { // 8V threshold
if (white_read_voltage_mV() > 8000U) { // 8V threshold
white_set_usb_power_mode(USB_POWER_CDP);
} else {
white_set_usb_power_mode(USB_POWER_CLIENT);
@ -217,17 +180,16 @@ void white_grey_init_bootloader(void) {
set_gpio_output(GPIOC, 14, 0);
}
const harness_configuration white_harness_config = {
harness_configuration white_harness_config = {
.has_harness = false
};
const board board_white = {
board board_white = {
.set_bootkick = unused_set_bootkick,
.harness_config = &white_harness_config,
.has_obd = false,
.has_spi = false,
.has_canfd = false,
.has_rtc_battery = false,
.fan_max_rpm = 0U,
.avdd_mV = 3300U,
.fan_stall_recovery = false,
@ -239,7 +201,8 @@ const board board_white = {
.set_led = white_set_led,
.set_can_mode = white_set_can_mode,
.check_ignition = white_check_ignition,
.read_current = white_read_current,
.read_voltage_mV = white_read_voltage_mV,
.read_current_mA = white_read_current_mA,
.set_fan_enabled = unused_set_fan_enabled,
.set_ir_power = unused_set_ir_power,
.set_siren = unused_set_siren,

View File

@ -19,6 +19,7 @@
#include "obj/gitversion.h"
#include "flasher.h"
// cppcheck-suppress unusedFunction ; used in headers not included in cppcheck
void __initialize_hardware_early(void) {
early_initialization();
}

View File

@ -6,8 +6,6 @@ void puth4(uint8_t i){ UNUSED(i); }
void hexdump(const void *a, int l){ UNUSED(a); UNUSED(l); }
typedef struct board board;
typedef struct harness_configuration harness_configuration;
// No CAN support on bootloader
void can_flip_buses(uint8_t bus1, uint8_t bus2){UNUSED(bus1); UNUSED(bus2);}
void pwm_init(TIM_TypeDef *TIM, uint8_t channel);
void pwm_set(TIM_TypeDef *TIM, uint8_t channel, uint8_t percentage);
// No UART support in bootloader
@ -17,4 +15,4 @@ void uart_init(uart_ring *q, int baud) { UNUSED(q); UNUSED(baud); }
// ********************* Globals **********************
uint8_t hw_type = 0;
const board *current_board;
board *current_board;

View File

@ -1,14 +1,14 @@
#pragma once
const uint8_t PANDA_CAN_CNT = 3U;
const uint8_t PANDA_BUS_CNT = 4U;
const uint8_t PANDA_BUS_CNT = 3U;
// bump this when changing the CAN packet
#define CAN_PACKET_VERSION 4
#define CANPACKET_HEAD_SIZE 6U
#if !defined(STM32F4) && !defined(STM32F2)
#if !defined(STM32F4)
#define CANFD
#define CANPACKET_DATA_SIZE_MAX 64U
#else

View File

@ -11,13 +11,10 @@
//#define DEBUG_FAN
#define CAN_INIT_TIMEOUT_MS 500U
#define DEEPSLEEP_WAKEUP_DELAY 3U
#define USBPACKET_MAX_SIZE 0x40U
#define MAX_CAN_MSGS_PER_USB_BULK_TRANSFER 51U
#define MAX_CAN_MSGS_PER_SPI_BULK_TRANSFER 170U
#define VIN_READOUT_DIVIDER 11U
// USB definitions
#define USB_VID 0xBBAAU
@ -38,8 +35,8 @@
// platform includes
#ifdef STM32H7
#include "stm32h7/stm32h7_config.h"
#elif defined(STM32F2) || defined(STM32F4)
#include "stm32fx/stm32fx_config.h"
#elif defined(STM32F4)
#include "stm32f4/stm32f4_config.h"
#else
// TODO: uncomment this, cppcheck complains
// building for tests

View File

@ -48,7 +48,7 @@ void update_can_health_pkt(uint8_t can_number, uint32_t ir_reg) {
can_health[can_number].total_error_cnt += 1U;
// RX message lost due to FIFO overrun
if ((CANx->RF0R & (CAN_RF0R_FOVR0)) != 0) {
if ((CANx->RF0R & (CAN_RF0R_FOVR0)) != 0U) {
can_health[can_number].total_rx_lost_cnt += 1U;
CANx->RF0R &= ~(CAN_RF0R_FOVR0);
}
@ -74,7 +74,7 @@ void process_can(uint8_t can_number) {
// check for empty mailbox
CANPacket_t to_send;
if ((CANx->TSR & (CAN_TSR_TERR0 | CAN_TSR_ALST0)) != 0) { // last TX failed due to error arbitration lost
if ((CANx->TSR & (CAN_TSR_TERR0 | CAN_TSR_ALST0)) != 0U) { // last TX failed due to error arbitration lost
can_health[can_number].total_tx_lost_cnt += 1U;
CANx->TSR |= (CAN_TSR_TERR0 | CAN_TSR_ALST0);
}
@ -129,7 +129,7 @@ void can_rx(uint8_t can_number) {
CAN_TypeDef *CANx = CANIF_FROM_CAN_NUM(can_number);
uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number);
while ((CANx->RF0R & CAN_RF0R_FMP0) != 0) {
while ((CANx->RF0R & CAN_RF0R_FMP0) != 0U) {
can_health[can_number].total_rx_cnt += 1U;
// can is live

View File

@ -20,7 +20,6 @@ uint32_t safety_tx_blocked = 0;
uint32_t safety_rx_invalid = 0;
uint32_t tx_buffer_overflow = 0;
uint32_t rx_buffer_overflow = 0;
uint32_t gmlan_send_errs = 0;
can_health_t can_health[] = {{0}, {0}, {0}};
@ -28,8 +27,8 @@ extern int can_live;
extern int pending_can_live;
// must reinit after changing these
extern int can_loopback;
extern int can_silent;
extern bool can_loopback;
// Ignition detected from CAN meessages
bool ignition_can = false;
@ -40,8 +39,8 @@ uint32_t ignition_can_cnt = 0U;
int can_live = 0;
int pending_can_live = 0;
int can_loopback = 0;
int can_silent = ALL_CAN_SILENT;
bool can_loopback = false;
// ******************* functions prototypes *********************
bool can_init(uint8_t can_number);
@ -54,7 +53,6 @@ void process_can(uint8_t can_number);
#define CAN_RX_BUFFER_SIZE 4096U
#define CAN_TX_BUFFER_SIZE 416U
#define GMLAN_TX_BUFFER_SIZE 416U
#ifdef STM32H7
// ITCM RAM and DTCM RAM are the fastest for Cortex-M7 core access
@ -67,10 +65,10 @@ can_buffer(tx1_q, CAN_TX_BUFFER_SIZE)
can_buffer(tx2_q, CAN_TX_BUFFER_SIZE)
#endif
can_buffer(tx3_q, CAN_TX_BUFFER_SIZE)
can_buffer(txgmlan_q, GMLAN_TX_BUFFER_SIZE)
// FIXME:
// cppcheck-suppress misra-c2012-9.3
can_ring *can_queues[] = {&can_tx1_q, &can_tx2_q, &can_tx3_q, &can_txgmlan_q};
can_ring *can_queues[] = {&can_tx1_q, &can_tx2_q, &can_tx3_q};
// helpers
#define WORD_TO_BYTE_ARRAY(dst8, src32) 0[dst8] = ((src32) & 0xFFU); 1[dst8] = (((src32) >> 8U) & 0xFFU); 2[dst8] = (((src32) >> 16U) & 0xFFU); 3[dst8] = (((src32) >> 24U) & 0xFFU)
@ -122,8 +120,6 @@ bool can_push(can_ring *q, const CANPacket_t *elem) {
print("can_tx2_q");
} else if (q == &can_tx3_q) {
print("can_tx3_q");
} else if (q == &can_txgmlan_q) {
print("can_txgmlan_q");
} else {
print("unknown");
}
@ -157,7 +153,7 @@ void can_clear(can_ring *q) {
}
// assign CAN numbering
// bus num: Can bus number on ODB connector. Sent to/from USB
// bus num: CAN Bus numbers in panda, sent to/from USB
// Min: 0; Max: 127; Bit 7 marks message as receipt (bus 129 is receipt for but 1)
// cans: Look up MCU can interface from bus number
// can number: numeric lookup for MCU CAN interfaces (0 = CAN1, 1 = CAN2, etc);
@ -179,22 +175,20 @@ bus_config_t bus_config[] = {
#define CAN_NUM_FROM_BUS_NUM(num) (bus_config[num].can_num_lookup)
void can_init_all(void) {
bool ret = true;
for (uint8_t i=0U; i < PANDA_CAN_CNT; i++) {
if (!current_board->has_canfd) {
bus_config[i].can_data_speed = 0U;
}
can_clear(can_queues[i]);
ret &= can_init(i);
(void)can_init(i);
}
UNUSED(ret);
}
void can_flip_buses(uint8_t bus1, uint8_t bus2){
bus_config[bus1].bus_lookup = bus2;
bus_config[bus2].bus_lookup = bus1;
bus_config[bus1].can_num_lookup = bus2;
bus_config[bus2].can_num_lookup = bus1;
void can_set_orientation(bool flipped) {
bus_config[0].bus_lookup = flipped ? 2U : 0U;
bus_config[0].can_num_lookup = flipped ? 2U : 0U;
bus_config[2].bus_lookup = flipped ? 0U : 2U;
bus_config[2].can_num_lookup = flipped ? 0U : 2U;
}
void can_set_forwarding(uint8_t from, uint8_t to) {
@ -234,8 +228,7 @@ bool can_tx_check_min_slots_free(uint32_t min) {
return
(can_slots_empty(&can_tx1_q) >= min) &&
(can_slots_empty(&can_tx2_q) >= min) &&
(can_slots_empty(&can_tx3_q) >= min) &&
(can_slots_empty(&can_txgmlan_q) >= min);
(can_slots_empty(&can_tx3_q) >= min);
}
uint8_t calculate_checksum(const uint8_t *dat, uint32_t len) {
@ -259,12 +252,8 @@ void can_send(CANPacket_t *to_push, uint8_t bus_number, bool skip_tx_hook) {
if (skip_tx_hook || safety_tx_hook(to_push) != 0) {
if (bus_number < PANDA_BUS_CNT) {
// add CAN packet to send queue
if ((bus_number == 3U) && (bus_config[3].can_num_lookup == 0xFFU)) {
gmlan_send_errs += bitbang_gmlan(to_push) ? 0U : 1U;
} else {
tx_buffer_overflow += can_push(can_queues[bus_number], to_push) ? 0U : 1U;
process_can(CAN_NUM_FROM_BUS_NUM(bus_number));
}
tx_buffer_overflow += can_push(can_queues[bus_number], to_push) ? 0U : 1U;
process_can(CAN_NUM_FROM_BUS_NUM(bus_number));
}
} else {
safety_tx_blocked += 1U;
@ -277,10 +266,10 @@ void can_send(CANPacket_t *to_push, uint8_t bus_number, bool skip_tx_hook) {
}
}
bool is_speed_valid(uint32_t speed, const uint32_t *speeds, uint8_t len) {
bool is_speed_valid(uint32_t speed, const uint32_t *all_speeds, uint8_t len) {
bool ret = false;
for (uint8_t i = 0U; i < len; i++) {
if (speeds[i] == speed) {
if (all_speeds[i] == speed) {
ret = true;
}
}

View File

@ -26,8 +26,8 @@ void clock_source_init(void) {
set_gpio_alternate(GPIOB, 15, GPIO_AF1_TIM1);
// Set PWM mode
register_set(&(TIM1->CCMR1), (0b110 << TIM_CCMR1_OC2M_Pos), 0xFFFFU);
register_set(&(TIM1->CCMR2), (0b110 << TIM_CCMR2_OC3M_Pos), 0xFFFFU);
register_set(&(TIM1->CCMR1), (0b110UL << TIM_CCMR1_OC2M_Pos), 0xFFFFU);
register_set(&(TIM1->CCMR2), (0b110UL << TIM_CCMR2_OC3M_Pos), 0xFFFFU);
// Enable output
register_set(&(TIM1->BDTR), TIM_BDTR_MOE, 0xFFFFU);

View File

@ -59,13 +59,13 @@ void fake_siren_init(void) {
register_set(&DMA1_Stream1->PAR, (uint32_t) &(DAC1->DHR8R1), 0xFFFFFFFFU);
DMA1_Stream1->NDTR = sizeof(fake_siren_lut);
register_set(&DMA1_Stream1->FCR, 0U, 0x00000083U);
DMA1_Stream1->CR = (0b11 << DMA_SxCR_PL_Pos);
DMA1_Stream1->CR |= DMA_SxCR_MINC | DMA_SxCR_CIRC | (1 << DMA_SxCR_DIR_Pos);
DMA1_Stream1->CR = (0b11UL << DMA_SxCR_PL_Pos);
DMA1_Stream1->CR |= DMA_SxCR_MINC | DMA_SxCR_CIRC | (1U << DMA_SxCR_DIR_Pos);
// Init trigger timer (around 2.5kHz)
register_set(&TIM7->PSC, 0U, 0xFFFFU);
register_set(&TIM7->ARR, 133U, 0xFFFFU);
register_set(&TIM7->CR2, (0b10 << TIM_CR2_MMS_Pos), TIM_CR2_MMS_Msk);
register_set(&TIM7->CR2, (0b10U << TIM_CR2_MMS_Pos), TIM_CR2_MMS_Msk);
register_set(&TIM7->CR1, TIM_CR1_ARPE | TIM_CR1_URS, 0x088EU);
TIM7->SR = 0U;
TIM7->CR1 |= TIM_CR1_CEN;

View File

@ -67,14 +67,14 @@ void update_can_health_pkt(uint8_t can_number, uint32_t ir_reg) {
FDCANx->IR |= (FDCAN_IR_PED | FDCAN_IR_PEA | FDCAN_IR_EP | FDCAN_IR_BO | FDCAN_IR_RF0L);
can_health[can_number].total_error_cnt += 1U;
// Check for RX FIFO overflow
if ((ir_reg & (FDCAN_IR_RF0L)) != 0) {
if ((ir_reg & (FDCAN_IR_RF0L)) != 0U) {
can_health[can_number].total_rx_lost_cnt += 1U;
}
// Cases:
// 1. while multiplexing between buses 1 and 3 we are getting ACK errors that overwhelm CAN core, by resetting it recovers faster
// 2. H7 gets stuck in bus off recovery state indefinitely
if ((((can_health[can_number].last_error == CAN_ACK_ERROR) || (can_health[can_number].last_data_error == CAN_ACK_ERROR)) && (can_health[can_number].transmit_error_cnt > 127U)) ||
((ir_reg & FDCAN_IR_BO) != 0)) {
((ir_reg & FDCAN_IR_BO) != 0U)) {
can_health[can_number].can_core_reset_cnt += 1U;
can_health[can_number].total_tx_lost_cnt += (FDCAN_TX_FIFO_EL_CNT - (FDCANx->TXFQS & FDCAN_TXFQS_TFFL)); // TX FIFO msgs will be lost after reset
llcan_clear_send(FDCANx);
@ -93,7 +93,7 @@ void process_can(uint8_t can_number) {
FDCANx->IR |= FDCAN_IR_TFE; // Clear Tx FIFO Empty flag
if ((FDCANx->TXFQS & FDCAN_TXFQS_TFQF) == 0) {
if ((FDCANx->TXFQS & FDCAN_TXFQS_TFQF) == 0U) {
CANPacket_t to_send;
if (can_pop(can_queues[bus_number], &to_send)) {
if (can_check_checksum(&to_send)) {
@ -101,7 +101,7 @@ void process_can(uint8_t can_number) {
uint32_t TxFIFOSA = FDCAN_START_ADDRESS + (can_number * FDCAN_OFFSET) + (FDCAN_RX_FIFO_0_EL_CNT * FDCAN_RX_FIFO_0_EL_SIZE);
// get the index of the next TX FIFO element (0 to FDCAN_TX_FIFO_EL_CNT - 1)
uint32_t tx_index = (FDCANx->TXFQS >> FDCAN_TXFQS_TFQPI_Pos) & 0x1F;
uint32_t tx_index = (FDCANx->TXFQS >> FDCAN_TXFQS_TFQPI_Pos) & 0x1FU;
// only send if we have received a packet
canfd_fifo *fifo;
fifo = (canfd_fifo *)(TxFIFOSA + (tx_index * FDCAN_TX_FIFO_EL_SIZE));
@ -126,7 +126,7 @@ void process_can(uint8_t can_number) {
to_push.rejected = 0U;
to_push.extended = to_send.extended;
to_push.addr = to_send.addr;
to_push.bus = to_send.bus;
to_push.bus = bus_number;
to_push.data_len_code = to_send.data_len_code;
(void)memcpy(to_push.data, to_send.data, dlc_to_len[to_push.data_len_code]);
can_set_checksum(&to_push);
@ -153,14 +153,14 @@ void can_rx(uint8_t can_number) {
// Clear all new messages from Rx FIFO 0
FDCANx->IR |= FDCAN_IR_RF0N;
while((FDCANx->RXF0S & FDCAN_RXF0S_F0FL) != 0) {
while((FDCANx->RXF0S & FDCAN_RXF0S_F0FL) != 0U) {
can_health[can_number].total_rx_cnt += 1U;
// can is live
pending_can_live = 1;
// get the index of the next RX FIFO element (0 to FDCAN_RX_FIFO_0_EL_CNT - 1)
uint32_t rx_fifo_idx = (uint8_t)((FDCANx->RXF0S >> FDCAN_RXF0S_F0GI_Pos) & 0x3F);
uint32_t rx_fifo_idx = (uint8_t)((FDCANx->RXF0S >> FDCAN_RXF0S_F0GI_Pos) & 0x3FU);
// Recommended to offset get index by at least +1 if RX FIFO is in overwrite mode and full (datasheet)
if((FDCANx->RXF0S & FDCAN_RXF0S_F0F) == FDCAN_RXF0S_F0F) {
@ -232,7 +232,7 @@ void can_rx(uint8_t can_number) {
}
// Error handling
if ((ir_reg & (FDCAN_IR_PED | FDCAN_IR_PEA | FDCAN_IR_EP | FDCAN_IR_BO | FDCAN_IR_RF0L)) != 0) {
if ((ir_reg & (FDCAN_IR_PED | FDCAN_IR_PEA | FDCAN_IR_EP | FDCAN_IR_BO | FDCAN_IR_RF0L)) != 0U) {
update_can_health_pkt(can_number, ir_reg);
}
}

View File

@ -1,296 +0,0 @@
#define GMLAN_TICKS_PER_SECOND 33300 //1sec @ 33.3kbps
#define GMLAN_TICKS_PER_TIMEOUT_TICKLE 500 //15ms @ 33.3kbps
#define GMLAN_HIGH 0 //0 is high on bus (dominant)
#define GMLAN_LOW 1 //1 is low on bus
#define DISABLED -1
#define BITBANG 0
#define GPIO_SWITCH 1
#define MAX_BITS_CAN_PACKET (200)
int gmlan_alt_mode = DISABLED;
// returns out_len
int do_bitstuff(char *out, const char *in, int in_len) {
int last_bit = -1;
int bit_cnt = 0;
int j = 0;
for (int i = 0; i < in_len; i++) {
char bit = in[i];
out[j] = bit;
j++;
// do the stuffing
if (bit == (char)last_bit) {
bit_cnt++;
if (bit_cnt == 5) {
// 5 in a row the same, do stuff
last_bit = !bit;
out[j] = last_bit;
j++;
bit_cnt = 1;
}
} else {
// this is a new bit
last_bit = bit;
bit_cnt = 1;
}
}
return j;
}
int append_crc(char *in, int in_len) {
unsigned int crc = 0;
for (int i = 0; i < in_len; i++) {
crc <<= 1;
if (((unsigned int)(in[i]) ^ ((crc >> 15) & 1U)) != 0U) {
crc = crc ^ 0x4599U;
}
crc &= 0x7fffU;
}
int in_len_copy = in_len;
for (int i = 14; i >= 0; i--) {
in[in_len_copy] = (crc >> (unsigned int)(i)) & 1U;
in_len_copy++;
}
return in_len_copy;
}
int append_bits(char *in, int in_len, const char *app, int app_len) {
int in_len_copy = in_len;
for (int i = 0; i < app_len; i++) {
in[in_len_copy] = app[i];
in_len_copy++;
}
return in_len_copy;
}
int append_int(char *in, int in_len, int val, int val_len) {
int in_len_copy = in_len;
for (int i = val_len - 1; i >= 0; i--) {
in[in_len_copy] = ((unsigned int)(val) & (1U << (unsigned int)(i))) != 0U;
in_len_copy++;
}
return in_len_copy;
}
int get_bit_message(char *out, const CANPacket_t *to_bang) {
char pkt[MAX_BITS_CAN_PACKET];
char footer[] = {
1, // CRC delimiter
1, // ACK
1, // ACK delimiter
1,1,1,1,1,1,1, // EOF
1,1,1, // IFS
};
int len = 0;
// test packet
int dlc_len = GET_LEN(to_bang);
len = append_int(pkt, len, 0, 1); // Start-of-frame
if (to_bang->extended != 0U) {
// extended identifier
len = append_int(pkt, len, GET_ADDR(to_bang) >> 18, 11); // Identifier
len = append_int(pkt, len, 3, 2); // SRR+IDE
len = append_int(pkt, len, (GET_ADDR(to_bang)) & ((1UL << 18) - 1U), 18); // Identifier
len = append_int(pkt, len, 0, 3); // RTR+r1+r0
} else {
// standard identifier
len = append_int(pkt, len, GET_ADDR(to_bang), 11); // Identifier
len = append_int(pkt, len, 0, 3); // RTR+IDE+reserved
}
len = append_int(pkt, len, dlc_len, 4); // Data length code
// append data
for (int i = 0; i < dlc_len; i++) {
len = append_int(pkt, len, to_bang->data[i], 8);
}
// append crc
len = append_crc(pkt, len);
// do bitstuffing
len = do_bitstuff(out, pkt, len);
// append footer
len = append_bits(out, len, footer, sizeof(footer));
return len;
}
void TIM12_IRQ_Handler(void);
void setup_timer(void) {
// register interrupt
REGISTER_INTERRUPT(TIM8_BRK_TIM12_IRQn, TIM12_IRQ_Handler, 40000U, FAULT_INTERRUPT_RATE_GMLAN)
// setup
register_set(&(TIM12->PSC), (APB1_TIMER_FREQ-1U), 0xFFFFU); // Tick on 1 us
register_set(&(TIM12->CR1), TIM_CR1_CEN, 0x3FU); // Enable
register_set(&(TIM12->ARR), (30U-1U), 0xFFFFU); // 33.3 kbps
// in case it's disabled
NVIC_EnableIRQ(TIM8_BRK_TIM12_IRQn);
// run the interrupt
register_set(&(TIM12->DIER), TIM_DIER_UIE, 0x5F5FU); // Update interrupt
TIM12->SR = 0;
}
int gmlan_timeout_counter = GMLAN_TICKS_PER_TIMEOUT_TICKLE; //GMLAN transceiver times out every 17ms held high; tickle every 15ms
int can_timeout_counter = GMLAN_TICKS_PER_SECOND; //1 second
int inverted_bit_to_send = GMLAN_HIGH;
int gmlan_switch_below_timeout = -1;
int gmlan_switch_timeout_enable = 0;
void gmlan_switch_init(int timeout_enable) {
gmlan_switch_timeout_enable = timeout_enable;
gmlan_alt_mode = GPIO_SWITCH;
gmlan_switch_below_timeout = 1;
set_gpio_mode(GPIOB, 13, MODE_OUTPUT);
setup_timer();
inverted_bit_to_send = GMLAN_LOW; //We got initialized, set the output low
}
void set_gmlan_digital_output(int to_set) {
inverted_bit_to_send = to_set;
/*
print("Writing ");
puth(inverted_bit_to_send);
print("\n");
*/
}
void reset_gmlan_switch_timeout(void) {
can_timeout_counter = GMLAN_TICKS_PER_SECOND;
gmlan_switch_below_timeout = 1;
gmlan_alt_mode = GPIO_SWITCH;
}
void set_bitbanged_gmlan(int val) {
if (val != 0) {
register_set_bits(&(GPIOB->ODR), (1UL << 13));
} else {
register_clear_bits(&(GPIOB->ODR), (1UL << 13));
}
}
char pkt_stuffed[MAX_BITS_CAN_PACKET];
int gmlan_sending = -1;
int gmlan_sendmax = -1;
bool gmlan_send_ok = true;
int gmlan_silent_count = 0;
int gmlan_fail_count = 0;
#define REQUIRED_SILENT_TIME 10
#define MAX_FAIL_COUNT 10
void TIM12_IRQ_Handler(void) {
if (gmlan_alt_mode == BITBANG) {
if ((TIM12->SR & TIM_SR_UIF) && (gmlan_sendmax != -1)) {
int read = get_gpio_input(GPIOB, 12);
if (gmlan_silent_count < REQUIRED_SILENT_TIME) {
if (read == 0) {
gmlan_silent_count = 0;
} else {
gmlan_silent_count++;
}
} else {
bool retry = 0;
// in send loop
if ((gmlan_sending > 0) && // not first bit
((read == 0) && (pkt_stuffed[gmlan_sending-1] == (char)1)) && // bus wrongly dominant
(gmlan_sending != (gmlan_sendmax - 11))) { //not ack bit
print("GMLAN ERR: bus driven at ");
puth(gmlan_sending);
print("\n");
retry = 1;
} else if ((read == 1) && (gmlan_sending == (gmlan_sendmax - 11))) { // recessive during ACK
print("GMLAN ERR: didn't recv ACK\n");
retry = 1;
} else {
// do not retry
}
if (retry) {
// reset sender (retry after 7 silent)
set_bitbanged_gmlan(1); // recessive
gmlan_silent_count = 0;
gmlan_sending = 0;
gmlan_fail_count++;
if (gmlan_fail_count == MAX_FAIL_COUNT) {
print("GMLAN ERR: giving up send\n");
gmlan_send_ok = false;
}
} else {
set_bitbanged_gmlan(pkt_stuffed[gmlan_sending]);
gmlan_sending++;
}
}
if ((gmlan_sending == gmlan_sendmax) || (gmlan_fail_count == MAX_FAIL_COUNT)) {
set_bitbanged_gmlan(1); // recessive
set_gpio_mode(GPIOB, 13, MODE_INPUT);
register_clear_bits(&(TIM12->DIER), TIM_DIER_UIE); // No update interrupt
register_set(&(TIM12->CR1), 0U, 0x3FU); // Disable timer
gmlan_sendmax = -1; // exit
}
}
} else if (gmlan_alt_mode == GPIO_SWITCH) {
if ((TIM12->SR & TIM_SR_UIF) && (gmlan_switch_below_timeout != -1)) {
if ((can_timeout_counter == 0) && gmlan_switch_timeout_enable) {
//it has been more than 1 second since timeout was reset; disable timer and restore the GMLAN output
set_gpio_output(GPIOB, 13, GMLAN_LOW);
gmlan_switch_below_timeout = -1;
gmlan_timeout_counter = GMLAN_TICKS_PER_TIMEOUT_TICKLE;
gmlan_alt_mode = DISABLED;
}
else {
can_timeout_counter--;
if (gmlan_timeout_counter == 0) {
//Send a 1 (bus low) every 15ms to reset the GMLAN transceivers timeout
gmlan_timeout_counter = GMLAN_TICKS_PER_TIMEOUT_TICKLE;
set_gpio_output(GPIOB, 13, GMLAN_LOW);
}
else {
set_gpio_output(GPIOB, 13, inverted_bit_to_send);
gmlan_timeout_counter--;
}
}
}
} else {
// Invalid GMLAN mode. Do not put a print statement here, way too fast to keep up with
}
TIM12->SR = 0;
}
bool bitbang_gmlan(const CANPacket_t *to_bang) {
gmlan_send_ok = true;
gmlan_alt_mode = BITBANG;
#ifdef HW_TYPE_DOS
if (hw_type == HW_TYPE_DOS) {
if (gmlan_sendmax == -1) {
int len = get_bit_message(pkt_stuffed, to_bang);
gmlan_fail_count = 0;
gmlan_silent_count = 0;
gmlan_sending = 0;
gmlan_sendmax = len;
// setup for bitbang loop
set_bitbanged_gmlan(1); // recessive
set_gpio_mode(GPIOB, 13, MODE_OUTPUT);
// 33kbps
setup_timer();
}
}
#else
UNUSED(to_bang);
#endif
return gmlan_send_ok;
}

View File

@ -11,7 +11,7 @@
#define OUTPUT_TYPE_OPEN_DRAIN 1U
typedef struct {
GPIO_TypeDef *bank;
GPIO_TypeDef * const bank;
uint8_t pin;
} gpio_t;
@ -68,13 +68,13 @@ int get_gpio_input(const GPIO_TypeDef *GPIO, unsigned int pin) {
return (GPIO->IDR & (1UL << pin)) == (1UL << pin);
}
void gpio_set_all_output(const gpio_t *pins, uint8_t num_pins, bool enabled) {
void gpio_set_all_output(gpio_t *pins, uint8_t num_pins, bool enabled) {
for (uint8_t i = 0; i < num_pins; i++) {
set_gpio_output(pins[i].bank, pins[i].pin, enabled);
}
}
void gpio_set_bitmask(const gpio_t *pins, uint8_t num_pins, uint32_t bitmask) {
void gpio_set_bitmask(gpio_t *pins, uint8_t num_pins, uint32_t bitmask) {
for (uint8_t i = 0; i < num_pins; i++) {
set_gpio_output(pins[i].bank, pins[i].pin, (bitmask >> i) & 1U);
}

View File

@ -13,16 +13,16 @@ struct harness_t harness;
struct harness_configuration {
const bool has_harness;
GPIO_TypeDef *GPIO_SBU1;
GPIO_TypeDef *GPIO_SBU2;
GPIO_TypeDef *GPIO_relay_SBU1;
GPIO_TypeDef *GPIO_relay_SBU2;
uint8_t pin_SBU1;
uint8_t pin_SBU2;
uint8_t pin_relay_SBU1;
uint8_t pin_relay_SBU2;
uint8_t adc_channel_SBU1;
uint8_t adc_channel_SBU2;
GPIO_TypeDef * const GPIO_SBU1;
GPIO_TypeDef * const GPIO_SBU2;
GPIO_TypeDef * const GPIO_relay_SBU1;
GPIO_TypeDef * const GPIO_relay_SBU2;
const uint8_t pin_SBU1;
const uint8_t pin_SBU2;
const uint8_t pin_relay_SBU1;
const uint8_t pin_relay_SBU2;
const uint8_t adc_channel_SBU1;
const uint8_t adc_channel_SBU2;
};
// The ignition relay is only used for testing purposes
@ -95,6 +95,7 @@ uint8_t harness_detect_orientation(void) {
ret = HARNESS_STATUS_FLIPPED;
} else {
// orientation normal (PANDA_SBU2->HARNESS_SBU1(relay), PANDA_SBU1->HARNESS_SBU2(ign))
// (SBU1->SBU2 is the normal orientation connection per USB-C cable spec)
ret = HARNESS_STATUS_NORMAL;
}
} else {
@ -116,11 +117,6 @@ void harness_tick(void) {
}
void harness_init(void) {
// delay such that the connection is fully made before trying orientation detection
current_board->set_led(LED_BLUE, true);
delay(10000000);
current_board->set_led(LED_BLUE, false);
// try to detect orientation
harness.status = harness_detect_orientation();
if (harness.status != HARNESS_STATUS_NC) {

View File

@ -64,7 +64,7 @@ void handle_interrupt(IRQn_Type irq_type){
// Every second
void interrupt_timer_handler(void) {
if (INTERRUPT_TIMER->SR != 0) {
if (INTERRUPT_TIMER->SR != 0U) {
for (uint16_t i = 0U; i < NUM_INTERRUPTS; i++) {
// Log IRQ call rate faults
if (check_interrupt_rate && (interrupts[i].call_counter > interrupts[i].max_call_rate)) {
@ -78,8 +78,8 @@ void interrupt_timer_handler(void) {
// Calculate interrupt load
// The bootstub does not have the FPU enabled, so can't do float operations.
#if !defined(PEDAL) && !defined(BOOTSTUB)
interrupt_load = ((busy_time + idle_time) > 0U) ? ((float) busy_time) / (busy_time + idle_time) : 0.0f;
#if !defined(BOOTSTUB)
interrupt_load = ((busy_time + idle_time) > 0U) ? ((float) (((float) busy_time) / (busy_time + idle_time))) : 0.0f;
#endif
idle_time = 0U;
busy_time = 0U;

View File

@ -1,79 +0,0 @@
#define YEAR_OFFSET 2000U
typedef struct __attribute__((packed)) timestamp_t {
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t weekday;
uint8_t hour;
uint8_t minute;
uint8_t second;
} timestamp_t;
uint8_t to_bcd(uint16_t value){
return (((value / 10U) & 0x0FU) << 4U) | ((value % 10U) & 0x0FU);
}
uint16_t from_bcd(uint8_t value){
return (((value & 0xF0U) >> 4U) * 10U) + (value & 0x0FU);
}
void rtc_set_time(timestamp_t time){
print("Setting RTC time\n");
// Disable write protection
disable_bdomain_protection();
RTC->WPR = 0xCA;
RTC->WPR = 0x53;
// Enable initialization mode
register_set_bits(&(RTC->ISR), RTC_ISR_INIT);
while((RTC->ISR & RTC_ISR_INITF) == 0){}
// Set time
RTC->TR = (to_bcd(time.hour) << RTC_TR_HU_Pos) | (to_bcd(time.minute) << RTC_TR_MNU_Pos) | (to_bcd(time.second) << RTC_TR_SU_Pos);
RTC->DR = (to_bcd(time.year - YEAR_OFFSET) << RTC_DR_YU_Pos) | (time.weekday << RTC_DR_WDU_Pos) | (to_bcd(time.month) << RTC_DR_MU_Pos) | (to_bcd(time.day) << RTC_DR_DU_Pos);
// Set options
register_set(&(RTC->CR), 0U, 0xFCFFFFU);
// Disable initalization mode
register_clear_bits(&(RTC->ISR), RTC_ISR_INIT);
// Wait for synchronization
while((RTC->ISR & RTC_ISR_RSF) == 0){}
// Re-enable write protection
RTC->WPR = 0x00;
enable_bdomain_protection();
}
timestamp_t rtc_get_time(void){
timestamp_t result;
// Init with zero values in case there is no RTC running
result.year = 0U;
result.month = 0U;
result.day = 0U;
result.weekday = 0U;
result.hour = 0U;
result.minute = 0U;
result.second = 0U;
// Wait until the register sync flag is set
while((RTC->ISR & RTC_ISR_RSF) == 0){}
// Read time and date registers. Since our HSE > 7*LSE, this should be fine.
uint32_t time = RTC->TR;
uint32_t date = RTC->DR;
// Parse values
result.year = from_bcd((date & (RTC_DR_YT | RTC_DR_YU)) >> RTC_DR_YU_Pos) + YEAR_OFFSET;
result.month = from_bcd((date & (RTC_DR_MT | RTC_DR_MU)) >> RTC_DR_MU_Pos);
result.day = from_bcd((date & (RTC_DR_DT | RTC_DR_DU)) >> RTC_DR_DU_Pos);
result.weekday = ((date & RTC_DR_WDU) >> RTC_DR_WDU_Pos);
result.hour = from_bcd((time & (RTC_TR_HT | RTC_TR_HU)) >> RTC_TR_HU_Pos);
result.minute = from_bcd((time & (RTC_TR_MNT | RTC_TR_MNU)) >> RTC_TR_MNU_Pos);
result.second = from_bcd((time & (RTC_TR_ST | RTC_TR_SU)) >> RTC_TR_SU_Pos);
return result;
}

View File

@ -73,10 +73,8 @@ uint16_t spi_version_packet(uint8_t *out) {
uint16_t data_pos = 7U + 2U;
// write serial
#ifdef UID_BASE
(void)memcpy(&out[data_pos], ((uint8_t *)UID_BASE), 12);
data_len += 12U;
#endif
// HW type
out[data_pos + data_len] = hw_type;
@ -232,7 +230,7 @@ void spi_rx_done(void) {
llspi_miso_dma(spi_buf_tx, response_len);
spi_state = next_rx_state;
if (!checksum_valid && (spi_checksum_error_count < __UINT16_MAX__)) {
if (!checksum_valid && (spi_checksum_error_count < UINT16_MAX)) {
spi_checksum_error_count += 1U;
}
}

View File

@ -129,21 +129,6 @@ bool put_char(uart_ring *q, char elem) {
return ret;
}
// Seems dangerous to use (might lock CPU if called with interrupts disabled f.e.)
// TODO: Remove? Not used anyways
void uart_flush(const uart_ring *q) {
while (q->w_ptr_tx != q->r_ptr_tx) {
__WFI();
}
}
void uart_flush_sync(uart_ring *q) {
// empty the TX buffer
while (q->w_ptr_tx != q->r_ptr_tx) {
uart_tx_ring(q);
}
}
void clear_uart_buff(uart_ring *q) {
ENTER_CRITICAL();
q->w_ptr_tx = 0;

View File

@ -79,7 +79,7 @@ void refresh_can_tx_slots_available(void);
#define STS_SETUP_COMP 4
#define STS_SETUP_UPDT 6
uint8_t resp[USBPACKET_MAX_SIZE];
uint8_t response[USBPACKET_MAX_SIZE];
// for the repeating interfaces
#define DSCR_INTERFACE_LEN 9
@ -198,13 +198,8 @@ uint16_t string_product_desc[] = {
// default serial number when we're not a panda
uint16_t string_serial_desc[] = {
#ifdef PEDAL
STRING_DESCRIPTOR_HEADER(5),
'p', 'e', 'd', 'a', 'l'
#else
STRING_DESCRIPTOR_HEADER(4),
'n', 'o', 'n', 'e'
#endif
};
// a string containing the default configuration index
@ -309,13 +304,6 @@ uint8_t binary_object_store_desc[] = {
MS_VENDOR_CODE, 0x00 // vendor code, no alternate enumeration
};
uint8_t webusb_url_descriptor[] = {
0x14, /* bLength */
WEBUSB_DESC_TYPE_URL, // bDescriptorType
WEBUSB_URL_SCHEME_HTTPS, // bScheme
'u', 's', 'b', 'p', 'a', 'n', 'd', 'a', '.', 'c', 'o', 'm', 'm', 'a', '.', 'a', 'i'
};
// WinUSB 2.0 descriptor. This is what modern systems use
// https://github.com/sowbug/weblight/blob/192ad7a0e903542e2aa28c607d98254a12a6399d/firmware/webusb.c
// http://janaxelson.com/files/ms_os_20_descriptors.c
@ -369,10 +357,10 @@ int current_int0_alt_setting = 0;
void *USB_ReadPacket(void *dest, uint16_t len) {
uint32_t *dest_copy = (uint32_t *)dest;
uint32_t count32b = (len + 3U) / 4U;
uint32_t count32b = ((uint32_t)len + 3U) / 4U;
for (uint32_t i = 0; i < count32b; i++) {
*dest_copy = USBx_DFIFO(0);
*dest_copy = USBx_DFIFO(0U);
dest_copy++;
}
return ((void *)dest_copy);
@ -384,9 +372,9 @@ void USB_WritePacket(const void *src, uint16_t len, uint32_t ep) {
hexdump(src, len);
#endif
uint32_t numpacket = (len + (USBPACKET_MAX_SIZE - 1U)) / USBPACKET_MAX_SIZE;
uint32_t numpacket = ((uint32_t)len + (USBPACKET_MAX_SIZE - 1U)) / USBPACKET_MAX_SIZE;
uint32_t count32b = 0;
count32b = (len + 3U) / 4U;
count32b = ((uint32_t)len + 3U) / 4U;
// TODO: revisit this
USBx_INEP(ep)->DIEPTSIZ = ((numpacket << 19) & USB_OTG_DIEPTSIZ_PKTCNT) |
@ -419,7 +407,7 @@ void USB_WritePacket_EP0(uint8_t *src, uint16_t len) {
ep0_txlen = len - wplen;
USBx_DEVICE->DIEPEMPMSK |= 1;
} else {
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
}
}
@ -436,8 +424,8 @@ void usb_reset(void) {
USBx_DEVICE->DOEPMSK = 0xFFFFFFFFU;
// clear interrupts
USBx_INEP(0)->DIEPINT = 0xFF;
USBx_OUTEP(0)->DOEPINT = 0xFF;
USBx_INEP(0U)->DIEPINT = 0xFF;
USBx_OUTEP(0U)->DOEPINT = 0xFF;
// unset the address
USBx_DEVICE->DCFG &= ~USB_OTG_DCFG_DAD;
@ -463,15 +451,15 @@ void usb_reset(void) {
USBx_DEVICE->DCTL |= USB_OTG_DCTL_CGINAK;
// ready to receive setup packets
USBx_OUTEP(0)->DOEPTSIZ = USB_OTG_DOEPTSIZ_STUPCNT | (USB_OTG_DOEPTSIZ_PKTCNT & (1UL << 19)) | (3U << 3);
USBx_OUTEP(0U)->DOEPTSIZ = USB_OTG_DOEPTSIZ_STUPCNT | (USB_OTG_DOEPTSIZ_PKTCNT & (1UL << 19)) | (3U << 3);
}
char to_hex_char(int a) {
char to_hex_char(uint8_t a) {
char ret;
if (a < 10) {
if (a < 10U) {
ret = '0' + a;
} else {
ret = 'a' + (a - 10);
ret = 'a' + (a - 10U);
}
return ret;
}
@ -490,26 +478,26 @@ void usb_setup(void) {
switch (setup.b.bRequest) {
case USB_REQ_SET_CONFIGURATION:
// enable other endpoints, has to be here?
USBx_INEP(1)->DIEPCTL = (0x40U & USB_OTG_DIEPCTL_MPSIZ) | (2UL << 18) | (1UL << 22) |
USBx_INEP(1U)->DIEPCTL = (0x40U & USB_OTG_DIEPCTL_MPSIZ) | (2UL << 18) | (1UL << 22) |
USB_OTG_DIEPCTL_SD0PID_SEVNFRM | USB_OTG_DIEPCTL_USBAEP;
USBx_INEP(1)->DIEPINT = 0xFF;
USBx_INEP(1U)->DIEPINT = 0xFF;
USBx_OUTEP(2)->DOEPTSIZ = (1UL << 19) | 0x40U;
USBx_OUTEP(2)->DOEPCTL = (0x40U & USB_OTG_DOEPCTL_MPSIZ) | (2UL << 18) |
USBx_OUTEP(2U)->DOEPTSIZ = (1UL << 19) | 0x40U;
USBx_OUTEP(2U)->DOEPCTL = (0x40U & USB_OTG_DOEPCTL_MPSIZ) | (2UL << 18) |
USB_OTG_DOEPCTL_SD0PID_SEVNFRM | USB_OTG_DOEPCTL_USBAEP;
USBx_OUTEP(2)->DOEPINT = 0xFF;
USBx_OUTEP(2U)->DOEPINT = 0xFF;
USBx_OUTEP(3)->DOEPTSIZ = (32UL << 19) | 0x800U;
USBx_OUTEP(3)->DOEPCTL = (0x40U & USB_OTG_DOEPCTL_MPSIZ) | (2UL << 18) |
USBx_OUTEP(3U)->DOEPTSIZ = (32UL << 19) | 0x800U;
USBx_OUTEP(3U)->DOEPCTL = (0x40U & USB_OTG_DOEPCTL_MPSIZ) | (2UL << 18) |
USB_OTG_DOEPCTL_SD0PID_SEVNFRM | USB_OTG_DOEPCTL_USBAEP;
USBx_OUTEP(3)->DOEPINT = 0xFF;
USBx_OUTEP(3U)->DOEPINT = 0xFF;
// mark ready to receive
USBx_OUTEP(2)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(3)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(2U)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(3U)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
USB_WritePacket(0, 0, 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
case USB_REQ_SET_ADDRESS:
// set now?
@ -520,7 +508,7 @@ void usb_setup(void) {
#endif
USB_WritePacket(0, 0, 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
case USB_REQ_GET_DESCRIPTOR:
@ -532,17 +520,17 @@ void usb_setup(void) {
device_desc[13] = hw_type;
// setup transfer
USB_WritePacket(device_desc, MIN(sizeof(device_desc), setup.b.wLength.w), 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
//print("D");
break;
case USB_DESC_TYPE_CONFIGURATION:
USB_WritePacket(configuration_desc, MIN(sizeof(configuration_desc), setup.b.wLength.w), 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
case USB_DESC_TYPE_DEVICE_QUALIFIER:
USB_WritePacket(device_qualifier, MIN(sizeof(device_qualifier), setup.b.wLength.w), 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
case USB_DESC_TYPE_STRING:
switch (setup.b.wValue.bw.msb) {
@ -556,23 +544,19 @@ void usb_setup(void) {
USB_WritePacket((uint8_t*)string_product_desc, MIN(sizeof(string_product_desc), setup.b.wLength.w), 0);
break;
case STRING_OFFSET_ISERIAL:
#ifdef UID_BASE
resp[0] = 0x02 + (12 * 4);
resp[1] = 0x03;
response[0] = 0x02 + (12 * 4);
response[1] = 0x03;
// 96 bits = 12 bytes
for (int i = 0; i < 12; i++){
uint8_t cc = ((uint8_t *)UID_BASE)[i];
resp[2 + (i * 4)] = to_hex_char((cc >> 4) & 0xFU);
resp[2 + (i * 4) + 1] = '\0';
resp[2 + (i * 4) + 2] = to_hex_char((cc >> 0) & 0xFU);
resp[2 + (i * 4) + 3] = '\0';
}
// 96 bits = 12 bytes
for (int i = 0; i < 12; i++){
uint8_t cc = ((uint8_t *)UID_BASE)[i];
response[2 + (i * 4)] = to_hex_char((cc >> 4) & 0xFU);
response[2 + (i * 4) + 1] = '\0';
response[2 + (i * 4) + 2] = to_hex_char((cc >> 0) & 0xFU);
response[2 + (i * 4) + 3] = '\0';
}
USB_WritePacket(resp, MIN(resp[0], setup.b.wLength.w), 0);
#else
USB_WritePacket((const uint8_t *)string_serial_desc, MIN(sizeof(string_serial_desc), setup.b.wLength.w), 0);
#endif
USB_WritePacket(response, MIN(response[0], setup.b.wLength.w), 0);
break;
case STRING_OFFSET_ICONFIGURATION:
USB_WritePacket((uint8_t*)string_configuration_desc, MIN(sizeof(string_configuration_desc), setup.b.wLength.w), 0);
@ -585,44 +569,36 @@ void usb_setup(void) {
USB_WritePacket(0, 0, 0);
break;
}
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
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;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
default:
// nothing here?
USB_WritePacket(0, 0, 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
}
break;
case USB_REQ_GET_STATUS:
// empty resp?
resp[0] = 0;
resp[1] = 0;
USB_WritePacket((void*)&resp, 2, 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
// empty response?
response[0] = 0;
response[1] = 0;
USB_WritePacket((void*)&response, 2, 0);
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
case USB_REQ_SET_INTERFACE:
// Store the alt setting number for IN EP behavior.
current_int0_alt_setting = setup.b.wValue.w;
USB_WritePacket(0, 0, 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
case WEBUSB_VENDOR_CODE:
switch (setup.b.wIndex.w) {
case WEBUSB_REQ_GET_URL:
USB_WritePacket(webusb_url_descriptor, MIN(sizeof(webusb_url_descriptor), setup.b.wLength.w), 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
default:
// probably asking for allowed origins, which was removed from the spec
USB_WritePacket(0, 0, 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
}
// probably asking for allowed origins, which was removed from the spec
USB_WritePacket(0, 0, 0);
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
case MS_VENDOR_CODE:
switch (setup.b.wIndex.w) {
@ -648,11 +624,11 @@ void usb_setup(void) {
control_req.param2 = setup.b.wIndex.w;
control_req.length = setup.b.wLength.w;
resp_len = comms_control_handler(&control_req, resp);
resp_len = comms_control_handler(&control_req, response);
// response pending if -1 was returned
if (resp_len != -1) {
USB_WritePacket(resp, MIN(resp_len, setup.b.wLength.w), 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USB_WritePacket(response, MIN(resp_len, setup.b.wLength.w), 0);
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
}
}
}
@ -680,23 +656,23 @@ void usb_irqhandler(void) {
print(" USB interrupt!\n");
#endif
if ((gintsts & USB_OTG_GINTSTS_CIDSCHG) != 0) {
if ((gintsts & USB_OTG_GINTSTS_CIDSCHG) != 0U) {
print("connector ID status change\n");
}
if ((gintsts & USB_OTG_GINTSTS_USBRST) != 0) {
if ((gintsts & USB_OTG_GINTSTS_USBRST) != 0U) {
print("USB reset\n");
usb_reset();
}
if ((gintsts & USB_OTG_GINTSTS_ENUMDNE) != 0) {
if ((gintsts & USB_OTG_GINTSTS_ENUMDNE) != 0U) {
print("enumeration done");
// Full speed, ENUMSPD
//puth(USBx_DEVICE->DSTS);
print("\n");
}
if ((gintsts & USB_OTG_GINTSTS_OTGINT) != 0) {
if ((gintsts & USB_OTG_GINTSTS_OTGINT) != 0U) {
print("OTG int:");
puth(USBx->GOTGINT);
print("\n");
@ -706,7 +682,7 @@ void usb_irqhandler(void) {
}
// RX FIFO first
if ((gintsts & USB_OTG_GINTSTS_RXFLVL) != 0) {
if ((gintsts & USB_OTG_GINTSTS_RXFLVL) != 0U) {
// 1. Read the Receive status pop register
volatile unsigned int rxst = USBx->GRXSTSP;
int status = (rxst & USB_OTG_GRXSTSP_PKTSTS) >> 17;
@ -772,7 +748,7 @@ void usb_irqhandler(void) {
USBx_DEVICE->DCTL |= USB_OTG_DCTL_CGONAK | USB_OTG_DCTL_CGINAK;
}
if ((gintsts & USB_OTG_GINTSTS_SRQINT) != 0) {
if ((gintsts & USB_OTG_GINTSTS_SRQINT) != 0U) {
// we want to do "A-device host negotiation protocol" since we are the A-device
/*print("start request\n");
puth(USBx->GOTGCTL);
@ -783,76 +759,76 @@ void usb_irqhandler(void) {
}
// out endpoint hit
if ((gintsts & USB_OTG_GINTSTS_OEPINT) != 0) {
if ((gintsts & USB_OTG_GINTSTS_OEPINT) != 0U) {
#ifdef DEBUG_USB
print(" 0:");
puth(USBx_OUTEP(0)->DOEPINT);
puth(USBx_OUTEP(0U)->DOEPINT);
print(" 2:");
puth(USBx_OUTEP(2)->DOEPINT);
puth(USBx_OUTEP(2U)->DOEPINT);
print(" 3:");
puth(USBx_OUTEP(3)->DOEPINT);
puth(USBx_OUTEP(3U)->DOEPINT);
print(" ");
puth(USBx_OUTEP(3)->DOEPCTL);
puth(USBx_OUTEP(3U)->DOEPCTL);
print(" 4:");
puth(USBx_OUTEP(4)->DOEPINT);
print(" OUT ENDPOINT\n");
#endif
if ((USBx_OUTEP(2)->DOEPINT & USB_OTG_DOEPINT_XFRC) != 0) {
if ((USBx_OUTEP(2U)->DOEPINT & USB_OTG_DOEPINT_XFRC) != 0U) {
#ifdef DEBUG_USB
print(" OUT2 PACKET XFRC\n");
#endif
USBx_OUTEP(2)->DOEPTSIZ = (1UL << 19) | 0x40U;
USBx_OUTEP(2)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(2U)->DOEPTSIZ = (1UL << 19) | 0x40U;
USBx_OUTEP(2U)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
}
if ((USBx_OUTEP(3)->DOEPINT & USB_OTG_DOEPINT_XFRC) != 0) {
if ((USBx_OUTEP(3U)->DOEPINT & USB_OTG_DOEPINT_XFRC) != 0U) {
#ifdef DEBUG_USB
print(" OUT3 PACKET XFRC\n");
#endif
// NAK cleared by process_can (if tx buffers have room)
outep3_processing = false;
refresh_can_tx_slots_available();
} else if ((USBx_OUTEP(3)->DOEPINT & 0x2000) != 0) {
} else if ((USBx_OUTEP(3U)->DOEPINT & 0x2000U) != 0U) {
#ifdef DEBUG_USB
print(" OUT3 PACKET WTF\n");
#endif
// if NAK was set trigger this, unknown interrupt
// TODO: why was this here? fires when TX buffers when we can't clear NAK
// USBx_OUTEP(3)->DOEPTSIZ = (1U << 19) | 0x40U;
// USBx_OUTEP(3)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
} else if ((USBx_OUTEP(3)->DOEPINT) != 0) {
// USBx_OUTEP(3U)->DOEPTSIZ = (1U << 19) | 0x40U;
// USBx_OUTEP(3U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
} else if ((USBx_OUTEP(3U)->DOEPINT) != 0U) {
#ifdef DEBUG_USB
print("OUTEP3 error ");
puth(USBx_OUTEP(3)->DOEPINT);
puth(USBx_OUTEP(3U)->DOEPINT);
print("\n");
#endif
} else {
// USBx_OUTEP(3)->DOEPINT is 0, ok to skip
// USBx_OUTEP(3U)->DOEPINT is 0, ok to skip
}
if ((USBx_OUTEP(0)->DOEPINT & USB_OTG_DIEPINT_XFRC) != 0) {
if ((USBx_OUTEP(0U)->DOEPINT & USB_OTG_DIEPINT_XFRC) != 0U) {
// ready for next packet
USBx_OUTEP(0)->DOEPTSIZ = USB_OTG_DOEPTSIZ_STUPCNT | (USB_OTG_DOEPTSIZ_PKTCNT & (1UL << 19)) | (1U << 3);
USBx_OUTEP(0U)->DOEPTSIZ = USB_OTG_DOEPTSIZ_STUPCNT | (USB_OTG_DOEPTSIZ_PKTCNT & (1UL << 19)) | (1U << 3);
}
// respond to setup packets
if ((USBx_OUTEP(0)->DOEPINT & USB_OTG_DOEPINT_STUP) != 0) {
if ((USBx_OUTEP(0U)->DOEPINT & USB_OTG_DOEPINT_STUP) != 0U) {
usb_setup();
}
USBx_OUTEP(0)->DOEPINT = USBx_OUTEP(0)->DOEPINT;
USBx_OUTEP(2)->DOEPINT = USBx_OUTEP(2)->DOEPINT;
USBx_OUTEP(3)->DOEPINT = USBx_OUTEP(3)->DOEPINT;
USBx_OUTEP(0U)->DOEPINT = USBx_OUTEP(0U)->DOEPINT;
USBx_OUTEP(2U)->DOEPINT = USBx_OUTEP(2U)->DOEPINT;
USBx_OUTEP(3U)->DOEPINT = USBx_OUTEP(3U)->DOEPINT;
}
// interrupt endpoint hit (Page 1221)
if ((gintsts & USB_OTG_GINTSTS_IEPINT) != 0) {
if ((gintsts & USB_OTG_GINTSTS_IEPINT) != 0U) {
#ifdef DEBUG_USB
print(" ");
puth(USBx_INEP(0)->DIEPINT);
puth(USBx_INEP(0U)->DIEPINT);
print(" ");
puth(USBx_INEP(1)->DIEPINT);
puth(USBx_INEP(1U)->DIEPINT);
print(" IN ENDPOINT\n");
#endif
@ -872,25 +848,25 @@ void usb_irqhandler(void) {
switch (current_int0_alt_setting) {
case 0: ////// Bulk config
// *** IN token received when TxFIFO is empty
if ((USBx_INEP(1)->DIEPINT & USB_OTG_DIEPMSK_ITTXFEMSK) != 0) {
if ((USBx_INEP(1U)->DIEPINT & USB_OTG_DIEPMSK_ITTXFEMSK) != 0U) {
#ifdef DEBUG_USB
print(" IN PACKET QUEUE\n");
#endif
// TODO: always assuming max len, can we get the length?
USB_WritePacket((void *)resp, comms_can_read(resp, 0x40), 1);
USB_WritePacket((void *)response, comms_can_read(response, 0x40), 1);
}
break;
case 1: ////// Interrupt config
// *** IN token received when TxFIFO is empty
if ((USBx_INEP(1)->DIEPINT & USB_OTG_DIEPMSK_ITTXFEMSK) != 0) {
if ((USBx_INEP(1U)->DIEPINT & USB_OTG_DIEPMSK_ITTXFEMSK) != 0U) {
#ifdef DEBUG_USB
print(" IN PACKET QUEUE\n");
#endif
// TODO: always assuming max len, can we get the length?
int len = comms_can_read(resp, 0x40);
int len = comms_can_read(response, 0x40);
if (len > 0) {
USB_WritePacket((void *)resp, len, 1);
USB_WritePacket((void *)response, len, 1);
}
}
break;
@ -899,12 +875,12 @@ void usb_irqhandler(void) {
break;
}
if ((USBx_INEP(0)->DIEPINT & USB_OTG_DIEPMSK_ITTXFEMSK) != 0) {
if ((USBx_INEP(0U)->DIEPINT & USB_OTG_DIEPMSK_ITTXFEMSK) != 0U) {
#ifdef DEBUG_USB
print(" IN PACKET QUEUE\n");
#endif
if ((ep0_txlen != 0U) && ((USBx_INEP(0)->DTXFSTS & USB_OTG_DTXFSTS_INEPTFSAV) >= 0x40U)) {
if ((ep0_txlen != 0U) && ((USBx_INEP(0U)->DTXFSTS & USB_OTG_DTXFSTS_INEPTFSAV) >= 0x40U)) {
uint16_t len = MIN(ep0_txlen, 0x40);
USB_WritePacket(ep0_txdata, len, 0);
ep0_txdata = &ep0_txdata[len];
@ -912,14 +888,14 @@ void usb_irqhandler(void) {
if (ep0_txlen == 0U) {
ep0_txdata = NULL;
USBx_DEVICE->DIEPEMPMSK &= ~1;
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
}
}
}
// clear interrupts
USBx_INEP(0)->DIEPINT = USBx_INEP(0)->DIEPINT; // Why ep0?
USBx_INEP(1)->DIEPINT = USBx_INEP(1)->DIEPINT;
USBx_INEP(0U)->DIEPINT = USBx_INEP(0U)->DIEPINT; // Why ep0?
USBx_INEP(1U)->DIEPINT = USBx_INEP(1U)->DIEPINT;
}
// clear all interrupts we handled
@ -932,9 +908,9 @@ void usb_irqhandler(void) {
void can_tx_comms_resume_usb(void) {
ENTER_CRITICAL();
if (!outep3_processing && (USBx_OUTEP(3)->DOEPCTL & USB_OTG_DOEPCTL_NAKSTS) != 0) {
USBx_OUTEP(3)->DOEPTSIZ = (32UL << 19) | 0x800U;
USBx_OUTEP(3)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
if (!outep3_processing && (USBx_OUTEP(3U)->DOEPCTL & USB_OTG_DOEPCTL_NAKSTS) != 0U) {
USBx_OUTEP(3U)->DOEPTSIZ = (32UL << 19) | 0x800U;
USBx_OUTEP(3U)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
}
EXIT_CRITICAL();
}

View File

@ -1,9 +1,3 @@
// TODO: why doesn't it define these?
#ifdef STM32F2
#define IWDG_PR_PR_Msk 0x7U
#define IWDG_RLR_RL_Msk 0xFFFU
#endif
typedef enum {
WATCHDOG_50_MS = (400U - 1U),
WATCHDOG_500_MS = 4000U,

View File

@ -9,7 +9,7 @@
#define FAULT_INTERRUPT_RATE_CAN_2 (1UL << 3)
#define FAULT_INTERRUPT_RATE_CAN_3 (1UL << 4)
#define FAULT_INTERRUPT_RATE_TACH (1UL << 5)
#define FAULT_INTERRUPT_RATE_GMLAN (1UL << 6)
#define FAULT_INTERRUPT_RATE_GMLAN (1UL << 6) // deprecated
#define FAULT_INTERRUPT_RATE_INTERRUPTS (1UL << 7)
#define FAULT_INTERRUPT_RATE_SPI_DMA (1UL << 8)
#define FAULT_INTERRUPT_RATE_SPI_CS (1UL << 9)

View File

@ -15,3 +15,4 @@ if __name__ == "__main__":
print("flashing", s)
with Panda(serial=s) as p:
p.flash()
exit(1 if len(serials) == 0 else 0)

View File

@ -4,10 +4,6 @@ bool unlocked = false;
void spi_init(void);
#ifdef uart_ring
void debug_ring_callback(uart_ring *ring) {}
#endif
int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
int resp_len = 0;
@ -50,23 +46,19 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
break;
// **** 0xc3: fetch MCU UID
case 0xc3:
#ifdef UID_BASE
(void)memcpy(resp, ((uint8_t *)UID_BASE), 12);
resp_len = 12;
#endif
(void)memcpy(resp, ((uint8_t *)UID_BASE), 12);
resp_len = 12;
break;
// **** 0xd0: fetch serial number
case 0xd0:
#ifndef STM32F2
// addresses are OTP
if (req->param1 == 1) {
memcpy(resp, (void *)DEVICE_SERIAL_NUMBER_ADDRESS, 0x10);
resp_len = 0x10;
} else {
get_provision_chunk(resp);
resp_len = PROVISION_CHUNK_LEN;
}
#endif
// addresses are OTP
if (req->param1 == 1) {
memcpy(resp, (void *)DEVICE_SERIAL_NUMBER_ADDRESS, 0x10);
resp_len = 0x10;
} else {
get_provision_chunk(resp);
resp_len = PROVISION_CHUNK_LEN;
}
break;
// **** 0xd1: enter bootloader mode
case 0xd1:
@ -124,172 +116,13 @@ void comms_endpoint2_write(const uint8_t *data, uint32_t len) {
}
int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) {
UNUSED(len);
ControlPacket_t control_req;
int resp_len = 0;
switch (data[0]) {
case 0:
// control transfer
control_req.request = ((USB_Setup_TypeDef *)(data+4))->b.bRequest;
control_req.param1 = ((USB_Setup_TypeDef *)(data+4))->b.wValue.w;
control_req.param2 = ((USB_Setup_TypeDef *)(data+4))->b.wIndex.w;
control_req.length = ((USB_Setup_TypeDef *)(data+4))->b.wLength.w;
resp_len = comms_control_handler(&control_req, data_out);
break;
case 2:
// ep 2, flash!
comms_endpoint2_write(data+4, data[2]);
break;
}
return resp_len;
}
#ifdef PEDAL
#include "stm32fx/llbxcan.h"
#define CANx CAN1
#define CAN_BL_INPUT 0x1
#define CAN_BL_OUTPUT 0x2
void CAN1_TX_IRQ_Handler(void) {
// clear interrupt
CANx->TSR |= CAN_TSR_RQCP0;
}
#define ISOTP_BUF_SIZE 0x110
uint8_t isotp_buf[ISOTP_BUF_SIZE];
uint8_t *isotp_buf_ptr = NULL;
int isotp_buf_remain = 0;
uint8_t isotp_buf_out[ISOTP_BUF_SIZE];
uint8_t *isotp_buf_out_ptr = NULL;
int isotp_buf_out_remain = 0;
int isotp_buf_out_idx = 0;
void bl_can_send(uint8_t *odat) {
// wait for send
while (!(CANx->TSR & CAN_TSR_TME0));
// send continue
CANx->sTxMailBox[0].TDLR = ((uint32_t*)odat)[0];
CANx->sTxMailBox[0].TDHR = ((uint32_t*)odat)[1];
CANx->sTxMailBox[0].TDTR = 8;
CANx->sTxMailBox[0].TIR = (CAN_BL_OUTPUT << 21) | 1;
}
void CAN1_RX0_IRQ_Handler(void) {
while (CANx->RF0R & CAN_RF0R_FMP0) {
if ((CANx->sFIFOMailBox[0].RIR>>21) == CAN_BL_INPUT) {
uint8_t dat[8];
for (int i = 0; i < 8; i++) {
dat[i] = GET_MAILBOX_BYTE(&CANx->sFIFOMailBox[0], i);
}
uint8_t odat[8];
uint8_t type = dat[0] & 0xF0;
if (type == 0x30) {
// continue
while (isotp_buf_out_remain > 0) {
// wait for send
while (!(CANx->TSR & CAN_TSR_TME0));
odat[0] = 0x20 | isotp_buf_out_idx;
memcpy(odat+1, isotp_buf_out_ptr, 7);
isotp_buf_out_remain -= 7;
isotp_buf_out_ptr += 7;
isotp_buf_out_idx++;
bl_can_send(odat);
}
} else if (type == 0x20) {
if (isotp_buf_remain > 0) {
memcpy(isotp_buf_ptr, dat+1, 7);
isotp_buf_ptr += 7;
isotp_buf_remain -= 7;
}
if (isotp_buf_remain <= 0) {
int len = isotp_buf_ptr - isotp_buf + isotp_buf_remain;
// call the function
memset(isotp_buf_out, 0, ISOTP_BUF_SIZE);
isotp_buf_out_remain = spi_cb_rx(isotp_buf, len, isotp_buf_out);
isotp_buf_out_ptr = isotp_buf_out;
isotp_buf_out_idx = 0;
// send initial
if (isotp_buf_out_remain <= 7) {
odat[0] = isotp_buf_out_remain;
memcpy(odat+1, isotp_buf_out_ptr, isotp_buf_out_remain);
} else {
odat[0] = 0x10 | (isotp_buf_out_remain>>8);
odat[1] = isotp_buf_out_remain & 0xFF;
memcpy(odat+2, isotp_buf_out_ptr, 6);
isotp_buf_out_remain -= 6;
isotp_buf_out_ptr += 6;
isotp_buf_out_idx++;
}
bl_can_send(odat);
}
} else if (type == 0x10) {
int len = ((dat[0]&0xF)<<8) | dat[1];
// setup buffer
isotp_buf_ptr = isotp_buf;
memcpy(isotp_buf_ptr, dat+2, 6);
if (len < (ISOTP_BUF_SIZE-0x10)) {
isotp_buf_ptr += 6;
isotp_buf_remain = len-6;
}
memset(odat, 0, 8);
odat[0] = 0x30;
bl_can_send(odat);
}
}
// next
CANx->RF0R |= CAN_RF0R_RFOM0;
}
}
void CAN1_SCE_IRQ_Handler(void) {
llcan_clear_send(CANx);
}
#endif
void soft_flasher_start(void) {
#ifdef PEDAL
REGISTER_INTERRUPT(CAN1_TX_IRQn, CAN1_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
REGISTER_INTERRUPT(CAN1_RX0_IRQn, CAN1_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
REGISTER_INTERRUPT(CAN1_SCE_IRQn, CAN1_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
#endif
print("\n\n\n************************ FLASHER START ************************\n");
enter_bootloader_mode = 0;
flasher_peripherals_init();
// pedal has the canloader
#ifdef PEDAL
RCC->APB1ENR |= RCC_APB1ENR_CAN1EN;
// B8,B9: CAN 1
set_gpio_alternate(GPIOB, 8, GPIO_AF9_CAN1);
set_gpio_alternate(GPIOB, 9, GPIO_AF9_CAN1);
current_board->enable_can_transceiver(1, true);
// init can
llcan_set_speed(CANx, 5000, false, false);
llcan_init(CANx);
#endif
gpio_usart2_init();
gpio_usb_init();

View File

@ -1,6 +1,6 @@
// When changing these structs, python/__init__.py needs to be kept up to date!
#define HEALTH_PACKET_VERSION 15
#define HEALTH_PACKET_VERSION 16
struct __attribute__((packed)) health_t {
uint32_t uptime_pkt;
uint32_t voltage_pkt;
@ -9,7 +9,6 @@ struct __attribute__((packed)) health_t {
uint32_t safety_rx_invalid_pkt;
uint32_t tx_buffer_overflow_pkt;
uint32_t rx_buffer_overflow_pkt;
uint32_t gmlan_send_errs_pkt;
uint32_t faults_pkt;
uint8_t ignition_line_pkt;
uint8_t ignition_can_pkt;
@ -21,10 +20,10 @@ struct __attribute__((packed)) health_t {
uint8_t power_save_enabled_pkt;
uint8_t heartbeat_lost_pkt;
uint16_t alternative_experience_pkt;
float interrupt_load;
float interrupt_load_pkt;
uint8_t fan_power;
uint8_t safety_rx_checks_invalid;
uint16_t spi_checksum_error_count;
uint8_t safety_rx_checks_invalid_pkt;
uint16_t spi_checksum_error_count_pkt;
uint8_t fan_stall_count;
uint16_t sbu1_voltage_mV;
uint16_t sbu2_voltage_mV;

View File

@ -2,7 +2,6 @@
import os
import struct
from functools import wraps
from typing import Optional
from panda import Panda, PandaDFU
from panda.python.constants import McuType
@ -57,7 +56,7 @@ class PandaJungle(Panda):
fn = os.path.join(FW_PATH, self._mcu_type.config.app_fn.replace("panda", "panda_jungle"))
super().flash(fn=fn, code=code, reconnect=reconnect)
def recover(self, timeout: Optional[int] = 60, reset: bool = True) -> bool:
def recover(self, timeout: int | None = 60, reset: bool = True) -> bool:
dfu_serial = self.get_dfu_serial()
if reset:
@ -81,6 +80,12 @@ class PandaJungle(Panda):
return McuType.F4
elif hw_type in PandaJungle.H7_DEVICES:
return McuType.H7
else:
# have to assume F4, see comment in Panda.connect
# initially Jungle V1 has HW type: bytearray(b'')
if hw_type == b'' or self._assume_f4_mcu:
return McuType.F4
raise ValueError(f"unknown HW type: {hw_type}")
def up_to_date(self, fn=None) -> bool:

View File

@ -49,8 +49,6 @@ struct board {
// CAN modes
#define CAN_MODE_NORMAL 0U
#define CAN_MODE_GMLAN_CAN2 1U
#define CAN_MODE_GMLAN_CAN3 2U
#define CAN_MODE_OBD_CAN2 3U
// Harness states

View File

@ -1,3 +1,6 @@
// ///////////////////////// //
// Jungle board v1 (STM32F4) //
// ///////////////////////// //
void board_v1_set_led(uint8_t color, bool enabled) {
switch (color) {
@ -154,7 +157,7 @@ void board_v1_init(void) {
void board_v1_tick(void) {}
const board board_v1 = {
board board_v1 = {
.has_canfd = false,
.has_sbu_sense = false,
.avdd_mV = 3300U,

View File

@ -1,5 +1,8 @@
// ///////////////////////// //
// Jungle board v2 (STM32H7) //
// ///////////////////////// //
const gpio_t power_pins[] = {
gpio_t power_pins[] = {
{.bank = GPIOA, .pin = 0},
{.bank = GPIOA, .pin = 1},
{.bank = GPIOF, .pin = 12},
@ -8,7 +11,7 @@ const gpio_t power_pins[] = {
{.bank = GPIOB, .pin = 2},
};
const gpio_t sbu1_ignition_pins[] = {
gpio_t sbu1_ignition_pins[] = {
{.bank = GPIOD, .pin = 0},
{.bank = GPIOD, .pin = 5},
{.bank = GPIOD, .pin = 12},
@ -17,7 +20,7 @@ const gpio_t sbu1_ignition_pins[] = {
{.bank = GPIOE, .pin = 9},
};
const gpio_t sbu1_relay_pins[] = {
gpio_t sbu1_relay_pins[] = {
{.bank = GPIOD, .pin = 1},
{.bank = GPIOD, .pin = 6},
{.bank = GPIOD, .pin = 11},
@ -26,7 +29,7 @@ const gpio_t sbu1_relay_pins[] = {
{.bank = GPIOE, .pin = 10},
};
const gpio_t sbu2_ignition_pins[] = {
gpio_t sbu2_ignition_pins[] = {
{.bank = GPIOD, .pin = 3},
{.bank = GPIOD, .pin = 8},
{.bank = GPIOD, .pin = 9},
@ -35,7 +38,7 @@ const gpio_t sbu2_ignition_pins[] = {
{.bank = GPIOE, .pin = 11},
};
const gpio_t sbu2_relay_pins[] = {
gpio_t sbu2_relay_pins[] = {
{.bank = GPIOD, .pin = 4},
{.bank = GPIOD, .pin = 10},
{.bank = GPIOD, .pin = 13},
@ -44,7 +47,7 @@ const gpio_t sbu2_relay_pins[] = {
{.bank = GPIOE, .pin = 12},
};
const adc_channel_t sbu1_channels[] = {
adc_channel_t sbu1_channels[] = {
{.adc = ADC3, .channel = 12},
{.adc = ADC3, .channel = 2},
{.adc = ADC3, .channel = 4},
@ -53,7 +56,7 @@ const adc_channel_t sbu1_channels[] = {
{.adc = ADC3, .channel = 10},
};
const adc_channel_t sbu2_channels[] = {
adc_channel_t sbu2_channels[] = {
{.adc = ADC1, .channel = 13},
{.adc = ADC3, .channel = 3},
{.adc = ADC3, .channel = 5},
@ -304,7 +307,7 @@ void board_v2_init(void) {
void board_v2_tick(void) {}
const board board_v2 = {
board board_v2 = {
.has_canfd = true,
.has_sbu_sense = true,
.avdd_mV = 3300U,

View File

@ -15,3 +15,5 @@ if __name__ == "__main__":
print("flashing", s)
with PandaJungle(serial=s) as p:
p.flash()
exit(1 if len(serials) == 0 else 0)

View File

@ -2,7 +2,6 @@
#include "board/config.h"
#include "board/safety.h"
#include "board/drivers/gmlan_alt.h"
#include "board/drivers/pwm.h"
#include "board/drivers/usb.h"

View File

@ -24,3 +24,4 @@ if __name__ == "__main__":
for s in dfu_serials:
print("flashing", s)
PandaJungleDFU(s).recover()
exit(1 if len(dfu_serials) == 0 else 0)

View File

@ -4,6 +4,6 @@ from panda import PandaJungle
if __name__ == "__main__":
for p in PandaJungle.list():
pp = PandaJungle(p)
print("%s: %s" % (pp.get_serial()[0], pp.get_version()))
print(f"{pp.get_serial()[0]}: {pp.get_version()}")

View File

@ -3,7 +3,6 @@
#include "drivers/pwm.h"
#include "drivers/usb.h"
#include "drivers/gmlan_alt.h"
#include "drivers/simple_watchdog.h"
#include "drivers/bootkick.h"
@ -34,7 +33,6 @@
bool check_started(void) {
bool started = current_board->check_ignition() || ignition_can;
ignition_seen |= started;
return started;
}
@ -145,8 +143,10 @@ void __attribute__ ((noinline)) enable_fpu(void) {
// called at 8Hz
uint8_t loop_counter = 0U;
uint8_t prev_harness_status = HARNESS_STATUS_NC;
void tick_handler(void) {
if (TICK_TIMER->SR != 0) {
if (TICK_TIMER->SR != 0U) {
// siren
current_board->set_siren((loop_counter & 1U) && (siren_enabled || (siren_countdown > 0U)));
@ -156,6 +156,17 @@ void tick_handler(void) {
harness_tick();
simple_watchdog_kick();
// re-init everything that uses harness status
if (harness.status != prev_harness_status) {
prev_harness_status = harness.status;
can_set_orientation(harness.status == HARNESS_STATUS_FLIPPED);
// re-init everything that uses harness status
can_init_all();
set_safety_mode(current_safety_mode, current_safety_param);
set_power_save_state(power_save_status);
}
// decimated to 1Hz
if (loop_counter == 0U) {
can_live = pending_can_live;
@ -187,7 +198,7 @@ void tick_handler(void) {
bootkick_tick(check_started(), recent_heartbeat);
// increase heartbeat counter and cap it at the uint32 limit
if (heartbeat_counter < __UINT32_MAX__) {
if (heartbeat_counter < UINT32_MAX) {
heartbeat_counter += 1U;
}
@ -280,38 +291,6 @@ void tick_handler(void) {
TICK_TIMER->SR = 0;
}
void EXTI_IRQ_Handler(void) {
if (check_exti_irq()) {
exti_irq_clear();
clock_init();
set_power_save_state(POWER_SAVE_STATUS_DISABLED);
deepsleep_allowed = false;
heartbeat_counter = 0U;
usb_soft_disconnect(false);
NVIC_EnableIRQ(TICK_TIMER_IRQ);
}
}
uint8_t rtc_counter = 0;
void RTC_WKUP_IRQ_Handler(void) {
exti_irq_clear();
clock_init();
rtc_counter++;
if ((rtc_counter % 2U) == 0U) {
current_board->set_led(LED_BLUE, false);
} else {
current_board->set_led(LED_BLUE, true);
}
if (rtc_counter == __UINT8_MAX__) {
rtc_counter = 1U;
}
}
int main(void) {
// Init interrupt table
init_interrupts(true);
@ -413,22 +392,6 @@ int main(void) {
}
#endif
} else {
if (deepsleep_allowed && !usb_enumerated && !check_started() && ignition_seen && (heartbeat_counter > 20U)) {
usb_soft_disconnect(true);
fan_set_power(0U);
NVIC_DisableIRQ(TICK_TIMER_IRQ);
delay(512000U);
// Init IRQs for CAN transceiver and ignition line
exti_irq_init();
// Init RTC Wakeup event on EXTI22
REGISTER_INTERRUPT(RTC_WKUP_IRQn, RTC_WKUP_IRQ_Handler, 10U, FAULT_INTERRUPT_RATE_EXTI)
rtc_wakeup_init();
// STOP mode
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
}
__WFI();
SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
}

View File

@ -9,8 +9,8 @@ int get_health_pkt(void *dat) {
struct health_t * health = (struct health_t*)dat;
health->uptime_pkt = uptime_cnt;
health->voltage_pkt = adc_get_mV(ADCCHAN_VIN) * VIN_READOUT_DIVIDER;
health->current_pkt = current_board->read_current();
health->voltage_pkt = current_board->read_voltage_mV();
health->current_pkt = current_board->read_current_mA();
// Use the GPIO pin to determine ignition or use a CAN based logic
health->ignition_line_pkt = (uint8_t)(current_board->check_ignition());
@ -21,21 +21,20 @@ int get_health_pkt(void *dat) {
health->safety_rx_invalid_pkt = safety_rx_invalid;
health->tx_buffer_overflow_pkt = tx_buffer_overflow;
health->rx_buffer_overflow_pkt = rx_buffer_overflow;
health->gmlan_send_errs_pkt = gmlan_send_errs;
health->car_harness_status_pkt = harness.status;
health->safety_mode_pkt = (uint8_t)(current_safety_mode);
health->safety_param_pkt = current_safety_param;
health->alternative_experience_pkt = alternative_experience;
health->power_save_enabled_pkt = power_save_status == POWER_SAVE_STATUS_ENABLED;
health->heartbeat_lost_pkt = heartbeat_lost;
health->safety_rx_checks_invalid = safety_rx_checks_invalid;
health->safety_rx_checks_invalid_pkt = safety_rx_checks_invalid;
health->spi_checksum_error_count = spi_checksum_error_count;
health->spi_checksum_error_count_pkt = spi_checksum_error_count;
health->fault_status_pkt = fault_status;
health->faults_pkt = faults;
health->interrupt_load = interrupt_load;
health->interrupt_load_pkt = interrupt_load;
health->fan_power = fan_state.power;
health->fan_stall_count = fan_state.total_stall_count;
@ -48,12 +47,6 @@ int get_health_pkt(void *dat) {
return sizeof(*health);
}
int get_rtc_pkt(void *dat) {
timestamp_t t = rtc_get_time();
(void)memcpy(dat, &t, sizeof(t));
return sizeof(t);
}
// send on serial, first byte to select the ring
void comms_endpoint2_write(const uint8_t *data, uint32_t len) {
uart_ring *ur = get_ring_by_number(data[0]);
@ -71,7 +64,6 @@ void comms_endpoint2_write(const uint8_t *data, uint32_t len) {
int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
unsigned int resp_len = 0;
uart_ring *ur = NULL;
timestamp_t t;
uint32_t time;
#ifdef DEBUG_COMMS
@ -82,52 +74,6 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
#endif
switch (req->request) {
// **** 0xa0: get rtc time
case 0xa0:
resp_len = get_rtc_pkt(resp);
break;
// **** 0xa1: set rtc year
case 0xa1:
t = rtc_get_time();
t.year = req->param1;
rtc_set_time(t);
break;
// **** 0xa2: set rtc month
case 0xa2:
t = rtc_get_time();
t.month = req->param1;
rtc_set_time(t);
break;
// **** 0xa3: set rtc day
case 0xa3:
t = rtc_get_time();
t.day = req->param1;
rtc_set_time(t);
break;
// **** 0xa4: set rtc weekday
case 0xa4:
t = rtc_get_time();
t.weekday = req->param1;
rtc_set_time(t);
break;
// **** 0xa5: set rtc hour
case 0xa5:
t = rtc_get_time();
t.hour = req->param1;
rtc_set_time(t);
break;
// **** 0xa6: set rtc minute
case 0xa6:
t = rtc_get_time();
t.minute = req->param1;
rtc_set_time(t);
break;
// **** 0xa7: set rtc second
case 0xa7:
t = rtc_get_time();
t.second = req->param1;
rtc_set_time(t);
break;
// **** 0xa8: get microsecond timer
case 0xa8:
time = microsecond_timer_get();
@ -264,9 +210,9 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
case 0xd8:
NVIC_SystemReset();
break;
// **** 0xdb: set GMLAN (white/grey) or OBD CAN (black) multiplexing mode
// **** 0xdb: set OBD CAN multiplexing mode
case 0xdb:
if(current_board->has_obd){
if (current_board->has_obd) {
if (req->param1 == 1U) {
// Enable OBD CAN
current_board->set_can_mode(CAN_MODE_OBD_CAN2);
@ -360,7 +306,7 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
break;
// **** 0xe5: set CAN loopback (for testing)
case 0xe5:
can_loopback = (req->param1 > 0U);
can_loopback = req->param1 > 0U;
can_init_all();
break;
// **** 0xe6: set custom clock source period
@ -428,10 +374,6 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
UNUSED(ret);
}
break;
// **** 0xfb: allow highest power saving mode (stop) to be entered
case 0xfb:
deepsleep_allowed = true;
break;
// **** 0xfc: set CAN FD non-ISO mode
case 0xfc:
if ((req->param1 < PANDA_CAN_CNT) && current_board->has_canfd) {

View File

@ -6,13 +6,12 @@ void puth4(unsigned int i);
void hexdump(const void *a, int l);
typedef struct board board;
typedef struct harness_configuration harness_configuration;
void can_flip_buses(uint8_t bus1, uint8_t bus2);
void pwm_init(TIM_TypeDef *TIM, uint8_t channel);
void pwm_set(TIM_TypeDef *TIM, uint8_t channel, uint8_t percentage);
// ********************* Globals **********************
uint8_t hw_type = 0;
const board *current_board;
board *current_board;
uint32_t uptime_cnt = 0;
bool green_led_enabled = false;
@ -21,10 +20,6 @@ uint32_t heartbeat_counter = 0;
bool heartbeat_lost = false;
bool heartbeat_disabled = false; // set over USB
// Enter deep sleep mode
bool deepsleep_allowed = false;
bool ignition_seen = false;
// siren state
bool siren_enabled = false;
uint32_t siren_countdown = 0; // siren plays while countdown > 0

View File

@ -1 +0,0 @@
obj/*

View File

@ -1,28 +0,0 @@
# pedal
This is the firmware for the comma pedal.
The comma pedal is a gas pedal interceptor for Honda/Acura and Toyota/Lexus. It allows you to "virtually" press the pedal and borrows a lot from panda.
== 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

View File

@ -1,28 +0,0 @@
import copy
Import('build_project')
build_projects = {}
build_projects["pedal"] = {
"MAIN": "main.c",
"BOOTSTUB": "../bootstub.c",
"STARTUP_FILE": "../stm32fx/startup_stm32f205xx.s",
"LINKER_SCRIPT": "../stm32fx/stm32f2_flash.ld",
"APP_START_ADDRESS": "0x8004000",
"PROJECT_FLAGS": [
"-mcpu=cortex-m3",
"-msoft-float",
"-DSTM32F2",
"-DSTM32F205xx",
"-O2",
"-DPEDAL",
],
}
# build with the USB driver enabled
build_projects["pedal_usb"] = copy.deepcopy(build_projects["pedal"])
build_projects["pedal_usb"]["PROJECT_FLAGS"].append("-DPEDAL_USB")
for project_name, project in build_projects.items():
build_project(project_name, project, [])

View File

@ -1,8 +0,0 @@
#!/usr/bin/env sh
set -e
cd ..
scons -u -j$(nproc)
cd pedal
../../tests/pedal/enter_canloader.py obj/pedal.bin.signed

View File

@ -1,316 +0,0 @@
// ********************* Includes *********************
//#define PEDAL_USB
#include "../config.h"
#include "early_init.h"
#include "crc.h"
#define CAN CAN1
#ifdef PEDAL_USB
#include "drivers/usb.h"
#else
// no serial either
void print(const char *a) {
UNUSED(a);
}
void puth(unsigned int i) {
UNUSED(i);
}
void puth2(unsigned int i) {
UNUSED(i);
}
#endif
#define ENTER_BOOTLOADER_MAGIC 0xdeadbeefU
uint32_t enter_bootloader_mode;
// cppcheck-suppress unusedFunction ; used in headers not included in cppcheck
void __initialize_hardware_early(void) {
early_initialization();
}
// ********************* serial debugging *********************
#ifdef PEDAL_USB
void debug_ring_callback(uart_ring *ring) {
char rcv;
while (get_char(ring, &rcv) != 0) {
(void)put_char(ring, rcv);
}
}
int comms_can_read(uint8_t *data, uint32_t max_len) {
UNUSED(data);
UNUSED(max_len);
return 0;
}
void comms_can_write(const uint8_t *data, uint32_t len) {
UNUSED(data);
UNUSED(len);
}
void comms_endpoint2_write(const uint8_t *data, uint32_t len) {
UNUSED(data);
UNUSED(len);
}
void refresh_can_tx_slots_available(void) {}
int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
unsigned int resp_len = 0;
uart_ring *ur = NULL;
switch (req->request) {
// **** 0xc1: get hardware type
case 0xc1:
resp[0] = hw_type;
resp_len = 1;
break;
// **** 0xe0: uart read
case 0xe0:
ur = get_ring_by_number(req->param1);
if (!ur) {
break;
}
// read
while ((resp_len < MIN(req->length, USBPACKET_MAX_SIZE)) &&
get_char(ur, (char*)&resp[resp_len])) {
++resp_len;
}
break;
default:
print("NO HANDLER ");
puth(req->request);
print("\n");
break;
}
return resp_len;
}
#endif
// ***************************** can port *****************************
// addresses to be used on CAN
#define CAN_GAS_INPUT 0x200
#define CAN_GAS_OUTPUT 0x201UL
#define CAN_GAS_SIZE 6
#define COUNTER_CYCLE 0xFU
void CAN1_TX_IRQ_Handler(void) {
// 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 10U
uint32_t timeout = 0;
uint32_t current_index = 0;
#define NO_FAULT 0U
#define FAULT_BAD_CHECKSUM 1U
#define FAULT_SEND 2U
#define FAULT_SCE 3U
#define FAULT_STARTUP 4U
#define FAULT_TIMEOUT 5U
#define FAULT_INVALID 6U
uint8_t state = FAULT_STARTUP;
const uint8_t crc_poly = 0xD5U; // standard crc8
void CAN1_RX0_IRQ_Handler(void) {
while ((CAN->RF0R & CAN_RF0R_FMP0) != 0) {
#ifdef DEBUG
print("CAN RX\n");
#endif
int address = CAN->sFIFOMailBox[0].RIR >> 21;
if (address == CAN_GAS_INPUT) {
// softloader entry
if (GET_MAILBOX_BYTES_04(&CAN->sFIFOMailBox[0]) == 0xdeadfaceU) {
if (GET_MAILBOX_BYTES_48(&CAN->sFIFOMailBox[0]) == 0x0ab00b1e) {
enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC;
NVIC_SystemReset();
} else if (GET_MAILBOX_BYTES_48(&CAN->sFIFOMailBox[0]) == 0x02b00b1e) {
enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC;
NVIC_SystemReset();
} else {
print("Failed entering Softloader or Bootloader\n");
}
}
// normal packet
uint8_t dat[8];
for (int i=0; i<8; i++) {
dat[i] = GET_MAILBOX_BYTE(&CAN->sFIFOMailBox[0], i);
}
uint16_t value_0 = (dat[0] << 8) | dat[1];
uint16_t value_1 = (dat[2] << 8) | dat[3];
bool enable = ((dat[4] >> 7) & 1U) != 0U;
uint8_t index = dat[4] & COUNTER_CYCLE;
if (crc_checksum(dat, CAN_GAS_SIZE - 1, crc_poly) == dat[5]) {
if (((current_index + 1U) & COUNTER_CYCLE) == index) {
#ifdef DEBUG
print("setting gas ");
puth(value_0);
print("\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 == 0U) && (value_1 == 0U)) {
state = NO_FAULT;
} else {
state = FAULT_INVALID;
}
gas_set_0 = 0;
gas_set_1 = 0;
}
// clear the timeout
timeout = 0;
}
current_index = index;
} else {
// wrong checksum = fault
state = FAULT_BAD_CHECKSUM;
}
}
// next
CAN->RF0R |= CAN_RF0R_RFOM0;
}
}
void CAN1_SCE_IRQ_Handler(void) {
state = FAULT_SCE;
llcan_clear_send(CAN);
}
uint32_t pdl0 = 0;
uint32_t pdl1 = 0;
unsigned int pkt_idx = 0;
int led_value = 0;
void TIM3_IRQ_Handler(void) {
#ifdef DEBUG
puth(TIM3->CNT);
print(" ");
puth(pdl0);
print(" ");
puth(pdl1);
print("\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) & 0xFFU;
dat[1] = (pdl0 >> 0) & 0xFFU;
dat[2] = (pdl1 >> 8) & 0xFFU;
dat[3] = (pdl1 >> 0) & 0xFFU;
dat[4] = ((state & 0xFU) << 4) | pkt_idx;
dat[5] = crc_checksum(dat, CAN_GAS_SIZE - 1, crc_poly);
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) | 1U;
++pkt_idx;
pkt_idx &= COUNTER_CYCLE;
} else {
// old can packet hasn't sent!
state = FAULT_SEND;
#ifdef DEBUG
print("CAN MISS\n");
#endif
}
// blink the LED
current_board->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 += 1U;
}
}
// ***************************** main code *****************************
void pedal(void) {
// read/write
pdl0 = adc_get_raw(ADCCHAN_ACCEL0);
pdl1 = adc_get_raw(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);
}
watchdog_feed();
}
int main(void) {
// Init interrupt table
init_interrupts(true);
REGISTER_INTERRUPT(CAN1_TX_IRQn, CAN1_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
REGISTER_INTERRUPT(CAN1_RX0_IRQn, CAN1_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
REGISTER_INTERRUPT(CAN1_SCE_IRQn, CAN1_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
// Should run at around 732Hz (see init below)
REGISTER_INTERRUPT(TIM3_IRQn, TIM3_IRQ_Handler, 1000U, FAULT_INTERRUPT_RATE_TIM3)
disable_interrupts();
// init devices
clock_init();
peripherals_init();
detect_board_type();
// init board
current_board->init();
#ifdef PEDAL_USB
// enable USB
usb_init();
#endif
// pedal stuff
dac_init();
adc_init();
// init can
bool llcan_speed_set = llcan_set_speed(CAN, 5000, false, false);
if (!llcan_speed_set) {
print("Failed to set llcan speed");
}
bool ret = llcan_init(CAN);
UNUSED(ret);
// 48mhz / 65536 ~= 732
timer_init(TIM3, 15);
NVIC_EnableIRQ(TIM3_IRQn);
watchdog_init(WATCHDOG_50_MS);
print("**** INTERRUPTS ON ****\n");
enable_interrupts();
// main pedal loop
while (1) {
pedal();
}
return 0;
}

View File

@ -1,11 +0,0 @@
// ******************** Prototypes ********************
void print(const char *a);
void puth(unsigned int i);
void puth2(unsigned int i);
void puth4(unsigned int i);
typedef struct board board;
typedef struct harness_configuration harness_configuration;
// ********************* Globals **********************
uint8_t hw_type = 0;
const board *current_board;

View File

@ -1,11 +0,0 @@
#!/usr/bin/env sh
set -e
DFU_UTIL="dfu-util"
cd ..
scons -u -j$(nproc)
cd pedal
$DFU_UTIL -d 0483:df11 -a 0 -s 0x08004000 -D obj/pedal.bin.signed
$DFU_UTIL -d 0483:df11 -a 0 -s 0x08000000:leave -D obj/bootstub.pedal.bin

View File

@ -11,9 +11,3 @@ void get_provision_chunk(uint8_t *resp) {
(void)memcpy(resp, "unprovisioned\x00\x00\x00testing123\x00\x00\xa3\xa6\x99\xec", 0x20);
}
}
uint8_t chunk[PROVISION_CHUNK_LEN];
bool is_provisioned(void) {
(void)memcpy(chunk, (uint8_t *)PROVISION_CHUNK_ADDRESS, PROVISION_CHUNK_LEN);
return (memcmp(chunk, unprovisioned_text, 0x20) != 0);
}

View File

@ -24,3 +24,4 @@ if __name__ == "__main__":
for s in dfu_serials:
print("flashing", s)
PandaDFU(s).recover()
exit(1 if len(dfu_serials) == 0 else 0)

View File

@ -94,8 +94,8 @@ bool get_longitudinal_allowed(void) {
// Given a CRC-8 poly, generate a static lookup table to use with a fast CRC-8
// algorithm. Called at init time for safety modes using CRC-8.
void gen_crc_lookup_table_8(uint8_t poly, uint8_t crc_lut[]) {
for (int i = 0; i < 256; i++) {
uint8_t crc = i;
for (uint16_t i = 0U; i <= 0xFFU; i++) {
uint8_t crc = (uint8_t)i;
for (int j = 0; j < 8; j++) {
if ((crc & 0x80U) != 0U) {
crc = (uint8_t)((crc << 1) ^ poly);
@ -327,8 +327,6 @@ int set_safety_hooks(uint16_t mode, uint16_t param) {
// reset state set by safety mode
safety_mode_cnt = 0U;
relay_malfunction = false;
enable_gas_interceptor = false;
gas_interceptor_prev = 0;
gas_pressed = false;
gas_pressed_prev = false;
brake_pressed = false;
@ -543,10 +541,6 @@ bool longitudinal_brake_checks(int desired_brake, const LongitudinalLimits limit
return violation;
}
bool longitudinal_interceptor_checks(const CANPacket_t *to_send) {
return !get_longitudinal_allowed() && (GET_BYTE(to_send, 0) || GET_BYTE(to_send, 1));
}
// Safety checks for torque-based steering commands
bool steer_torque_cmd_checks(int desired_torque, int steer_req, const SteeringLimits limits) {
bool violation = false;

View File

@ -123,11 +123,12 @@ RxCheck chrysler_ram_hd_rx_checks[] = {
const uint32_t CHRYSLER_PARAM_RAM_DT = 1U; // set for Ram DT platform
const uint32_t CHRYSLER_PARAM_RAM_HD = 2U; // set for Ram HD platform
enum {
typedef enum {
CHRYSLER_RAM_DT,
CHRYSLER_RAM_HD,
CHRYSLER_PACIFICA, // plus Jeep
} chrysler_platform = CHRYSLER_PACIFICA;
} ChryslerPlatform;
ChryslerPlatform chrysler_platform = CHRYSLER_PACIFICA;
const ChryslerAddrs *chrysler_addrs = &CHRYSLER_ADDRS;
static uint32_t chrysler_get_checksum(const CANPacket_t *to_push) {
@ -185,7 +186,7 @@ static void chrysler_rx_hook(const CANPacket_t *to_push) {
// enter controls on rising edge of ACC, exit controls on ACC off
const int das_3_bus = (chrysler_platform == CHRYSLER_PACIFICA) ? 0 : 2;
if ((bus == das_3_bus) && (addr == chrysler_addrs->DAS_3)) {
bool cruise_engaged = GET_BIT(to_push, 21U) == 1U;
bool cruise_engaged = GET_BIT(to_push, 21U);
pcm_cruise_check(cruise_engaged);
}
@ -226,7 +227,7 @@ static bool chrysler_tx_hook(const CANPacket_t *to_send) {
const SteeringLimits limits = (chrysler_platform == CHRYSLER_PACIFICA) ? CHRYSLER_STEERING_LIMITS :
(chrysler_platform == CHRYSLER_RAM_DT) ? CHRYSLER_RAM_DT_STEERING_LIMITS : CHRYSLER_RAM_HD_STEERING_LIMITS;
bool steer_req = (chrysler_platform == CHRYSLER_PACIFICA) ? (GET_BIT(to_send, 4U) != 0U) : ((GET_BYTE(to_send, 3) & 0x7U) == 2U);
bool steer_req = (chrysler_platform == CHRYSLER_PACIFICA) ? GET_BIT(to_send, 4U) : (GET_BYTE(to_send, 3) & 0x7U) == 2U;
if (steer_torque_cmd_checks(desired_torque, steer_req, limits)) {
tx = false;
}

View File

@ -59,8 +59,10 @@ const CanMsg FORD_CANFD_LONG_TX_MSGS[] = {
// this may be the cause of blocked messages
RxCheck ford_rx_checks[] = {
{.msg = {{FORD_BrakeSysFeatures, 0, 8, .check_checksum = true, .max_counter = 15U, .quality_flag=true, .frequency = 50U}, { 0 }, { 0 }}},
// TODO: FORD_EngVehicleSpThrottle2 has a counter that skips by 2, understand and enable counter check
{.msg = {{FORD_EngVehicleSpThrottle2, 0, 8, .check_checksum = true, .quality_flag=true, .frequency = 50U}, { 0 }, { 0 }}},
// FORD_EngVehicleSpThrottle2 has a counter that either randomly skips or by 2, likely ECU bug
// Some hybrid models also experience a bug where this checksum mismatches for one or two frames under heavy acceleration with ACC
// It has been confirmed that the Bronco Sport's camera only disallows ACC for bad quality flags, not counters or checksums, so we match that
{.msg = {{FORD_EngVehicleSpThrottle2, 0, 8, .check_checksum = false, .quality_flag=true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{FORD_Yaw_Data_FD1, 0, 8, .check_checksum = true, .max_counter = 255U, .quality_flag=true, .frequency = 100U}, { 0 }, { 0 }}},
// These messages have no counter or checksum
{.msg = {{FORD_EngBrakeData, 0, 8, .frequency = 10U}, { 0 }, { 0 }}},
@ -90,9 +92,6 @@ static uint32_t ford_get_checksum(const CANPacket_t *to_push) {
if (addr == FORD_BrakeSysFeatures) {
// Signal: VehVActlBrk_No_Cs
chksum = GET_BYTE(to_push, 3);
} else if (addr == FORD_EngVehicleSpThrottle2) {
// Signal: VehVActlEng_No_Cs
chksum = GET_BYTE(to_push, 1);
} else if (addr == FORD_Yaw_Data_FD1) {
// Signal: VehRollYawW_No_Cs
chksum = GET_BYTE(to_push, 4);
@ -110,11 +109,6 @@ static uint32_t ford_compute_checksum(const CANPacket_t *to_push) {
chksum += GET_BYTE(to_push, 2) >> 6; // VehVActlBrk_D_Qf
chksum += (GET_BYTE(to_push, 2) >> 2) & 0xFU; // VehVActlBrk_No_Cnt
chksum = 0xFFU - chksum;
} else if (addr == FORD_EngVehicleSpThrottle2) {
chksum += (GET_BYTE(to_push, 2) >> 3) & 0xFU; // VehVActlEng_No_Cnt
chksum += (GET_BYTE(to_push, 4) >> 5) & 0x3U; // VehVActlEng_D_Qf
chksum += GET_BYTE(to_push, 6) + GET_BYTE(to_push, 7); // Veh_V_ActlEng
chksum = 0xFFU - chksum;
} else if (addr == FORD_Yaw_Data_FD1) {
chksum += GET_BYTE(to_push, 0) + GET_BYTE(to_push, 1); // VehRol_W_Actl
chksum += GET_BYTE(to_push, 2) + GET_BYTE(to_push, 3); // VehYaw_W_Actl
@ -280,7 +274,7 @@ static bool ford_tx_hook(const CANPacket_t *to_send) {
// Signal: AccBrkTot_A_Rq
int accel = ((GET_BYTE(to_send, 0) & 0x1FU) << 8) | GET_BYTE(to_send, 1);
// Signal: CmbbDeny_B_Actl
int cmbb_deny = GET_BIT(to_send, 37U);
bool cmbb_deny = GET_BIT(to_send, 37U);
bool violation = false;
violation |= longitudinal_accel_checks(accel, FORD_LONG_LIMITS);
@ -288,7 +282,7 @@ static bool ford_tx_hook(const CANPacket_t *to_send) {
violation |= longitudinal_gas_checks(gas_pred, FORD_LONG_LIMITS);
// Safety check for stock AEB
violation |= cmbb_deny != 0; // do not prevent stock AEB actuation
violation |= cmbb_deny; // do not prevent stock AEB actuation
if (violation) {
tx = false;
@ -302,8 +296,8 @@ static bool ford_tx_hook(const CANPacket_t *to_send) {
// Violation if resume button is pressed while controls not allowed, or
// if cancel button is pressed when cruise isn't engaged.
bool violation = false;
violation |= (GET_BIT(to_send, 8U) == 1U) && !cruise_engaged_prev; // Signal: CcAslButtnCnclPress (cancel)
violation |= (GET_BIT(to_send, 25U) == 1U) && !controls_allowed; // Signal: CcAsllButtnResPress (resume)
violation |= GET_BIT(to_send, 8U) && !cruise_engaged_prev; // Signal: CcAslButtnCnclPress (cancel)
violation |= GET_BIT(to_send, 25U) && !controls_allowed; // Signal: CcAsllButtnResPress (resume)
if (violation) {
tx = false;

View File

@ -29,8 +29,7 @@ const int GM_STANDSTILL_THRSLD = 10; // 0.311kph
const CanMsg GM_ASCM_TX_MSGS[] = {{0x180, 0, 4}, {0x409, 0, 7}, {0x40A, 0, 7}, {0x2CB, 0, 8}, {0x370, 0, 6}, // pt bus
{0xA1, 1, 7}, {0x306, 1, 8}, {0x308, 1, 7}, {0x310, 1, 2}, // obs bus
{0x315, 2, 5}, // ch bus
{0x104c006c, 3, 3}, {0x10400060, 3, 5}}; // gmlan
{0x315, 2, 5}}; // ch bus
const CanMsg GM_CAM_TX_MSGS[] = {{0x180, 0, 4}, // pt bus
{0x1E1, 2, 7}, {0x184, 2, 8}}; // camera bus
@ -60,7 +59,11 @@ enum {
GM_BTN_CANCEL = 6,
};
enum {GM_ASCM, GM_CAM} gm_hw = GM_ASCM;
typedef enum {
GM_ASCM,
GM_CAM
} GmHardware;
GmHardware gm_hw = GM_ASCM;
bool gm_cam_long = false;
bool gm_pcm_cruise = false;
@ -108,7 +111,7 @@ static void gm_rx_hook(const CANPacket_t *to_push) {
}
if ((addr == 0xC9) && (gm_hw == GM_CAM)) {
brake_pressed = GET_BIT(to_push, 40U) != 0U;
brake_pressed = GET_BIT(to_push, 40U);
}
if (addr == 0x1C4) {
@ -153,7 +156,7 @@ static bool gm_tx_hook(const CANPacket_t *to_send) {
int desired_torque = ((GET_BYTE(to_send, 0) & 0x7U) << 8) + GET_BYTE(to_send, 1);
desired_torque = to_signed(desired_torque, 11);
bool steer_req = (GET_BIT(to_send, 3U) != 0U);
bool steer_req = GET_BIT(to_send, 3U);
if (steer_torque_cmd_checks(desired_torque, steer_req, GM_STEERING_LIMITS)) {
tx = false;
@ -162,7 +165,7 @@ static bool gm_tx_hook(const CANPacket_t *to_send) {
// GAS/REGEN: safety check
if (addr == 0x2CB) {
bool apply = GET_BIT(to_send, 0U) != 0U;
bool apply = GET_BIT(to_send, 0U);
int gas_regen = ((GET_BYTE(to_send, 2) & 0x7FU) << 5) + ((GET_BYTE(to_send, 3) & 0xF8U) >> 3);
bool violation = false;
@ -204,7 +207,7 @@ static int gm_fwd_hook(int bus_num, int addr) {
// block lkas message and acc messages if gm_cam_long, forward all others
bool is_lkas_msg = (addr == 0x180);
bool is_acc_msg = (addr == 0x315) || (addr == 0x2CB) || (addr == 0x370);
int block_msg = is_lkas_msg || (is_acc_msg && gm_cam_long);
bool block_msg = is_lkas_msg || (is_acc_msg && gm_cam_long);
if (!block_msg) {
bus_fwd = 0;
}

View File

@ -1,16 +1,9 @@
const CanMsg HONDA_N_TX_MSGS[] = {{0xE4, 0, 5}, {0x194, 0, 4}, {0x1FA, 0, 8}, {0x30C, 0, 8}, {0x33D, 0, 5}};
const CanMsg HONDA_N_INTERCEPTOR_TX_MSGS[] = {{0xE4, 0, 5}, {0x194, 0, 4}, {0x1FA, 0, 8}, {0x200, 0, 6}, {0x30C, 0, 8}, {0x33D, 0, 5}};
const CanMsg HONDA_BOSCH_TX_MSGS[] = {{0xE4, 0, 5}, {0xE5, 0, 8}, {0x296, 1, 4}, {0x33D, 0, 5}, {0x33DA, 0, 5}, {0x33DB, 0, 8}}; // Bosch
const CanMsg HONDA_BOSCH_LONG_TX_MSGS[] = {{0xE4, 1, 5}, {0x1DF, 1, 8}, {0x1EF, 1, 8}, {0x1FA, 1, 8}, {0x30C, 1, 8}, {0x33D, 1, 5}, {0x33DA, 1, 5}, {0x33DB, 1, 8}, {0x39F, 1, 8}, {0x18DAB0F1, 1, 8}}; // Bosch w/ gas and brakes
const CanMsg HONDA_RADARLESS_TX_MSGS[] = {{0xE4, 0, 5}, {0x296, 2, 4}, {0x33D, 0, 8}}; // Bosch radarless
const CanMsg HONDA_RADARLESS_LONG_TX_MSGS[] = {{0xE4, 0, 5}, {0x33D, 0, 8}, {0x1C8, 0, 8}, {0x30C, 0, 8}}; // Bosch radarless w/ gas and brakes
// panda interceptor threshold needs to be equivalent to openpilot threshold to avoid controls mismatches
// If thresholds are mismatched then it is possible for panda to see the gas fall and rise while openpilot is in the pre-enabled state
// Threshold calculated from DBC gains: round(((83.3 / 0.253984064) + (83.3 / 0.126992032)) / 2) = 492
const int HONDA_GAS_INTERCEPTOR_THRESHOLD = 492;
#define HONDA_GET_INTERCEPTOR(msg) (((GET_BYTE((msg), 0) << 8) + GET_BYTE((msg), 1) + (GET_BYTE((msg), 2) << 8) + GET_BYTE((msg), 3)) / 2U) // avg between 2 tracks
const LongitudinalLimits HONDA_BOSCH_LONG_LIMITS = {
.max_accel = 200, // accel is used for brakes
.min_accel = -350,
@ -47,11 +40,6 @@ RxCheck honda_common_rx_checks[] = {
HONDA_COMMON_RX_CHECKS(0)
};
RxCheck honda_common_interceptor_rx_checks[] = {
HONDA_COMMON_RX_CHECKS(0)
{.msg = {{0x201, 0, 6, .check_checksum = false, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
};
RxCheck honda_common_alt_brake_rx_checks[] = {
HONDA_COMMON_RX_CHECKS(0)
HONDA_ALT_BRAKE_ADDR_CHECK(0)
@ -62,11 +50,6 @@ RxCheck honda_nidec_alt_rx_checks[] = {
HONDA_COMMON_NO_SCM_FEEDBACK_RX_CHECKS(0)
};
RxCheck honda_nidec_alt_interceptor_rx_checks[] = {
HONDA_COMMON_NO_SCM_FEEDBACK_RX_CHECKS(0)
{.msg = {{0x201, 0, 6, .check_checksum = false, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
};
// Bosch has pt on bus 1, verified 0x1A6 does not exist
RxCheck honda_bosch_rx_checks[] = {
HONDA_COMMON_RX_CHECKS(1)
@ -81,7 +64,6 @@ const uint16_t HONDA_PARAM_ALT_BRAKE = 1;
const uint16_t HONDA_PARAM_BOSCH_LONG = 2;
const uint16_t HONDA_PARAM_NIDEC_ALT = 4;
const uint16_t HONDA_PARAM_RADARLESS = 8;
const uint16_t HONDA_PARAM_GAS_INTERCEPTOR = 16;
enum {
HONDA_BTN_NONE = 0,
@ -97,7 +79,8 @@ bool honda_alt_brake_msg = false;
bool honda_fwd_brake = false;
bool honda_bosch_long = false;
bool honda_bosch_radarless = false;
enum {HONDA_NIDEC, HONDA_BOSCH} honda_hw = HONDA_NIDEC;
typedef enum {HONDA_NIDEC, HONDA_BOSCH} HondaHw;
HondaHw honda_hw = HONDA_NIDEC;
int honda_get_pt_bus(void) {
@ -114,11 +97,11 @@ static uint32_t honda_compute_checksum(const CANPacket_t *to_push) {
uint8_t checksum = 0U;
unsigned int addr = GET_ADDR(to_push);
while (addr > 0U) {
checksum += (addr & 0xFU); addr >>= 4;
checksum += (uint8_t)(addr & 0xFU); addr >>= 4;
}
for (int j = 0; j < len; j++) {
uint8_t byte = GET_BYTE(to_push, j);
checksum += (byte & 0xFU) + (byte >> 4U);
checksum += (uint8_t)(byte & 0xFU) + (byte >> 4U);
if (j == (len - 1)) {
checksum -= (byte & 0xFU); // remove checksum in message
}
@ -127,26 +110,15 @@ static uint32_t honda_compute_checksum(const CANPacket_t *to_push) {
}
static uint8_t honda_get_counter(const CANPacket_t *to_push) {
int addr = GET_ADDR(to_push);
uint8_t cnt = 0U;
if (addr == 0x201) {
// Signal: COUNTER_PEDAL
cnt = GET_BYTE(to_push, 4) & 0x0FU;
} else {
int counter_byte = GET_LEN(to_push) - 1U;
cnt = (GET_BYTE(to_push, counter_byte) >> 4U) & 0x3U;
}
return cnt;
int counter_byte = GET_LEN(to_push) - 1U;
return (GET_BYTE(to_push, counter_byte) >> 4U) & 0x3U;
}
static void honda_rx_hook(const CANPacket_t *to_push) {
const bool pcm_cruise = ((honda_hw == HONDA_BOSCH) && !honda_bosch_long) || \
((honda_hw == HONDA_NIDEC) && !enable_gas_interceptor);
const bool pcm_cruise = ((honda_hw == HONDA_BOSCH) && !honda_bosch_long) || (honda_hw == HONDA_NIDEC);
int pt_bus = honda_get_pt_bus();
int addr = GET_ADDR(to_push);
int len = GET_LEN(to_push);
int bus = GET_BUS(to_push);
// sample speed
@ -166,7 +138,7 @@ static void honda_rx_hook(const CANPacket_t *to_push) {
// enter controls when PCM enters cruise state
if (pcm_cruise && (addr == 0x17C)) {
const bool cruise_engaged = GET_BIT(to_push, 38U) != 0U;
const bool cruise_engaged = GET_BIT(to_push, 38U);
// engage on rising edge
if (cruise_engaged && !cruise_engaged_prev) {
controls_allowed = true;
@ -207,34 +179,25 @@ static void honda_rx_hook(const CANPacket_t *to_push) {
// accord, crv: 0x1BE
if (honda_alt_brake_msg) {
if (addr == 0x1BE) {
brake_pressed = GET_BIT(to_push, 4U) != 0U;
brake_pressed = GET_BIT(to_push, 4U);
}
} else {
if (addr == 0x17C) {
// also if brake switch is 1 for two CAN frames, as brake pressed is delayed
const bool brake_switch = GET_BIT(to_push, 32U) != 0U;
brake_pressed = (GET_BIT(to_push, 53U) != 0U) || (brake_switch && honda_brake_switch_prev);
const bool brake_switch = GET_BIT(to_push, 32U);
brake_pressed = (GET_BIT(to_push, 53U)) || (brake_switch && honda_brake_switch_prev);
honda_brake_switch_prev = brake_switch;
}
}
// length check because bosch hardware also uses this id (0x201 w/ len = 8)
if ((addr == 0x201) && (len == 6) && enable_gas_interceptor) {
int gas_interceptor = HONDA_GET_INTERCEPTOR(to_push);
gas_pressed = gas_interceptor > HONDA_GAS_INTERCEPTOR_THRESHOLD;
gas_interceptor_prev = gas_interceptor;
}
if (!enable_gas_interceptor) {
if (addr == 0x17C) {
gas_pressed = GET_BYTE(to_push, 0) != 0U;
}
if (addr == 0x17C) {
gas_pressed = GET_BYTE(to_push, 0) != 0U;
}
// disable stock Honda AEB in alternative experience
if (!(alternative_experience & ALT_EXP_DISABLE_STOCK_AEB)) {
if ((bus == 2) && (addr == 0x1FA)) {
bool honda_stock_aeb = GET_BIT(to_push, 29U) != 0U;
bool honda_stock_aeb = GET_BIT(to_push, 29U);
int honda_stock_brake = (GET_BYTE(to_push, 0) << 2) | (GET_BYTE(to_push, 1) >> 6);
// Forward AEB when stock braking is higher than openpilot braking
@ -346,13 +309,6 @@ static bool honda_tx_hook(const CANPacket_t *to_send) {
}
}
// GAS: safety check (interceptor)
if (addr == 0x200) {
if (longitudinal_interceptor_checks(to_send)) {
tx = false;
}
}
// 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
@ -380,24 +336,18 @@ static safety_config honda_nidec_init(uint16_t param) {
honda_alt_brake_msg = false;
honda_bosch_long = false;
honda_bosch_radarless = false;
enable_gas_interceptor = GET_FLAG(param, HONDA_PARAM_GAS_INTERCEPTOR);
safety_config ret;
bool enable_nidec_alt = GET_FLAG(param, HONDA_PARAM_NIDEC_ALT);
if (enable_nidec_alt) {
enable_gas_interceptor ? SET_RX_CHECKS(honda_nidec_alt_interceptor_rx_checks, ret) : \
SET_RX_CHECKS(honda_nidec_alt_rx_checks, ret);
} else {
enable_gas_interceptor ? SET_RX_CHECKS(honda_common_interceptor_rx_checks, ret) : \
SET_RX_CHECKS(honda_common_rx_checks, ret);
}
if (enable_gas_interceptor) {
SET_TX_MSGS(HONDA_N_INTERCEPTOR_TX_MSGS, ret);
bool enable_nidec_alt = GET_FLAG(param, HONDA_PARAM_NIDEC_ALT);
if (enable_nidec_alt) {
SET_RX_CHECKS(honda_nidec_alt_rx_checks, ret);
} else {
SET_TX_MSGS(HONDA_N_TX_MSGS, ret);
SET_RX_CHECKS(honda_common_rx_checks, ret);
}
SET_TX_MSGS(HONDA_N_TX_MSGS, ret);
return ret;
}
@ -465,8 +415,8 @@ static int honda_bosch_fwd_hook(int bus_num, int addr) {
bus_fwd = 2;
}
if (bus_num == 2) {
int is_lkas_msg = (addr == 0xE4) || (addr == 0xE5) || (addr == 0x33D) || (addr == 0x33DA) || (addr == 0x33DB);
int is_acc_msg = ((addr == 0x1C8) || (addr == 0x30C)) && honda_bosch_radarless && honda_bosch_long;
bool is_lkas_msg = (addr == 0xE4) || (addr == 0xE5) || (addr == 0x33D) || (addr == 0x33DA) || (addr == 0x33DB);
bool is_acc_msg = ((addr == 0x1C8) || (addr == 0x30C)) && honda_bosch_radarless && honda_bosch_long;
bool block_msg = is_lkas_msg || is_acc_msg;
if (!block_msg) {
bus_fwd = 0;

View File

@ -178,7 +178,7 @@ static void hyundai_rx_hook(const CANPacket_t *to_push) {
// ACC steering wheel buttons
if (addr == 0x4F1) {
int cruise_button = GET_BYTE(to_push, 0) & 0x7U;
int main_button = GET_BIT(to_push, 3U);
bool main_button = GET_BIT(to_push, 3U);
hyundai_common_cruise_buttons_check(cruise_button, main_button);
}
@ -221,10 +221,10 @@ static bool hyundai_tx_hook(const CANPacket_t *to_send) {
// FCA11: Block any potential actuation
if (addr == 0x38D) {
int CR_VSM_DecCmd = GET_BYTE(to_send, 1);
int FCA_CmdAct = GET_BIT(to_send, 20U);
int CF_VSM_DecCmdAct = GET_BIT(to_send, 31U);
bool FCA_CmdAct = GET_BIT(to_send, 20U);
bool CF_VSM_DecCmdAct = GET_BIT(to_send, 31U);
if ((CR_VSM_DecCmd != 0) || (FCA_CmdAct != 0) || (CF_VSM_DecCmdAct != 0)) {
if ((CR_VSM_DecCmd != 0) || FCA_CmdAct || CF_VSM_DecCmdAct) {
tx = false;
}
}
@ -235,14 +235,14 @@ static bool hyundai_tx_hook(const CANPacket_t *to_send) {
int desired_accel_val = ((GET_BYTE(to_send, 5) << 3) | (GET_BYTE(to_send, 4) >> 5)) - 1023U;
int aeb_decel_cmd = GET_BYTE(to_send, 2);
int aeb_req = GET_BIT(to_send, 54U);
bool aeb_req = GET_BIT(to_send, 54U);
bool violation = false;
violation |= longitudinal_accel_checks(desired_accel_raw, HYUNDAI_LONG_LIMITS);
violation |= longitudinal_accel_checks(desired_accel_val, HYUNDAI_LONG_LIMITS);
violation |= (aeb_decel_cmd != 0);
violation |= (aeb_req != 0);
violation |= aeb_req;
if (violation) {
tx = false;
@ -252,7 +252,7 @@ static bool hyundai_tx_hook(const CANPacket_t *to_send) {
// LKA STEER: safety check
if (addr == 0x340) {
int desired_torque = ((GET_BYTES(to_send, 0, 4) >> 16) & 0x7ffU) - 1024U;
bool steer_req = GET_BIT(to_send, 27U) != 0U;
bool steer_req = GET_BIT(to_send, 27U);
const SteeringLimits limits = hyundai_alt_limits ? HYUNDAI_STEERING_LIMITS_ALT : HYUNDAI_STEERING_LIMITS;
if (steer_torque_cmd_checks(desired_torque, steer_req, limits)) {

View File

@ -170,7 +170,7 @@ static void hyundai_canfd_rx_hook(const CANPacket_t *to_push) {
// cruise buttons
const int button_addr = hyundai_canfd_alt_buttons ? 0x1aa : 0x1cf;
if (addr == button_addr) {
int main_button = 0;
bool main_button = false;
int cruise_button = 0;
if (addr == 0x1cf) {
cruise_button = GET_BYTE(to_push, 2) & 0x7U;
@ -186,15 +186,15 @@ static void hyundai_canfd_rx_hook(const CANPacket_t *to_push) {
if ((addr == 0x35) && hyundai_ev_gas_signal) {
gas_pressed = GET_BYTE(to_push, 5) != 0U;
} else if ((addr == 0x105) && hyundai_hybrid_gas_signal) {
gas_pressed = (GET_BIT(to_push, 103U) != 0U) || (GET_BYTE(to_push, 13) != 0U) || (GET_BIT(to_push, 112U) != 0U);
gas_pressed = GET_BIT(to_push, 103U) || (GET_BYTE(to_push, 13) != 0U) || GET_BIT(to_push, 112U);
} else if ((addr == 0x100) && !hyundai_ev_gas_signal && !hyundai_hybrid_gas_signal) {
gas_pressed = GET_BIT(to_push, 176U) != 0U;
gas_pressed = GET_BIT(to_push, 176U);
} else {
}
// brake press
if (addr == 0x175) {
brake_pressed = GET_BIT(to_push, 81U) != 0U;
brake_pressed = GET_BIT(to_push, 81U);
}
// vehicle moving
@ -235,7 +235,7 @@ static bool hyundai_canfd_tx_hook(const CANPacket_t *to_send) {
const int steer_addr = (hyundai_canfd_hda2 && !hyundai_longitudinal) ? hyundai_canfd_hda2_get_lkas_addr() : 0x12a;
if (addr == steer_addr) {
int desired_torque = (((GET_BYTE(to_send, 6) & 0xFU) << 7U) | (GET_BYTE(to_send, 5) >> 1U)) - 1024U;
bool steer_req = GET_BIT(to_send, 52U) != 0U;
bool steer_req = GET_BIT(to_send, 52U);
if (steer_torque_cmd_checks(desired_torque, steer_req, HYUNDAI_CANFD_STEERING_LIMITS)) {
tx = false;

View File

@ -45,7 +45,7 @@ void hyundai_common_init(uint16_t param) {
#endif
}
void hyundai_common_cruise_state_check(const int cruise_engaged) {
void hyundai_common_cruise_state_check(const bool cruise_engaged) {
// some newer HKG models can re-enable after spamming cancel button,
// so keep track of user button presses to deny engagement if no interaction
@ -62,9 +62,8 @@ void hyundai_common_cruise_state_check(const int cruise_engaged) {
}
}
void hyundai_common_cruise_buttons_check(const int cruise_button, const int main_button) {
if ((cruise_button == HYUNDAI_BTN_RESUME) || (cruise_button == HYUNDAI_BTN_SET) || (cruise_button == HYUNDAI_BTN_CANCEL) ||
(main_button != 0)) {
void hyundai_common_cruise_buttons_check(const int cruise_button, const bool main_button) {
if ((cruise_button == HYUNDAI_BTN_RESUME) || (cruise_button == HYUNDAI_BTN_SET) || (cruise_button == HYUNDAI_BTN_CANCEL) || main_button) {
hyundai_last_button_interaction = 0U;
} else {
hyundai_last_button_interaction = MIN(hyundai_last_button_interaction + 1U, HYUNDAI_PREV_BUTTON_SAMPLES);

View File

@ -129,7 +129,7 @@ static int nissan_fwd_hook(int bus_num, int addr) {
int bus_fwd = -1;
if (bus_num == 0) {
int block_msg = (addr == 0x280); // CANCEL_MSG
bool block_msg = (addr == 0x280); // CANCEL_MSG
if (!block_msg) {
bus_fwd = 2; // ADAS
}
@ -137,7 +137,7 @@ static int nissan_fwd_hook(int bus_num, int addr) {
if (bus_num == 2) {
// 0x169 is LKAS, 0x2b1 LKAS_HUD, 0x4cc LKAS_HUD_INFO_MSG
int block_msg = ((addr == 0x169) || (addr == 0x2b1) || (addr == 0x4cc));
bool block_msg = ((addr == 0x169) || (addr == 0x2b1) || (addr == 0x4cc));
if (!block_msg) {
bus_fwd = 0; // V-CAN
}

View File

@ -152,7 +152,7 @@ static void subaru_rx_hook(const CANPacket_t *to_push) {
// enter controls on rising edge of ACC, exit controls on ACC off
if ((addr == MSG_SUBARU_CruiseControl) && (bus == alt_main_bus)) {
bool cruise_engaged = GET_BIT(to_push, 41U) != 0U;
bool cruise_engaged = GET_BIT(to_push, 41U);
pcm_cruise_check(cruise_engaged);
}
@ -169,7 +169,7 @@ static void subaru_rx_hook(const CANPacket_t *to_push) {
}
if ((addr == MSG_SUBARU_Brake_Status) && (bus == alt_main_bus)) {
brake_pressed = GET_BIT(to_push, 62U) != 0U;
brake_pressed = GET_BIT(to_push, 62U);
}
if ((addr == MSG_SUBARU_Throttle) && (bus == SUBARU_MAIN_BUS)) {
@ -189,7 +189,7 @@ static bool subaru_tx_hook(const CANPacket_t *to_send) {
int desired_torque = ((GET_BYTES(to_send, 0, 4) >> 16) & 0x1FFFU);
desired_torque = -1 * to_signed(desired_torque, 13);
bool steer_req = GET_BIT(to_send, 29U) != 0U;
bool steer_req = GET_BIT(to_send, 29U);
const SteeringLimits limits = subaru_gen2 ? SUBARU_GEN2_STEERING_LIMITS : SUBARU_STEERING_LIMITS;
violation |= steer_torque_cmd_checks(desired_torque, steer_req, limits);
@ -204,7 +204,7 @@ static bool subaru_tx_hook(const CANPacket_t *to_send) {
// check es_distance cruise_throttle limits
if (addr == MSG_SUBARU_ES_Distance) {
int cruise_throttle = (GET_BYTES(to_send, 2, 2) & 0x1FFFU);
bool cruise_cancel = GET_BIT(to_send, 56U) != 0U;
bool cruise_cancel = GET_BIT(to_send, 56U);
if (subaru_longitudinal) {
violation |= longitudinal_gas_checks(cruise_throttle, SUBARU_LONG_LIMITS);

View File

@ -56,7 +56,7 @@ static void subaru_preglobal_rx_hook(const CANPacket_t *to_push) {
// enter controls on rising edge of ACC, exit controls on ACC off
if (addr == MSG_SUBARU_PG_CruiseControl) {
bool cruise_engaged = GET_BIT(to_push, 49U) != 0U;
bool cruise_engaged = GET_BIT(to_push, 49U);
pcm_cruise_check(cruise_engaged);
}
@ -86,7 +86,7 @@ static bool subaru_preglobal_tx_hook(const CANPacket_t *to_send) {
int desired_torque = ((GET_BYTES(to_send, 0, 4) >> 8) & 0x1FFFU);
desired_torque = -1 * to_signed(desired_torque, 13);
bool steer_req = (GET_BIT(to_send, 24U) != 0U);
bool steer_req = GET_BIT(to_send, 24U);
if (steer_torque_cmd_checks(desired_torque, steer_req, SUBARU_PG_STEERING_LIMITS)) {
tx = false;
@ -104,7 +104,7 @@ static int subaru_preglobal_fwd_hook(int bus_num, int addr) {
}
if (bus_num == SUBARU_PG_CAM_BUS) {
int block_msg = ((addr == MSG_SUBARU_PG_ES_Distance) || (addr == MSG_SUBARU_PG_ES_LKAS));
bool block_msg = ((addr == MSG_SUBARU_PG_ES_Distance) || (addr == MSG_SUBARU_PG_ES_LKAS));
if (!block_msg) {
bus_fwd = SUBARU_PG_MAIN_BUS; // Main CAN
}

View File

@ -19,6 +19,7 @@ const LongitudinalLimits TESLA_LONG_LIMITS = {
const int TESLA_FLAG_POWERTRAIN = 1;
const int TESLA_FLAG_LONGITUDINAL_CONTROL = 2;
const int TESLA_FLAG_RAVEN = 4;
const CanMsg TESLA_TX_MSGS[] = {
{0x488, 0, 4}, // DAS_steeringControl
@ -41,6 +42,16 @@ RxCheck tesla_rx_checks[] = {
{.msg = {{0x318, 0, 8, .frequency = 10U}, { 0 }, { 0 }}}, // GTW_carState
};
RxCheck tesla_raven_rx_checks[] = {
{.msg = {{0x2b9, 2, 8, .frequency = 25U}, { 0 }, { 0 }}}, // DAS_control
{.msg = {{0x131, 2, 8, .frequency = 100U}, { 0 }, { 0 }}}, // EPAS3P_sysStatus
{.msg = {{0x108, 0, 8, .frequency = 100U}, { 0 }, { 0 }}}, // DI_torque1
{.msg = {{0x118, 0, 6, .frequency = 100U}, { 0 }, { 0 }}}, // DI_torque2
{.msg = {{0x20a, 0, 8, .frequency = 50U}, { 0 }, { 0 }}}, // BrakeMessage
{.msg = {{0x368, 0, 8, .frequency = 10U}, { 0 }, { 0 }}}, // DI_state
{.msg = {{0x318, 0, 8, .frequency = 10U}, { 0 }, { 0 }}}, // GTW_carState
};
RxCheck tesla_pt_rx_checks[] = {
{.msg = {{0x106, 0, 8, .frequency = 100U}, { 0 }, { 0 }}}, // DI_torque1
{.msg = {{0x116, 0, 6, .frequency = 100U}, { 0 }, { 0 }}}, // DI_torque2
@ -51,6 +62,7 @@ RxCheck tesla_pt_rx_checks[] = {
bool tesla_longitudinal = false;
bool tesla_powertrain = false; // Are we the second panda intercepting the powertrain bus?
bool tesla_raven = false;
bool tesla_stock_aeb = false;
@ -58,16 +70,16 @@ static void tesla_rx_hook(const CANPacket_t *to_push) {
int bus = GET_BUS(to_push);
int addr = GET_ADDR(to_push);
if(bus == 0) {
if (!tesla_powertrain) {
if(addr == 0x370) {
// Steering angle: (0.1 * val) - 819.2 in deg.
// Store it 1/10 deg to match steering request
int angle_meas_new = (((GET_BYTE(to_push, 4) & 0x3FU) << 8) | GET_BYTE(to_push, 5)) - 8192U;
update_sample(&angle_meas, angle_meas_new);
}
if (!tesla_powertrain) {
if((!tesla_raven && (addr == 0x370) && (bus == 0)) || (tesla_raven && (addr == 0x131) && (bus == 2))) {
// Steering angle: (0.1 * val) - 819.2 in deg.
// Store it 1/10 deg to match steering request
int angle_meas_new = (((GET_BYTE(to_push, 4) & 0x3FU) << 8) | GET_BYTE(to_push, 5)) - 8192U;
update_sample(&angle_meas, angle_meas_new);
}
}
if(bus == 0) {
if(addr == (tesla_powertrain ? 0x116 : 0x118)) {
// Vehicle speed: ((0.05 * val) - 25) * MPH_TO_MPS
float speed = (((((GET_BYTE(to_push, 3) & 0x0FU) << 8) | (GET_BYTE(to_push, 2))) * 0.05) - 25) * 0.447;
@ -206,12 +218,15 @@ static int tesla_fwd_hook(int bus_num, int addr) {
static safety_config tesla_init(uint16_t param) {
tesla_powertrain = GET_FLAG(param, TESLA_FLAG_POWERTRAIN);
tesla_longitudinal = GET_FLAG(param, TESLA_FLAG_LONGITUDINAL_CONTROL);
tesla_raven = GET_FLAG(param, TESLA_FLAG_RAVEN);
tesla_stock_aeb = false;
safety_config ret;
if (tesla_powertrain) {
ret = BUILD_SAFETY_CFG(tesla_pt_rx_checks, TESLA_PT_TX_MSGS);
} else if (tesla_raven) {
ret = BUILD_SAFETY_CFG(tesla_raven_rx_checks, TESLA_TX_MSGS);
} else {
ret = BUILD_SAFETY_CFG(tesla_rx_checks, TESLA_TX_MSGS);
}

View File

@ -37,24 +37,23 @@ const LongitudinalLimits TOYOTA_LONG_LIMITS = {
.min_accel = -3500, // -3.5 m/s2
};
// panda interceptor threshold needs to be equivalent to openpilot threshold to avoid controls mismatches
// If thresholds are mismatched then it is possible for panda to see the gas fall and rise while openpilot is in the pre-enabled state
// Threshold calculated from DBC gains: round((((15 + 75.555) / 0.159375) + ((15 + 151.111) / 0.159375)) / 2) = 805
const int TOYOTA_GAS_INTERCEPTOR_THRSLD = 805;
#define TOYOTA_GET_INTERCEPTOR(msg) (((GET_BYTE((msg), 0) << 8) + GET_BYTE((msg), 1) + (GET_BYTE((msg), 2) << 8) + GET_BYTE((msg), 3)) / 2U) // avg between 2 tracks
// Stock longitudinal
#define TOYOTA_COMMON_TX_MSGS \
{0x2E4, 0, 5}, {0x191, 0, 8}, {0x412, 0, 8}, {0x343, 0, 8}, {0x1D2, 0, 8}, /* LKAS + LTA + ACC & PCM cancel cmds */ \
#define TOYOTA_COMMON_TX_MSGS \
#define TOYOTA_COMMON_LONG_TX_MSGS \
TOYOTA_COMMON_TX_MSGS \
{0x283, 0, 7}, {0x2E6, 0, 8}, {0x2E7, 0, 8}, {0x33E, 0, 7}, {0x344, 0, 8}, {0x365, 0, 7}, {0x366, 0, 7}, {0x4CB, 0, 8}, /* DSU bus 0 */ \
{0x128, 1, 6}, {0x141, 1, 4}, {0x160, 1, 8}, {0x161, 1, 7}, {0x470, 1, 4}, /* DSU bus 1 */ \
{0x2E4, 0, 5}, {0x191, 0, 8}, {0x411, 0, 8}, {0x412, 0, 8}, {0x343, 0, 8}, {0x1D2, 0, 8}, /* LKAS + ACC */ \
{0x411, 0, 8}, /* PCS_HUD */ \
{0x750, 0, 8}, /* radar diagnostic address */ \
const CanMsg TOYOTA_TX_MSGS[] = {
TOYOTA_COMMON_TX_MSGS
};
const CanMsg TOYOTA_INTERCEPTOR_TX_MSGS[] = {
TOYOTA_COMMON_TX_MSGS
{0x200, 0, 6}, // gas interceptor
const CanMsg TOYOTA_LONG_TX_MSGS[] = {
TOYOTA_COMMON_LONG_TX_MSGS
};
#define TOYOTA_COMMON_RX_CHECKS(lta) \
@ -68,21 +67,11 @@ RxCheck toyota_lka_rx_checks[] = {
TOYOTA_COMMON_RX_CHECKS(false)
};
RxCheck toyota_lka_interceptor_rx_checks[] = {
TOYOTA_COMMON_RX_CHECKS(false)
{.msg = {{0x201, 0, 6, .check_checksum = false, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
};
// Check the quality flag for angle measurement when using LTA, since it's not set on TSS-P cars
RxCheck toyota_lta_rx_checks[] = {
TOYOTA_COMMON_RX_CHECKS(true)
};
RxCheck toyota_lta_interceptor_rx_checks[] = {
TOYOTA_COMMON_RX_CHECKS(true)
{.msg = {{0x201, 0, 6, .check_checksum = false, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
};
// safety param flags
// first byte is for EPS factor, second is for flags
const uint32_t TOYOTA_PARAM_OFFSET = 8U;
@ -90,7 +79,6 @@ const uint32_t TOYOTA_EPS_FACTOR = (1UL << TOYOTA_PARAM_OFFSET) - 1U;
const uint32_t TOYOTA_PARAM_ALT_BRAKE = 1UL << TOYOTA_PARAM_OFFSET;
const uint32_t TOYOTA_PARAM_STOCK_LONGITUDINAL = 2UL << TOYOTA_PARAM_OFFSET;
const uint32_t TOYOTA_PARAM_LTA = 4UL << TOYOTA_PARAM_OFFSET;
const uint32_t TOYOTA_PARAM_GAS_INTERCEPTOR = 8UL << TOYOTA_PARAM_OFFSET;
bool toyota_alt_brake = false;
bool toyota_stock_longitudinal = false;
@ -112,23 +100,12 @@ static uint32_t toyota_get_checksum(const CANPacket_t *to_push) {
return (uint8_t)(GET_BYTE(to_push, checksum_byte));
}
static uint8_t toyota_get_counter(const CANPacket_t *to_push) {
int addr = GET_ADDR(to_push);
uint8_t cnt = 0U;
if (addr == 0x201) {
// Signal: COUNTER_PEDAL
cnt = GET_BYTE(to_push, 4) & 0x0FU;
}
return cnt;
}
static bool toyota_get_quality_flag_valid(const CANPacket_t *to_push) {
int addr = GET_ADDR(to_push);
bool valid = false;
if (addr == 0x260) {
valid = GET_BIT(to_push, 3U) == 0U; // STEER_ANGLE_INITIALIZING
valid = !GET_BIT(to_push, 3U); // STEER_ANGLE_INITIALIZING
}
return valid;
}
@ -159,7 +136,7 @@ static void toyota_rx_hook(const CANPacket_t *to_push) {
// LTA request angle should match current angle while inactive, clipped to max accepted angle.
// note that angle can be relative to init angle on some TSS2 platforms, LTA has the same offset
bool steer_angle_initializing = GET_BIT(to_push, 3U) != 0U;
bool steer_angle_initializing = GET_BIT(to_push, 3U);
if (!steer_angle_initializing) {
int angle_meas_new = (GET_BYTE(to_push, 3) << 8U) | GET_BYTE(to_push, 4);
angle_meas_new = CLAMP(to_signed(angle_meas_new, 16), -TOYOTA_LTA_MAX_ANGLE, TOYOTA_LTA_MAX_ANGLE);
@ -171,13 +148,11 @@ static void toyota_rx_hook(const CANPacket_t *to_push) {
// exit controls on rising edge of gas press
if (addr == 0x1D2) {
// 5th bit is CRUISE_ACTIVE
bool cruise_engaged = GET_BIT(to_push, 5U) != 0U;
bool cruise_engaged = GET_BIT(to_push, 5U);
pcm_cruise_check(cruise_engaged);
// sample gas pedal
if (!enable_gas_interceptor) {
gas_pressed = GET_BIT(to_push, 4U) == 0U;
}
gas_pressed = !GET_BIT(to_push, 4U);
}
// sample speed
@ -197,19 +172,14 @@ static void toyota_rx_hook(const CANPacket_t *to_push) {
// most cars have brake_pressed on 0x226, corolla and rav4 on 0x224
if (((addr == 0x224) && toyota_alt_brake) || ((addr == 0x226) && !toyota_alt_brake)) {
uint8_t bit = (addr == 0x224) ? 5U : 37U;
brake_pressed = GET_BIT(to_push, bit) != 0U;
brake_pressed = GET_BIT(to_push, bit);
}
// sample gas interceptor
if ((addr == 0x201) && enable_gas_interceptor) {
int gas_interceptor = TOYOTA_GET_INTERCEPTOR(to_push);
gas_pressed = gas_interceptor > TOYOTA_GAS_INTERCEPTOR_THRSLD;
// TODO: remove this, only left in for gas_interceptor_prev test
gas_interceptor_prev = gas_interceptor;
bool stock_ecu_detected = addr == 0x2E4; // STEERING_LKA
if (!toyota_stock_longitudinal && (addr == 0x343)) {
stock_ecu_detected = true; // ACC_CONTROL
}
generic_rx_checks((addr == 0x2E4));
generic_rx_checks(stock_ecu_detected);
}
}
@ -220,14 +190,6 @@ static bool toyota_tx_hook(const CANPacket_t *to_send) {
// Check if msg is sent on BUS 0
if (bus == 0) {
// GAS PEDAL: safety check
if (addr == 0x200) {
if (longitudinal_interceptor_checks(to_send)) {
tx = false;
}
}
// ACCEL: safety check on byte 1-2
if (addr == 0x343) {
int desired_accel = (GET_BYTE(to_send, 0) << 8) | GET_BYTE(to_send, 1);
@ -238,7 +200,7 @@ static bool toyota_tx_hook(const CANPacket_t *to_send) {
// only ACC messages that cancel are allowed when openpilot is not controlling longitudinal
if (toyota_stock_longitudinal) {
bool cancel_req = GET_BIT(to_send, 24U) != 0U;
bool cancel_req = GET_BIT(to_send, 24U);
if (!cancel_req) {
violation = true;
}
@ -264,8 +226,8 @@ static bool toyota_tx_hook(const CANPacket_t *to_send) {
// LTA angle steering check
if (addr == 0x191) {
// check the STEER_REQUEST, STEER_REQUEST_2, TORQUE_WIND_DOWN, STEER_ANGLE_CMD signals
bool lta_request = GET_BIT(to_send, 0U) != 0U;
bool lta_request2 = GET_BIT(to_send, 25U) != 0U;
bool lta_request = GET_BIT(to_send, 0U);
bool lta_request2 = GET_BIT(to_send, 25U);
int torque_wind_down = GET_BYTE(to_send, 5);
int lta_angle = (GET_BYTE(to_send, 1) << 8) | GET_BYTE(to_send, 2);
lta_angle = to_signed(lta_angle, 16);
@ -313,7 +275,7 @@ static bool toyota_tx_hook(const CANPacket_t *to_send) {
if (addr == 0x2E4) {
int desired_torque = (GET_BYTE(to_send, 1) << 8) | GET_BYTE(to_send, 2);
desired_torque = to_signed(desired_torque, 16);
bool steer_req = GET_BIT(to_send, 0U) != 0U;
bool steer_req = GET_BIT(to_send, 0U);
// When using LTA (angle control), assert no actuation on LKA message
if (!toyota_lta) {
if (steer_torque_cmd_checks(desired_torque, steer_req, TOYOTA_STEERING_LIMITS)) {
@ -327,6 +289,15 @@ static bool toyota_tx_hook(const CANPacket_t *to_send) {
}
}
// UDS: Only tester present ("\x0F\x02\x3E\x00\x00\x00\x00\x00") allowed on diagnostics address
if (addr == 0x750) {
// this address is sub-addressed. only allow tester present to radar (0xF)
bool invalid_uds_msg = (GET_BYTES(to_send, 0, 4) != 0x003E020FU) || (GET_BYTES(to_send, 4, 4) != 0x0U);
if (invalid_uds_msg) {
tx = 0;
}
}
return tx;
}
@ -334,22 +305,17 @@ static safety_config toyota_init(uint16_t param) {
toyota_alt_brake = GET_FLAG(param, TOYOTA_PARAM_ALT_BRAKE);
toyota_stock_longitudinal = GET_FLAG(param, TOYOTA_PARAM_STOCK_LONGITUDINAL);
toyota_lta = GET_FLAG(param, TOYOTA_PARAM_LTA);
enable_gas_interceptor = GET_FLAG(param, TOYOTA_PARAM_GAS_INTERCEPTOR);
toyota_dbc_eps_torque_factor = param & TOYOTA_EPS_FACTOR;
// Gas interceptor should not be used if openpilot is not controlling longitudinal
safety_config ret;
if (toyota_stock_longitudinal) {
enable_gas_interceptor = false;
SET_TX_MSGS(TOYOTA_TX_MSGS, ret);
} else {
SET_TX_MSGS(TOYOTA_LONG_TX_MSGS, ret);
}
safety_config ret;
if (toyota_lta) {
ret = enable_gas_interceptor ? BUILD_SAFETY_CFG(toyota_lta_interceptor_rx_checks, TOYOTA_INTERCEPTOR_TX_MSGS) : \
BUILD_SAFETY_CFG(toyota_lta_rx_checks, TOYOTA_TX_MSGS);
} else {
ret = enable_gas_interceptor ? BUILD_SAFETY_CFG(toyota_lka_interceptor_rx_checks, TOYOTA_INTERCEPTOR_TX_MSGS) : \
BUILD_SAFETY_CFG(toyota_lka_rx_checks, TOYOTA_TX_MSGS);
}
toyota_lta ? SET_RX_CHECKS(toyota_lta_rx_checks, ret) : \
SET_RX_CHECKS(toyota_lka_rx_checks, ret);
return ret;
}
@ -364,10 +330,10 @@ static int toyota_fwd_hook(int bus_num, int addr) {
if (bus_num == 2) {
// block stock lkas messages and stock acc messages (if OP is doing ACC)
// in TSS2, 0x191 is LTA which we need to block to avoid controls collision
int is_lkas_msg = ((addr == 0x2E4) || (addr == 0x412) || (addr == 0x191));
bool is_lkas_msg = ((addr == 0x2E4) || (addr == 0x412) || (addr == 0x191));
// in TSS2 the camera does ACC as well, so filter 0x343
int is_acc_msg = (addr == 0x343);
int block_msg = is_lkas_msg || (is_acc_msg && !toyota_stock_longitudinal);
bool is_acc_msg = (addr == 0x343);
bool block_msg = is_lkas_msg || (is_acc_msg && !toyota_stock_longitudinal);
if (!block_msg) {
bus_fwd = 0;
}
@ -383,6 +349,5 @@ const safety_hooks toyota_hooks = {
.fwd = toyota_fwd_hook,
.get_checksum = toyota_get_checksum,
.compute_checksum = toyota_compute_checksum,
.get_counter = toyota_get_counter,
.get_quality_flag_valid = toyota_get_quality_flag_valid,
};

View File

@ -46,6 +46,7 @@ RxCheck volkswagen_mqb_rx_checks[] = {
{.msg = {{MSG_TSK_06, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MSG_MOTOR_20, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MSG_MOTOR_14, 0, 8, .check_checksum = false, .max_counter = 0U, .frequency = 10U}, { 0 }, { 0 }}},
{.msg = {{MSG_GRA_ACC_01, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 33U}, { 0 }, { 0 }}},
};
uint8_t volkswagen_crc8_lut_8h2f[256]; // Static lookup table for CRC8 poly 0x2F, aka 8H2F/AUTOSAR
@ -83,6 +84,8 @@ static uint32_t volkswagen_mqb_compute_crc(const CANPacket_t *to_push) {
crc ^= (uint8_t[]){0xC4,0xE2,0x4F,0xE4,0xF8,0x2F,0x56,0x81,0x9F,0xE5,0x83,0x44,0x05,0x3F,0x97,0xDF}[counter];
} else if (addr == MSG_MOTOR_20) {
crc ^= (uint8_t[]){0xE9,0x65,0xAE,0x6B,0x7B,0x35,0xE5,0x5F,0x4E,0xC7,0x86,0xA2,0xBB,0xDD,0xEB,0xB4}[counter];
} else if (addr == MSG_GRA_ACC_01) {
crc ^= (uint8_t[]){0x6A,0x38,0xB4,0x27,0x22,0xEF,0xE1,0xBB,0xF8,0x80,0x84,0x49,0xC7,0x9E,0x1E,0x2B}[counter];
} else {
// Undefined CAN message, CRC check expected to fail
}
@ -167,7 +170,7 @@ static void volkswagen_mqb_rx_hook(const CANPacket_t *to_push) {
}
// Always exit controls on rising edge of Cancel
// Signal: GRA_ACC_01.GRA_Abbrechen
if (GET_BIT(to_push, 13U) == 1U) {
if (GET_BIT(to_push, 13U)) {
controls_allowed = false;
}
}
@ -207,7 +210,7 @@ static bool volkswagen_mqb_tx_hook(const CANPacket_t *to_send) {
desired_torque *= -1;
}
bool steer_req = GET_BIT(to_send, 30U) != 0U;
bool steer_req = GET_BIT(to_send, 30U);
if (steer_torque_cmd_checks(desired_torque, steer_req, VOLKSWAGEN_MQB_STEERING_LIMITS)) {
tx = false;

View File

@ -141,7 +141,7 @@ static void volkswagen_pq_rx_hook(const CANPacket_t *to_push) {
volkswagen_resume_button_prev = resume_button;
// Exit controls on rising edge of Cancel, override Set/Resume if present simultaneously
// Signal: GRA_ACC_01.GRA_Abbrechen
if (GET_BIT(to_push, 9U) == 1U) {
if (GET_BIT(to_push, 9U)) {
controls_allowed = false;
}
}
@ -185,7 +185,7 @@ static bool volkswagen_pq_tx_hook(const CANPacket_t *to_send) {
}
uint32_t hca_status = ((GET_BYTE(to_send, 1) >> 4) & 0xFU);
bool steer_req = (hca_status == 5U);
bool steer_req = ((hca_status == 5U) || (hca_status == 7U));
if (steer_torque_cmd_checks(desired_torque, steer_req, VOLKSWAGEN_PQ_STEERING_LIMITS)) {
tx = false;

View File

@ -1,6 +1,6 @@
#pragma once
#define GET_BIT(msg, b) (((msg)->data[((b) / 8U)] >> ((b) % 8U)) & 0x1U)
#define GET_BIT(msg, b) ((bool)!!(((msg)->data[((b) / 8U)] >> ((b) % 8U)) & 0x1U))
#define GET_BYTE(msg, b) ((msg)->data[(b)])
#define GET_FLAG(value, mask) (((__typeof__(mask))(value) & (mask)) == (mask))
@ -15,7 +15,7 @@
uint32_t GET_BYTES(const CANPacket_t *msg, int start, int len) {
uint32_t ret = 0U;
for (int i = 0; i < len; i++) {
const uint8_t shift = i * 8;
const uint32_t shift = i * 8;
ret |= (((uint32_t)msg->data[start + i]) << shift);
}
return ret;
@ -203,7 +203,6 @@ bool longitudinal_speed_checks(int desired_speed, const LongitudinalLimits limit
bool longitudinal_gas_checks(int desired_gas, const LongitudinalLimits limits);
bool longitudinal_transmission_rpm_checks(int desired_transmission_rpm, const LongitudinalLimits limits);
bool longitudinal_brake_checks(int desired_brake, const LongitudinalLimits limits);
bool longitudinal_interceptor_checks(const CANPacket_t *to_send);
void pcm_cruise_check(bool cruise_engaged);
void safety_tick(const safety_config *safety_config);
@ -211,8 +210,6 @@ void safety_tick(const safety_config *safety_config);
// This can be set by the safety hooks
bool controls_allowed = false;
bool relay_malfunction = false;
bool enable_gas_interceptor = false;
int gas_interceptor_prev = 0;
bool gas_pressed = false;
bool gas_pressed_prev = false;
bool brake_pressed = false;

39
board/stm32f4/board.h Normal file
View File

@ -0,0 +1,39 @@
// ///////////////////////////////////////////////////////////// //
// Hardware abstraction layer for all different supported boards //
// ///////////////////////////////////////////////////////////// //
#include "boards/board_declarations.h"
#include "boards/unused_funcs.h"
// ///// Board definition and detection ///// //
#include "stm32f4/lladc.h"
#include "drivers/harness.h"
#include "drivers/fan.h"
#include "stm32f4/llfan.h"
#include "drivers/clock_source.h"
#include "boards/white.h"
#include "boards/grey.h"
#include "boards/black.h"
#include "boards/uno.h"
#include "boards/dos.h"
void detect_board_type(void) {
// SPI lines floating: white (TODO: is this reliable? Not really, we have to enable ESP/GPS to be able to detect this on the UART)
set_gpio_output(GPIOC, 14, 1);
set_gpio_output(GPIOC, 5, 1);
if(!detect_with_pull(GPIOB, 1, PULL_UP) && !detect_with_pull(GPIOB, 7, PULL_UP)){
hw_type = HW_TYPE_DOS;
current_board = &board_dos;
} else if((detect_with_pull(GPIOA, 4, PULL_DOWN)) || (detect_with_pull(GPIOA, 5, PULL_DOWN)) || (detect_with_pull(GPIOA, 6, PULL_DOWN)) || (detect_with_pull(GPIOA, 7, PULL_DOWN))){
hw_type = HW_TYPE_WHITE_PANDA;
current_board = &board_white;
} else if(detect_with_pull(GPIOA, 13, PULL_DOWN)) { // Rev AB deprecated, so no pullup means black. In REV C, A13 is pulled up to 5V with a 10K
hw_type = HW_TYPE_GREY_PANDA;
current_board = &board_grey;
} else if(!detect_with_pull(GPIOB, 15, PULL_UP)) {
hw_type = HW_TYPE_UNO;
current_board = &board_uno;
} else {
hw_type = HW_TYPE_BLACK_PANDA;
current_board = &board_black;
}
}

View File

@ -1,7 +1,7 @@
void clock_init(void) {
// enable external oscillator
register_set_bits(&(RCC->CR), RCC_CR_HSEON);
while ((RCC->CR & RCC_CR_HSERDY) == 0);
while ((RCC->CR & RCC_CR_HSERDY) == 0U);
// divide things
// AHB = 96MHz
@ -20,7 +20,7 @@ void clock_init(void) {
// start PLL
register_set_bits(&(RCC->CR), RCC_CR_PLLON);
while ((RCC->CR & RCC_CR_PLLRDY) == 0);
while ((RCC->CR & RCC_CR_PLLRDY) == 0U);
// Configure Flash prefetch, Instruction cache, Data cache and wait state
// *** without this, it breaks ***

View File

@ -1,5 +1,5 @@
// ********************* Bare interrupt handlers *********************
// Only implemented the STM32F413 interrupts for now, the STM32F203 specific ones do not fall into the scope of SIL2
// Only implemented the STM32F413 interrupts for now
void WWDG_IRQHandler(void) {handle_interrupt(WWDG_IRQn);}
void PVD_IRQHandler(void) {handle_interrupt(PVD_IRQn);}
@ -73,28 +73,26 @@ void DMA2_Stream7_IRQHandler(void) {handle_interrupt(DMA2_Stream7_IRQn);}
void USART6_IRQHandler(void) {handle_interrupt(USART6_IRQn);}
void I2C3_EV_IRQHandler(void) {handle_interrupt(I2C3_EV_IRQn);}
void I2C3_ER_IRQHandler(void) {handle_interrupt(I2C3_ER_IRQn);}
#ifdef STM32F4
void DFSDM1_FLT0_IRQHandler(void) {handle_interrupt(DFSDM1_FLT0_IRQn);}
void DFSDM1_FLT1_IRQHandler(void) {handle_interrupt(DFSDM1_FLT1_IRQn);}
void CAN3_TX_IRQHandler(void) {handle_interrupt(CAN3_TX_IRQn);}
void CAN3_RX0_IRQHandler(void) {handle_interrupt(CAN3_RX0_IRQn);}
void CAN3_RX1_IRQHandler(void) {handle_interrupt(CAN3_RX1_IRQn);}
void CAN3_SCE_IRQHandler(void) {handle_interrupt(CAN3_SCE_IRQn);}
void RNG_IRQHandler(void) {handle_interrupt(RNG_IRQn);}
void FPU_IRQHandler(void) {handle_interrupt(FPU_IRQn);}
void UART7_IRQHandler(void) {handle_interrupt(UART7_IRQn);}
void UART8_IRQHandler(void) {handle_interrupt(UART8_IRQn);}
void SPI4_IRQHandler(void) {handle_interrupt(SPI4_IRQn);}
void SPI5_IRQHandler(void) {handle_interrupt(SPI5_IRQn);}
void SAI1_IRQHandler(void) {handle_interrupt(SAI1_IRQn);}
void UART9_IRQHandler(void) {handle_interrupt(UART9_IRQn);}
void UART10_IRQHandler(void) {handle_interrupt(UART10_IRQn);}
void QUADSPI_IRQHandler(void) {handle_interrupt(QUADSPI_IRQn);}
void FMPI2C1_EV_IRQHandler(void) {handle_interrupt(FMPI2C1_EV_IRQn);}
void FMPI2C1_ER_IRQHandler(void) {handle_interrupt(FMPI2C1_ER_IRQn);}
void LPTIM1_IRQHandler(void) {handle_interrupt(LPTIM1_IRQn);}
void DFSDM2_FLT0_IRQHandler(void) {handle_interrupt(DFSDM2_FLT0_IRQn);}
void DFSDM2_FLT1_IRQHandler(void) {handle_interrupt(DFSDM2_FLT1_IRQn);}
void DFSDM2_FLT2_IRQHandler(void) {handle_interrupt(DFSDM2_FLT2_IRQn);}
void DFSDM2_FLT3_IRQHandler(void) {handle_interrupt(DFSDM2_FLT3_IRQn);}
#endif
void DFSDM1_FLT0_IRQHandler(void) {handle_interrupt(DFSDM1_FLT0_IRQn);}
void DFSDM1_FLT1_IRQHandler(void) {handle_interrupt(DFSDM1_FLT1_IRQn);}
void CAN3_TX_IRQHandler(void) {handle_interrupt(CAN3_TX_IRQn);}
void CAN3_RX0_IRQHandler(void) {handle_interrupt(CAN3_RX0_IRQn);}
void CAN3_RX1_IRQHandler(void) {handle_interrupt(CAN3_RX1_IRQn);}
void CAN3_SCE_IRQHandler(void) {handle_interrupt(CAN3_SCE_IRQn);}
void RNG_IRQHandler(void) {handle_interrupt(RNG_IRQn);}
void FPU_IRQHandler(void) {handle_interrupt(FPU_IRQn);}
void UART7_IRQHandler(void) {handle_interrupt(UART7_IRQn);}
void UART8_IRQHandler(void) {handle_interrupt(UART8_IRQn);}
void SPI4_IRQHandler(void) {handle_interrupt(SPI4_IRQn);}
void SPI5_IRQHandler(void) {handle_interrupt(SPI5_IRQn);}
void SAI1_IRQHandler(void) {handle_interrupt(SAI1_IRQn);}
void UART9_IRQHandler(void) {handle_interrupt(UART9_IRQn);}
void UART10_IRQHandler(void) {handle_interrupt(UART10_IRQn);}
void QUADSPI_IRQHandler(void) {handle_interrupt(QUADSPI_IRQn);}
void FMPI2C1_EV_IRQHandler(void) {handle_interrupt(FMPI2C1_EV_IRQn);}
void FMPI2C1_ER_IRQHandler(void) {handle_interrupt(FMPI2C1_ER_IRQn);}
void LPTIM1_IRQHandler(void) {handle_interrupt(LPTIM1_IRQn);}
void DFSDM2_FLT0_IRQHandler(void) {handle_interrupt(DFSDM2_FLT0_IRQn);}
void DFSDM2_FLT1_IRQHandler(void) {handle_interrupt(DFSDM2_FLT1_IRQn);}
void DFSDM2_FLT2_IRQHandler(void) {handle_interrupt(DFSDM2_FLT2_IRQn);}
void DFSDM2_FLT3_IRQHandler(void) {handle_interrupt(DFSDM2_FLT3_IRQn);}

View File

@ -1,12 +1,3 @@
// ACCEL1 = ADC10
// ACCEL2 = ADC11
// VOLT_S = ADC12
// CURR_S = ADC13
#define ADCCHAN_ACCEL0 10
#define ADCCHAN_ACCEL1 11
#define ADCCHAN_VIN 12
#define ADCCHAN_CURRENT 13
void register_set(volatile uint32_t *addr, uint32_t val, uint32_t mask);

View File

@ -84,12 +84,10 @@ void llcan_irq_disable(const CAN_TypeDef *CANx) {
NVIC_DisableIRQ(CAN2_TX_IRQn);
NVIC_DisableIRQ(CAN2_RX0_IRQn);
NVIC_DisableIRQ(CAN2_SCE_IRQn);
#ifdef CAN3
} else if (CANx == CAN3) {
NVIC_DisableIRQ(CAN3_TX_IRQn);
NVIC_DisableIRQ(CAN3_RX0_IRQn);
NVIC_DisableIRQ(CAN3_SCE_IRQn);
#endif
} else if (CANx == CAN3) {
NVIC_DisableIRQ(CAN3_TX_IRQn);
NVIC_DisableIRQ(CAN3_RX0_IRQn);
NVIC_DisableIRQ(CAN3_SCE_IRQn);
} else {
}
}
@ -103,12 +101,10 @@ void llcan_irq_enable(const CAN_TypeDef *CANx) {
NVIC_EnableIRQ(CAN2_TX_IRQn);
NVIC_EnableIRQ(CAN2_RX0_IRQn);
NVIC_EnableIRQ(CAN2_SCE_IRQn);
#ifdef CAN3
} else if (CANx == CAN3) {
NVIC_EnableIRQ(CAN3_TX_IRQn);
NVIC_EnableIRQ(CAN3_RX0_IRQn);
NVIC_EnableIRQ(CAN3_SCE_IRQn);
#endif
} else if (CANx == CAN3) {
NVIC_EnableIRQ(CAN3_TX_IRQn);
NVIC_EnableIRQ(CAN3_RX0_IRQn);
NVIC_EnableIRQ(CAN3_SCE_IRQn);
} else {
}
}

View File

@ -5,7 +5,7 @@ void uart_tx_ring(uart_ring *q){
// Send out next byte of TX buffer
if (q->w_ptr_tx != q->r_ptr_tx) {
// Only send if transmit register is empty (aka last byte has been sent)
if ((q->uart->SR & USART_SR_TXE) != 0) {
if ((q->uart->SR & USART_SR_TXE) != 0U) {
q->uart->DR = q->elems_tx[q->r_ptr_tx]; // This clears TXE
q->r_ptr_tx = (q->r_ptr_tx + 1U) % q->tx_fifo_size;
}
@ -46,7 +46,7 @@ void uart_rx_ring(uart_ring *q){
}
void uart_send_break(uart_ring *u) {
while ((u->uart->CR1 & USART_CR1_SBK) != 0);
while ((u->uart->CR1 & USART_CR1_SBK) != 0U);
u->uart->CR1 |= USART_CR1_SBK;
}
@ -90,32 +90,3 @@ void USART2_IRQ_Handler(void) { uart_interrupt_handler(&uart_ring_debug); }
void uart_set_baud(USART_TypeDef *u, unsigned int baud) {
u->BRR = USART_BRR_(APB1_FREQ*1000000U, baud);
}
void uart_init(uart_ring *q, int baud) {
if(q->uart != NULL){
// Register interrupts (max data rate: 115200 baud)
if (q->uart == USART2){
REGISTER_INTERRUPT(USART2_IRQn, USART2_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_2)
} else {
// UART not used. Skip registering interrupts
}
// Set baud and enable peripheral with TX and RX mode
uart_set_baud(q->uart, baud);
q->uart->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
if ((q->uart == USART2) || (q->uart == USART3) || (q->uart == UART5)) {
q->uart->CR1 |= USART_CR1_RXNEIE;
}
// Enable UART interrupts
if (q->uart == USART2){
NVIC_EnableIRQ(USART2_IRQn);
} else if (q->uart == USART3){
NVIC_EnableIRQ(USART3_IRQn);
} else if (q->uart == UART5){
NVIC_EnableIRQ(UART5_IRQn);
} else {
// UART not used. Skip enabling interrupts
}
}
}

View File

@ -8,7 +8,7 @@ USB_OTG_GlobalTypeDef *USBx = USB_OTG_FS;
#define USBx_PCGCCTL *(__IO uint32_t *)((uint32_t)USBx + USB_OTG_PCGCCTL_BASE)
#define USBD_FS_TRDT_VALUE 5UL
#define USB_OTG_SPEED_FULL 3
#define USB_OTG_SPEED_FULL 3UL
void usb_irqhandler(void);
@ -27,7 +27,7 @@ void usb_init(void) {
// full speed PHY, do reset and remove power down
/*puth(USBx->GRSTCTL);
print(" resetting PHY\n");*/
while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0);
while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0U);
//print("AHB idle\n");
// reset PHY here
@ -42,7 +42,6 @@ void usb_init(void) {
USBx->GUSBCFG |= ((USBD_FS_TRDT_VALUE << 10) & USB_OTG_GUSBCFG_TRDT);
// power up the PHY
#ifdef STM32F4
USBx->GCCFG = USB_OTG_GCCFG_PWRDWN;
//USBx->GCCFG |= USB_OTG_GCCFG_VBDEN | USB_OTG_GCCFG_SDEN |USB_OTG_GCCFG_PDEN | USB_OTG_GCCFG_DCDEN;
@ -50,9 +49,6 @@ void usb_init(void) {
/* B-peripheral session valid override enable*/
USBx->GOTGCTL |= USB_OTG_GOTGCTL_BVALOVAL;
USBx->GOTGCTL |= USB_OTG_GOTGCTL_BVALOEN;
#else
USBx->GCCFG = USB_OTG_GCCFG_PWRDWN | USB_OTG_GCCFG_NOVBUSSENS;
#endif
// be a device, slowest timings
//USBx->GUSBCFG = USB_OTG_GUSBCFG_FDMOD | USB_OTG_GUSBCFG_PHYSEL | USB_OTG_GUSBCFG_TRDT | USB_OTG_GUSBCFG_TOCAL;

View File

@ -36,14 +36,9 @@ void common_init_gpio(void) {
gpio_usb_init();
// B8,B9: CAN 1
#ifdef STM32F4
set_gpio_alternate(GPIOB, 8, GPIO_AF8_CAN1);
set_gpio_alternate(GPIOB, 9, GPIO_AF8_CAN1);
#else
set_gpio_alternate(GPIOB, 8, GPIO_AF9_CAN1);
set_gpio_alternate(GPIOB, 9, GPIO_AF9_CAN1);
#endif
// B8,B9: CAN 1
set_gpio_alternate(GPIOB, 8, GPIO_AF8_CAN1);
set_gpio_alternate(GPIOB, 9, GPIO_AF8_CAN1);
}
void flasher_peripherals_init(void) {
@ -71,14 +66,10 @@ void peripherals_init(void) {
RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN;
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
RCC->APB1ENR |= RCC_APB1ENR_USART3EN;
#ifndef PEDAL
RCC->APB1ENR |= RCC_APB1ENR_UART5EN;
#endif
RCC->APB1ENR |= RCC_APB1ENR_UART5EN;
RCC->APB1ENR |= RCC_APB1ENR_CAN1EN;
RCC->APB1ENR |= RCC_APB1ENR_CAN2EN;
#ifdef CAN3
RCC->APB1ENR |= RCC_APB1ENR_CAN3EN;
#endif
RCC->APB1ENR |= RCC_APB1ENR_CAN3EN;
// Analog
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
@ -92,7 +83,6 @@ void peripherals_init(void) {
RCC->APB1ENR |= RCC_APB1ENR_TIM5EN; // k-line init
RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; // interrupt timer
RCC->APB2ENR |= RCC_APB2ENR_TIM9EN; // slow loop
RCC->APB1ENR |= RCC_APB1ENR_TIM12EN; // gmlan_alt
}
void enable_interrupt_timer(void) {

Some files were not shown because too many files have changed in this diff Show More