diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index ee2e144b..82bc2345 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -80,4 +80,4 @@ jobs: - name: tests/misra/install.sh run: ${{ env.RUN }} "cd tests/misra && ./install.sh" - name: MISRA mutation tests - run: ${{ env.RUN }} "cd tests/misra && pytest -n2 test_mutation.py" + run: ${{ env.RUN }} "cd tests/misra && pytest test_mutation.py" diff --git a/.gitignore b/.gitignore index 378d327f..612b14f7 100644 --- a/.gitignore +++ b/.gitignore @@ -22,9 +22,11 @@ nosetests.xml .mypy_cache/ .sconsign.dblite uv.lock +compile_commands.json # CTU info files generated by Cppcheck *.*.ctu-info +cppcheck-addon-ctu-file-list # safety coverage-related files *.gcda diff --git a/Dockerfile b/Dockerfile index 88190b08..a8a80e97 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,19 @@ FROM ubuntu:24.04 +ENV WORKDIR=/tmp/panda/ ENV PYTHONUNBUFFERED=1 -ENV PYTHONPATH=/tmp/pythonpath +ENV PATH="$WORKDIR/.venv/bin:$PATH" + +WORKDIR $WORKDIR # deps install -COPY pyproject.toml __init__.py setup.sh /tmp/ -COPY python/__init__.py /tmp/python/ -ENV DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y --no-install-recommends sudo && /tmp/setup.sh +COPY pyproject.toml __init__.py setup.sh $WORKDIR +RUN mkdir -p $WORKDIR/python/ && touch $WORKDIR/__init__.py +RUN apt-get update && apt-get install -y --no-install-recommends sudo && DEBIAN_FRONTEND=noninteractive $WORKDIR/setup.sh -COPY pyproject.toml __init__.py $PYTHONPATH/panda/ -COPY python/__init__.py $PYTHONPATH/panda/python/ -RUN pip3 install --break-system-packages --no-cache-dir $PYTHONPATH/panda/[dev] +# second pass for the opendbc moving tag +ARG CACHEBUST=1 +RUN DEBIAN_FRONTEND=noninteractive $WORKDIR/setup.sh -RUN git config --global --add safe.directory $PYTHONPATH/panda - -# for Jenkins -COPY README.md panda.tar.* /tmp/ -RUN mkdir -p /tmp/pythonpath/panda && \ - tar -xvf /tmp/panda.tar.gz -C /tmp/pythonpath/panda/ || true +RUN git config --global --add safe.directory $WORKDIR/panda +COPY . $WORKDIR diff --git a/Jenkinsfile b/Jenkinsfile index da692afe..25e386a0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -4,7 +4,6 @@ def docker_run(String step_label, int timeout_mins, String cmd) { --env PYTHONWARNINGS=error \ --volume /dev/bus/usb:/dev/bus/usb \ --volume /var/run/dbus:/var/run/dbus \ - --workdir /tmp/pythonpath/panda \ --net host \ ${env.DOCKER_IMAGE_TAG} \ bash -c 'scons -j8 && ${cmd}'", \ @@ -35,6 +34,9 @@ export PYTHONPATH=${env.TEST_DIR}/../ export PYTHONWARNINGS=error ln -sf /data/openpilot/opendbc_repo/opendbc /data/opendbc +# TODO: this is an agnos issue +export PYTEST_ADDOPTS="-p no:asyncio" + cd ${env.TEST_DIR} || true ${cmd} exit 0 @@ -83,8 +85,7 @@ pipeline { steps { timeout(time: 20, unit: 'MINUTES') { script { - sh 'git archive -v -o panda.tar.gz --format=tar.gz HEAD' - dockerImage = docker.build("${env.DOCKER_IMAGE_TAG}") + dockerImage = docker.build("${env.DOCKER_IMAGE_TAG}", "--build-arg CACHEBUST=${env.BUILD_NUMBER} .") } } } @@ -108,7 +109,7 @@ pipeline { ["build", "scons -j4"], ["flash", "cd scripts/ && ./reflash_internal_panda.py"], ["flash jungle", "cd board/jungle && ./flash.py --all"], - ["test", "cd tests/hitl && HW_TYPES=10 pytest -n0 --durations=0 2*.py [5-9]*.py"], + ["test", "cd tests/hitl && HW_TYPES=10 pytest --durations=0 2*.py [5-9]*.py"], ]) } } @@ -120,7 +121,7 @@ pipeline { ["build", "scons -j4"], ["flash", "cd scripts/ && ./reflash_internal_panda.py"], ["flash jungle", "cd board/jungle && ./flash.py --all"], - ["test", "cd tests/hitl && HW_TYPES=9 pytest -n0 --durations=0 2*.py [5-9]*.py"], + ["test", "cd tests/hitl && HW_TYPES=9 pytest --durations=0 2*.py [5-9]*.py"], ]) } } @@ -132,7 +133,7 @@ pipeline { ["build", "scons -j4"], ["flash", "cd scripts/ && ./reflash_internal_panda.py"], ["flash jungle", "cd board/jungle && ./flash.py --all"], - ["test", "cd tests/hitl && HW_TYPES=6 pytest -n0 --durations=0 [2-9]*.py -k 'not test_send_recv'"], + ["test", "cd tests/hitl && HW_TYPES=6 pytest --durations=0 [2-9]*.py -k 'not test_send_recv'"], ]) } } @@ -140,7 +141,7 @@ pipeline { stage('bootkick tests') { steps { script { - docker_run("test", 10, "pytest -n0 ./tests/som/test_bootkick.py") + docker_run("test", 10, "pytest ./tests/som/test_bootkick.py") } } } diff --git a/SConscript b/SConscript index 1a4c875b..0fe6723f 100644 --- a/SConscript +++ b/SConscript @@ -7,8 +7,6 @@ BUILDER = "DEV" common_flags = [] -panda_root = Dir('.') - if os.getenv("RELEASE"): BUILD_TYPE = "RELEASE" cert_fn = os.getenv("CERT") @@ -62,10 +60,10 @@ def to_c_uint32(x): return "{" + 'U,'.join(map(str, nums)) + "U}" -def build_project(project_name, project, extra_flags): - linkerscript_fn = File(project["LINKER_SCRIPT"]).srcnode().relpath +def build_project(project_name, project, main, extra_flags): + project_dir = Dir(f'./board/obj/{project_name}/') - flags = project["PROJECT_FLAGS"] + extra_flags + common_flags + [ + flags = project["FLAGS"] + extra_flags + common_flags + [ "-Wall", "-Wextra", "-Wstrict-prototypes", @@ -76,15 +74,10 @@ def build_project(project_name, project, extra_flags): "-fno-builtin", "-std=gnu11", "-fmax-errors=1", - f"-T{linkerscript_fn}", - ] - - includes = [ - '.', - '..', - panda_root, - f"{panda_root}/board/", - opendbc.INCLUDE_PATH, + f"-T{File(project['LINKER_SCRIPT']).srcnode().relpath}", + "-fsingle-precision-constant", + "-Os", + "-g", ] env = Environment( @@ -93,10 +86,11 @@ def build_project(project_name, project, extra_flags): AS=PREFIX + 'gcc', OBJCOPY=PREFIX + 'objcopy', OBJDUMP=PREFIX + 'objdump', + OBJPREFIX=project_dir, CFLAGS=flags, ASFLAGS=flags, LINKFLAGS=flags, - CPPPATH=includes, + CPPPATH=[Dir("./"), "./board/stm32f4/inc", "./board/stm32h7/inc", opendbc.INCLUDE_PATH], ASCOM="$AS $ASFLAGS -o $TARGET -c $SOURCES", BUILDERS={ 'Objcopy': Builder(generator=objcopy, suffix='.bin', src_suffix='.elf') @@ -104,68 +98,57 @@ def build_project(project_name, project, extra_flags): tools=["default", "compilation_db"], ) - startup = env.Object(f"obj/startup_{project_name}", project["STARTUP_FILE"]) + startup = env.Object(project["STARTUP_FILE"]) - # Bootstub - crypto_obj = [ - env.Object(f"rsa-{project_name}", f"{panda_root}/crypto/rsa.c"), - env.Object(f"sha-{project_name}", f"{panda_root}/crypto/sha.c") - ] - bootstub_obj = env.Object(f"bootstub-{project_name}", File(project.get("BOOTSTUB", f"{panda_root}/board/bootstub.c"))) - bootstub_elf = env.Program(f"obj/bootstub.{project_name}.elf", - [startup] + crypto_obj + [bootstub_obj]) - env.Objcopy(f"obj/bootstub.{project_name}.bin", bootstub_elf) + # Build bootstub + bs_env = env.Clone() + bs_env.Append(CFLAGS="-DBOOTSTUB", ASFLAGS="-DBOOTSTUB", LINKFLAGS="-DBOOTSTUB") + bs_elf = bs_env.Program(f"{project_dir}/bootstub.elf", [ + startup, + "./crypto/rsa.c", + "./crypto/sha.c", + "./board/bootstub.c", + ]) + bs_env.Objcopy(f"./board/obj/bootstub.{project_name}.bin", bs_elf) - # Build main - main_obj = env.Object(f"main-{project_name}", project["MAIN"]) - main_elf = env.Program(f"obj/{project_name}.elf", [startup, main_obj], - LINKFLAGS=[f"-Wl,--section-start,.isr_vector={project['APP_START_ADDRESS']}"] + flags) - main_bin = env.Objcopy(f"obj/{project_name}.bin", main_elf) - - # Sign main - sign_py = File(f"{panda_root}/crypto/sign.py").srcnode().relpath - env.Command(f"obj/{project_name}.bin.signed", main_bin, f"SETLEN=1 {sign_py} $SOURCE $TARGET {cert_fn}") + # Build + sign main (aka app) + main_elf = env.Program(f"{project_dir}/main.elf", [ + startup, + main + ], LINKFLAGS=[f"-Wl,--section-start,.isr_vector={project['APP_START_ADDRESS']}"] + flags) + main_bin = env.Objcopy(f"{project_dir}/main.bin", main_elf) + sign_py = File(f"./crypto/sign.py").srcnode().relpath + env.Command(f"./board/obj/{project_name}.bin.signed", main_bin, f"SETLEN=1 {sign_py} $SOURCE $TARGET {cert_fn}") base_project_f4 = { - "MAIN": "main.c", - "STARTUP_FILE": File("./board/stm32f4/startup_stm32f413xx.s"), - "LINKER_SCRIPT": File("./board/stm32f4/stm32f4_flash.ld"), + "STARTUP_FILE": "./board/stm32f4/startup_stm32f413xx.s", + "LINKER_SCRIPT": "./board/stm32f4/stm32f4_flash.ld", "APP_START_ADDRESS": "0x8004000", - "PROJECT_FLAGS": [ + "FLAGS": [ "-mcpu=cortex-m4", "-mhard-float", "-DSTM32F4", "-DSTM32F413xx", "-Iboard/stm32f4/inc", "-mfpu=fpv4-sp-d16", - "-fsingle-precision-constant", - "-Os", - "-g", ], } base_project_h7 = { - "MAIN": "main.c", - "STARTUP_FILE": File("./board/stm32h7/startup_stm32h7x5xx.s"), - "LINKER_SCRIPT": File("./board/stm32h7/stm32h7x5_flash.ld"), + "STARTUP_FILE": "./board/stm32h7/startup_stm32h7x5xx.s", + "LINKER_SCRIPT": "./board/stm32h7/stm32h7x5_flash.ld", "APP_START_ADDRESS": "0x8020000", - "PROJECT_FLAGS": [ + "FLAGS": [ "-mcpu=cortex-m7", "-mhard-float", "-DSTM32H7", "-DSTM32H725xx", "-Iboard/stm32h7/inc", "-mfpu=fpv5-d16", - "-fsingle-precision-constant", - "-Os", - "-g", ], } -Export('base_project_f4', 'base_project_h7', 'build_project') - - # Common autogenerated includes with open("board/obj/gitversion.h", "w") as f: version = get_version(BUILDER, BUILD_TYPE) @@ -181,10 +164,16 @@ with open("board/obj/cert.h", "w") as f: f.write("\n".join(cert) + "\n") # panda fw -SConscript('board/SConscript') +build_project("panda", base_project_f4, "./board/main.c", []) +build_project("panda_h7", base_project_h7, "./board/main.c", []) # panda jungle fw -SConscript('board/jungle/SConscript') +flags = [ + "-DPANDA_JUNGLE", +] +if os.getenv("FINAL_PROVISIONING"): + flags += ["-DFINAL_PROVISIONING"] +build_project("panda_jungle_h7", base_project_h7, "./board/jungle/main.c", flags) # test files if GetOption('extras'): diff --git a/board/SConscript b/board/SConscript deleted file mode 100644 index 3ff77648..00000000 --- a/board/SConscript +++ /dev/null @@ -1,18 +0,0 @@ -import os -import copy - -Import('build_project', 'base_project_f4', 'base_project_h7') - -build_projects = { - "panda": base_project_f4, - "panda_h7": base_project_h7, -} - -for project_name, project in build_projects.items(): - flags = [ - "-DPANDA", - ] - if ("ENABLE_SPI" in os.environ or "h7" in project_name): - flags.append('-DENABLE_SPI') - - build_project(project_name, project, flags) diff --git a/board/boards/black.h b/board/boards/black.h deleted file mode 100644 index 3f198179..00000000 --- a/board/boards/black.h +++ /dev/null @@ -1,130 +0,0 @@ -#pragma once - -#include "board_declarations.h" - -// /////////////////////////////// // -// Black Panda (STM32F4) + Harness // -// /////////////////////////////// // - -static void black_enable_can_transceiver(uint8_t transceiver, bool enabled) { - switch (transceiver){ - case 1U: - set_gpio_output(GPIOC, 1, !enabled); - break; - case 2U: - set_gpio_output(GPIOC, 13, !enabled); - break; - case 3U: - set_gpio_output(GPIOA, 0, !enabled); - break; - case 4U: - set_gpio_output(GPIOB, 10, !enabled); - break; - default: - print("Invalid CAN transceiver ("); puth(transceiver); print("): enabling failed\n"); - break; - } -} - -static void black_set_usb_load_switch(bool enabled) { - set_gpio_output(GPIOB, 1, !enabled); -} - -static void black_set_can_mode(uint8_t mode) { - black_enable_can_transceiver(2U, false); - black_enable_can_transceiver(4U, false); - switch (mode) { - case CAN_MODE_NORMAL: - case CAN_MODE_OBD_CAN2: - if ((bool)(mode == CAN_MODE_NORMAL) != (bool)(harness.status == HARNESS_STATUS_FLIPPED)) { - // B12,B13: disable OBD mode - set_gpio_mode(GPIOB, 12, MODE_INPUT); - set_gpio_mode(GPIOB, 13, MODE_INPUT); - - // B5,B6: normal CAN2 mode - set_gpio_alternate(GPIOB, 5, GPIO_AF9_CAN2); - set_gpio_alternate(GPIOB, 6, GPIO_AF9_CAN2); - black_enable_can_transceiver(2U, true); - - } else { - // B5,B6: disable normal CAN2 mode - set_gpio_mode(GPIOB, 5, MODE_INPUT); - set_gpio_mode(GPIOB, 6, MODE_INPUT); - - // B12,B13: OBD mode - set_gpio_alternate(GPIOB, 12, GPIO_AF9_CAN2); - set_gpio_alternate(GPIOB, 13, GPIO_AF9_CAN2); - black_enable_can_transceiver(4U, true); - } - break; - default: - print("Tried to set unsupported CAN mode: "); puth(mode); print("\n"); - break; - } -} - -static bool black_check_ignition(void){ - // ignition is checked through harness - return harness_check_ignition(); -} - -static void black_init(void) { - common_init_gpio(); - - // A8,A15: normal CAN3 mode - set_gpio_alternate(GPIOA, 8, GPIO_AF11_CAN3); - set_gpio_alternate(GPIOA, 15, GPIO_AF11_CAN3); - - // GPS OFF - set_gpio_output(GPIOC, 5, 0); - set_gpio_output(GPIOC, 12, 0); - - // Turn on USB load switch. - black_set_usb_load_switch(true); -} - -static void black_init_bootloader(void) { - // GPS OFF - set_gpio_output(GPIOC, 5, 0); - set_gpio_output(GPIOC, 12, 0); -} - -static harness_configuration black_harness_config = { - .has_harness = true, - .GPIO_SBU1 = GPIOC, - .GPIO_SBU2 = GPIOC, - .GPIO_relay_SBU1 = GPIOC, - .GPIO_relay_SBU2 = GPIOC, - .pin_SBU1 = 0, - .pin_SBU2 = 3, - .pin_relay_SBU1 = 10, - .pin_relay_SBU2 = 11, - .adc_channel_SBU1 = 10, - .adc_channel_SBU2 = 13 -}; - -board board_black = { - .set_bootkick = unused_set_bootkick, - .harness_config = &black_harness_config, - .has_spi = false, - .has_canfd = false, - .fan_max_rpm = 0U, - .fan_max_pwm = 100U, - .avdd_mV = 3300U, - .fan_stall_recovery = false, - .fan_enable_cooldown_time = 0U, - .init = black_init, - .init_bootloader = black_init_bootloader, - .enable_can_transceiver = black_enable_can_transceiver, - .led_GPIO = {GPIOC, GPIOC, GPIOC}, - .led_pin = {9, 7, 6}, - .set_can_mode = black_set_can_mode, - .check_ignition = black_check_ignition, - .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, - .read_som_gpio = unused_read_som_gpio, - .set_amp_enabled = unused_set_amp_enabled -}; diff --git a/board/boards/board_declarations.h b/board/boards/board_declarations.h index aa41fe3a..539244eb 100644 --- a/board/boards/board_declarations.h +++ b/board/boards/board_declarations.h @@ -14,7 +14,6 @@ typedef void (*board_init)(void); typedef void (*board_init_bootloader)(void); typedef void (*board_enable_can_transceiver)(uint8_t transceiver, bool enabled); typedef void (*board_set_can_mode)(uint8_t mode); -typedef bool (*board_check_ignition)(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); @@ -30,7 +29,6 @@ struct board { const uint8_t led_pin[3]; const uint8_t led_pwm_channels[3]; // leave at 0 to disable PWM const bool has_spi; - const bool has_canfd; const uint16_t fan_max_rpm; const uint16_t avdd_mV; const bool fan_stall_recovery; @@ -40,7 +38,6 @@ struct board { board_init_bootloader init_bootloader; board_enable_can_transceiver enable_can_transceiver; board_set_can_mode set_can_mode; - board_check_ignition check_ignition; board_read_voltage_mV read_voltage_mV; board_read_current_mA read_current_mA; board_set_ir_power set_ir_power; @@ -54,30 +51,17 @@ struct board { // ******************* Definitions ******************** // These should match the enums in cereal/log.capnp and __init__.py #define HW_TYPE_UNKNOWN 0U -#define HW_TYPE_WHITE_PANDA 1U -//#define HW_TYPE_GREY_PANDA 2U -#define HW_TYPE_BLACK_PANDA 3U -//#define HW_TYPE_PEDAL 4U -//#define HW_TYPE_UNO 5U #define HW_TYPE_DOS 6U #define HW_TYPE_RED_PANDA 7U #define HW_TYPE_RED_PANDA_V2 8U #define HW_TYPE_TRES 9U #define HW_TYPE_CUATRO 10U -// USB power modes (from cereal.log.health) -#define USB_POWER_NONE 0U -#define USB_POWER_CLIENT 1U -#define USB_POWER_CDP 2U -#define USB_POWER_DCP 3U - // CAN modes #define CAN_MODE_NORMAL 0U #define CAN_MODE_OBD_CAN2 1U -extern struct board board_black; extern struct board board_dos; extern struct board board_tres; -extern struct board board_white; extern struct board board_cuatro; extern struct board board_red; diff --git a/board/boards/cuatro.h b/board/boards/cuatro.h index 53b671e1..a4a04652 100644 --- a/board/boards/cuatro.h +++ b/board/boards/cuatro.h @@ -26,11 +26,11 @@ static void cuatro_enable_can_transceiver(uint8_t transceiver, bool enabled) { } static uint32_t cuatro_read_voltage_mV(void) { - return adc_get_mV(8) * 11U; + return adc_get_mV(&(const adc_signal_t) ADC_CHANNEL_DEFAULT(ADC1, 8)) * 11U; } static uint32_t cuatro_read_current_mA(void) { - return adc_get_mV(3) * 2U; + return adc_get_mV(&(const adc_signal_t) ADC_CHANNEL_DEFAULT(ADC1, 3)) * 2U; } static void cuatro_set_fan_enabled(bool enabled) { @@ -39,12 +39,27 @@ static void cuatro_set_fan_enabled(bool enabled) { static void cuatro_set_bootkick(BootState state) { set_gpio_output(GPIOA, 0, state != BOOT_BOOTKICK); - // TODO: confirm we need this - //set_gpio_output(GPIOC, 12, state != BOOT_RESET); } -static void cuatro_set_amp_enabled(bool enabled){ - set_gpio_output(GPIOA, 5, enabled); +static void cuatro_set_amp_enabled(bool enabled) { + // *** tmp, remove soon *** + static const uint8_t olds[][12] = { + {0x44, 0x00, 0x10, 0x00, 0x19, 0x51, 0x32, 0x34, 0x39, 0x37, 0x37, 0x30}, + {0x14, 0x00, 0x13, 0x00, 0x18, 0x51, 0x32, 0x34, 0x39, 0x37, 0x37, 0x30}, + {0x04, 0x00, 0x30, 0x00, 0x18, 0x51, 0x32, 0x34, 0x39, 0x37, 0x37, 0x30}, + {0x2f, 0x00, 0x14, 0x00, 0x18, 0x51, 0x32, 0x34, 0x39, 0x37, 0x37, 0x30}, + {0x1e, 0x00, 0x2f, 0x00, 0x18, 0x51, 0x32, 0x34, 0x39, 0x37, 0x37, 0x30}, + {0x26, 0x00, 0x15, 0x00, 0x19, 0x51, 0x32, 0x34, 0x39, 0x37, 0x37, 0x30}, + {0x35, 0x00, 0x32, 0x00, 0x18, 0x51, 0x32, 0x34, 0x39, 0x37, 0x37, 0x30}, + {0x37, 0x00, 0x2f, 0x00, 0x18, 0x51, 0x32, 0x34, 0x39, 0x37, 0x37, 0x30}, + }; + bool is_old = false; + for (uint8_t i = 0U; i < (sizeof(olds) / sizeof(olds[0])); i++) { + is_old |= (memcmp(olds[i], ((uint8_t *)UID_BASE), 12) == 0); + } + if (is_old) set_gpio_output(GPIOA, 5, enabled); + // *** tmp end *** + set_gpio_output(GPIOB, 0, enabled); } @@ -102,7 +117,6 @@ static void cuatro_init(void) { } static harness_configuration cuatro_harness_config = { - .has_harness = true, .GPIO_SBU1 = GPIOC, .GPIO_SBU2 = GPIOA, .GPIO_relay_SBU1 = GPIOA, @@ -111,14 +125,13 @@ static harness_configuration cuatro_harness_config = { .pin_SBU2 = 1, .pin_relay_SBU1 = 9, .pin_relay_SBU2 = 3, - .adc_channel_SBU1 = 4, // ADC12_INP4 - .adc_channel_SBU2 = 17 // ADC1_INP17 + .adc_signal_SBU1 = ADC_CHANNEL_DEFAULT(ADC1, 4), + .adc_signal_SBU2 = ADC_CHANNEL_DEFAULT(ADC1, 17) }; board board_cuatro = { .harness_config = &cuatro_harness_config, .has_spi = true, - .has_canfd = true, .fan_max_rpm = 12500U, .fan_max_pwm = 99U, // it can go up to 14k RPM, but 99% -> 100% is very non-linear .avdd_mV = 1800U, @@ -131,7 +144,6 @@ board board_cuatro = { .led_pin = {6, 7, 9}, .led_pwm_channels = {1, 2, 4}, .set_can_mode = tres_set_can_mode, - .check_ignition = red_check_ignition, .read_voltage_mV = cuatro_read_voltage_mV, .read_current_mA = cuatro_read_current_mA, .set_fan_enabled = cuatro_set_fan_enabled, diff --git a/board/boards/dos.h b/board/boards/dos.h index 661f91fb..0bb9cc82 100644 --- a/board/boards/dos.h +++ b/board/boards/dos.h @@ -62,11 +62,6 @@ static void dos_set_can_mode(uint8_t mode) { } } -static bool dos_check_ignition(void){ - // ignition is checked through harness - return harness_check_ignition(); -} - static void dos_set_ir_power(uint8_t percentage){ pwm_set(TIM4, 2, percentage); } @@ -79,6 +74,10 @@ static void dos_set_siren(bool enabled){ set_gpio_output(GPIOC, 12, enabled); } +static uint32_t dos_read_voltage_mV(void){ + return adc_get_mV(&(const adc_signal_t) ADC_CHANNEL_DEFAULT(ADC1, 12)) * 11U; +} + static bool dos_read_som_gpio (void){ return (get_gpio_input(GPIOC, 2) != 0); } @@ -110,7 +109,6 @@ static void dos_init(void) { } static harness_configuration dos_harness_config = { - .has_harness = true, .GPIO_SBU1 = GPIOC, .GPIO_SBU2 = GPIOC, .GPIO_relay_SBU1 = GPIOC, @@ -119,18 +117,13 @@ static harness_configuration dos_harness_config = { .pin_SBU2 = 3, .pin_relay_SBU1 = 10, .pin_relay_SBU2 = 11, - .adc_channel_SBU1 = 10, - .adc_channel_SBU2 = 13 + .adc_signal_SBU1 = ADC_CHANNEL_DEFAULT(ADC1, 10), + .adc_signal_SBU2 = ADC_CHANNEL_DEFAULT(ADC1, 13), }; board board_dos = { .harness_config = &dos_harness_config, -#ifdef ENABLE_SPI - .has_spi = true, -#else .has_spi = false, -#endif - .has_canfd = false, .fan_max_rpm = 6500U, .fan_max_pwm = 100U, .avdd_mV = 3300U, @@ -142,8 +135,7 @@ board board_dos = { .led_GPIO = {GPIOC, GPIOC, GPIOC}, .led_pin = {9, 7, 6}, .set_can_mode = dos_set_can_mode, - .check_ignition = dos_check_ignition, - .read_voltage_mV = white_read_voltage_mV, + .read_voltage_mV = dos_read_voltage_mV, .read_current_mA = unused_read_current, .set_fan_enabled = dos_set_fan_enabled, .set_ir_power = dos_set_ir_power, diff --git a/board/boards/red.h b/board/boards/red.h index 9871f959..c1f96500 100644 --- a/board/boards/red.h +++ b/board/boards/red.h @@ -67,13 +67,8 @@ static void red_set_can_mode(uint8_t mode) { } } -static bool red_check_ignition(void) { - // ignition is checked through harness - return harness_check_ignition(); -} - static uint32_t red_read_voltage_mV(void){ - return adc_get_mV(2) * 11U; // TODO: is this correct? + return adc_get_mV(&(const adc_signal_t) ADC_CHANNEL_DEFAULT(ADC1, 2)) * 11U; } static void red_init(void) { @@ -104,7 +99,6 @@ static void red_init(void) { } static harness_configuration red_harness_config = { - .has_harness = true, .GPIO_SBU1 = GPIOC, .GPIO_SBU2 = GPIOA, .GPIO_relay_SBU1 = GPIOC, @@ -113,15 +107,14 @@ static harness_configuration red_harness_config = { .pin_SBU2 = 1, .pin_relay_SBU1 = 10, .pin_relay_SBU2 = 11, - .adc_channel_SBU1 = 4, //ADC12_INP4 - .adc_channel_SBU2 = 17 //ADC1_INP17 + .adc_signal_SBU1 = ADC_CHANNEL_DEFAULT(ADC1, 4), + .adc_signal_SBU2 = ADC_CHANNEL_DEFAULT(ADC1, 17) }; board board_red = { .set_bootkick = unused_set_bootkick, .harness_config = &red_harness_config, .has_spi = false, - .has_canfd = true, .fan_max_rpm = 0U, .fan_max_pwm = 100U, .avdd_mV = 3300U, @@ -133,7 +126,6 @@ board board_red = { .led_GPIO = {GPIOE, GPIOE, GPIOE}, .led_pin = {4, 3, 2}, .set_can_mode = red_set_can_mode, - .check_ignition = red_check_ignition, .read_voltage_mV = red_read_voltage_mV, .read_current_mA = unused_read_current, .set_fan_enabled = unused_set_fan_enabled, diff --git a/board/boards/tres.h b/board/boards/tres.h index 811314a5..b92c5d6a 100644 --- a/board/boards/tres.h +++ b/board/boards/tres.h @@ -133,7 +133,6 @@ static void tres_init(void) { } static harness_configuration tres_harness_config = { - .has_harness = true, .GPIO_SBU1 = GPIOC, .GPIO_SBU2 = GPIOA, .GPIO_relay_SBU1 = GPIOA, @@ -142,14 +141,13 @@ static harness_configuration tres_harness_config = { .pin_SBU2 = 1, .pin_relay_SBU1 = 8, .pin_relay_SBU2 = 3, - .adc_channel_SBU1 = 4, // ADC12_INP4 - .adc_channel_SBU2 = 17 // ADC1_INP17 + .adc_signal_SBU1 = ADC_CHANNEL_DEFAULT(ADC1, 4), + .adc_signal_SBU2 = ADC_CHANNEL_DEFAULT(ADC1, 17) }; board board_tres = { .harness_config = &tres_harness_config, .has_spi = true, - .has_canfd = true, .fan_max_rpm = 6600U, .fan_max_pwm = 100U, .avdd_mV = 1800U, @@ -161,7 +159,6 @@ board board_tres = { .led_GPIO = {GPIOE, GPIOE, GPIOE}, .led_pin = {4, 3, 2}, .set_can_mode = tres_set_can_mode, - .check_ignition = red_check_ignition, .read_voltage_mV = red_read_voltage_mV, .read_current_mA = unused_read_current, .set_fan_enabled = tres_set_fan_enabled, diff --git a/board/boards/white.h b/board/boards/white.h deleted file mode 100644 index 5f43dda6..00000000 --- a/board/boards/white.h +++ /dev/null @@ -1,179 +0,0 @@ -#pragma once - -#include "board_declarations.h" - -// ///////////////////// // -// White Panda (STM32F4) // -// ///////////////////// // - -static void white_enable_can_transceiver(uint8_t transceiver, bool enabled) { - switch (transceiver){ - case 1U: - set_gpio_output(GPIOC, 1, !enabled); - break; - case 2U: - set_gpio_output(GPIOC, 13, !enabled); - break; - case 3U: - set_gpio_output(GPIOA, 0, !enabled); - break; - default: - break; - } -} - -static void white_set_usb_power_mode(uint8_t mode){ - switch (mode) { - case USB_POWER_CLIENT: - // B2,A13: set client mode - set_gpio_output(GPIOB, 2, 0); - set_gpio_output(GPIOA, 13, 1); - break; - case USB_POWER_CDP: - // B2,A13: set CDP mode - set_gpio_output(GPIOB, 2, 1); - set_gpio_output(GPIOA, 13, 1); - break; - case USB_POWER_DCP: - // B2,A13: set DCP mode on the charger (breaks USB!) - set_gpio_output(GPIOB, 2, 0); - set_gpio_output(GPIOA, 13, 0); - break; - default: - print("Invalid usb power mode\n"); - break; - } -} - -static void white_set_can_mode(uint8_t mode){ - 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); - - // 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); - } -} - -static uint32_t white_read_voltage_mV(void){ - return adc_get_mV(12) * 11U; -} - -static 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); -} - -static bool white_check_ignition(void){ - // ignition is on PA1 - return !get_gpio_input(GPIOA, 1); -} - -static void white_grey_init(void) { - common_init_gpio(); - - // C3: current sense - set_gpio_mode(GPIOC, 3, MODE_ANALOG); - - // A1: started_alt - set_gpio_pullup(GPIOA, 1, PULL_UP); - - // A2, A3: USART 2 for debugging - set_gpio_alternate(GPIOA, 2, GPIO_AF7_USART2); - set_gpio_alternate(GPIOA, 3, GPIO_AF7_USART2); - - // A4, A5, A6, A7: SPI - set_gpio_alternate(GPIOA, 4, GPIO_AF5_SPI1); - set_gpio_alternate(GPIOA, 5, GPIO_AF5_SPI1); - set_gpio_alternate(GPIOA, 6, GPIO_AF5_SPI1); - set_gpio_alternate(GPIOA, 7, GPIO_AF5_SPI1); - - // B12: GMLAN, ignition sense, pull up - set_gpio_pullup(GPIOB, 12, PULL_UP); - - /* GMLAN mode pins: - M0(B15) M1(B14) mode - ======================= - 0 0 sleep - 1 0 100kbit - 0 1 high voltage wakeup - 1 1 33kbit (normal) - */ - set_gpio_output(GPIOB, 14, 0); - set_gpio_output(GPIOB, 15, 0); - - // B7: K-line enable - set_gpio_output(GPIOB, 7, 1); - - // C12, D2: Setup K-line (UART5) - set_gpio_alternate(GPIOC, 12, GPIO_AF8_UART5); - set_gpio_alternate(GPIOD, 2, GPIO_AF8_UART5); - set_gpio_pullup(GPIOD, 2, PULL_UP); - - // L-line enable - set_gpio_output(GPIOA, 14, 1); - - // C10, C11: L-Line setup (USART3) - set_gpio_alternate(GPIOC, 10, GPIO_AF7_USART3); - set_gpio_alternate(GPIOC, 11, GPIO_AF7_USART3); - set_gpio_pullup(GPIOC, 11, PULL_UP); - - // Init usb power mode - // Init in CDP mode only if panda is powered by 12V. - // Otherwise a PC would not be able to flash a standalone panda - 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); - } - - // ESP/GPS off - set_gpio_output(GPIOC, 5, 0); - set_gpio_output(GPIOC, 14, 0); -} - -static void white_grey_init_bootloader(void) { - // ESP/GPS off - set_gpio_output(GPIOC, 5, 0); - set_gpio_output(GPIOC, 14, 0); -} - -static harness_configuration white_harness_config = { - .has_harness = false -}; - -board board_white = { - .set_bootkick = unused_set_bootkick, - .harness_config = &white_harness_config, - .has_spi = false, - .has_canfd = false, - .fan_max_rpm = 0U, - .fan_max_pwm = 100U, - .avdd_mV = 3300U, - .fan_stall_recovery = false, - .fan_enable_cooldown_time = 0U, - .init = white_grey_init, - .init_bootloader = white_grey_init_bootloader, - .enable_can_transceiver = white_enable_can_transceiver, - .led_GPIO = {GPIOC, GPIOC, GPIOC}, - .led_pin = {9, 7, 6}, - .set_can_mode = white_set_can_mode, - .check_ignition = white_check_ignition, - .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, - .read_som_gpio = unused_read_som_gpio, - .set_amp_enabled = unused_set_amp_enabled -}; diff --git a/board/bootstub.c b/board/bootstub.c index 5e05fa66..a48f308a 100644 --- a/board/bootstub.c +++ b/board/bootstub.c @@ -1,24 +1,22 @@ -#define BOOTSTUB - #define VERS_TAG 0x53524556 #define MIN_VERSION 2 // ********************* Includes ********************* -#include "config.h" +#include "board/config.h" -#include "drivers/led.h" -#include "drivers/pwm.h" -#include "drivers/usb.h" +#include "board/drivers/led.h" +#include "board/drivers/pwm.h" +#include "board/drivers/usb.h" -#include "early_init.h" -#include "provision.h" +#include "board/early_init.h" +#include "board/provision.h" #include "crypto/rsa.h" #include "crypto/sha.h" -#include "obj/cert.h" -#include "obj/gitversion.h" -#include "flasher.h" +#include "board/obj/cert.h" +#include "board/obj/gitversion.h" +#include "board/flasher.h" // cppcheck-suppress unusedFunction ; used in headers not included in cppcheck void __initialize_hardware_early(void) { @@ -32,9 +30,6 @@ void fail(void) { // know where to sig check extern void *_app_start[]; -// FIXME: sometimes your panda will fail flashing and will quickly blink a single Green LED -// BOUNTY: $200 coupon on shop.comma.ai or $100 check. - int main(void) { // Init interrupt table init_interrupts(true); diff --git a/board/config.h b/board/config.h index 6fb95ada..94ef5490 100644 --- a/board/config.h +++ b/board/config.h @@ -34,9 +34,9 @@ // platform includes #ifdef STM32H7 - #include "stm32h7/stm32h7_config.h" + #include "board/stm32h7/stm32h7_config.h" #elif defined(STM32F4) - #include "stm32f4/stm32f4_config.h" + #include "board/stm32f4/stm32f4_config.h" #else // TODO: uncomment this, cppcheck complains // building for tests diff --git a/board/crc.h b/board/crc.h index a3caf785..3e20fb09 100644 --- a/board/crc.h +++ b/board/crc.h @@ -1,6 +1,5 @@ #pragma once -#if defined(ENABLE_SPI) || defined(BOOTSTUB) uint8_t crc_checksum(const uint8_t *dat, int len, const uint8_t poly) { uint8_t crc = 0xFFU; int i; @@ -18,4 +17,3 @@ uint8_t crc_checksum(const uint8_t *dat, int len, const uint8_t poly) { } return crc; } -#endif diff --git a/board/dfu_util_f4.sh b/board/debug/dfu_util_f4.sh similarity index 100% rename from board/dfu_util_f4.sh rename to board/debug/dfu_util_f4.sh diff --git a/board/dfu_util_h7.sh b/board/debug/dfu_util_h7.sh similarity index 100% rename from board/dfu_util_h7.sh rename to board/debug/dfu_util_h7.sh diff --git a/board/gdb.sh b/board/debug/gdb.sh similarity index 100% rename from board/gdb.sh rename to board/debug/gdb.sh diff --git a/board/drivers/can_common.h b/board/drivers/can_common.h index fd2cfad4..23e0c1a4 100644 --- a/board/drivers/can_common.h +++ b/board/drivers/can_common.h @@ -139,9 +139,9 @@ bus_config_t bus_config[BUS_CONFIG_ARRAY_SIZE] = { void can_init_all(void) { for (uint8_t i=0U; i < PANDA_CAN_CNT; i++) { - if (!current_board->has_canfd) { + #ifndef CANFD bus_config[i].can_data_speed = 0U; - } + #endif can_clear(can_queues[i]); (void)can_init(i); } @@ -160,28 +160,28 @@ void can_set_forwarding(uint8_t from, uint8_t to) { } #endif -void ignition_can_hook(CANPacket_t *to_push) { - int bus = GET_BUS(to_push); +void ignition_can_hook(CANPacket_t *msg) { + int bus = GET_BUS(msg); if (bus == 0) { - int addr = GET_ADDR(to_push); - int len = GET_LEN(to_push); + int addr = GET_ADDR(msg); + int len = GET_LEN(msg); // GM exception if ((addr == 0x1F1) && (len == 8)) { // SystemPowerMode (2=Run, 3=Crank Request) - ignition_can = (GET_BYTE(to_push, 0) & 0x2U) != 0U; + ignition_can = (msg->data[0] & 0x2U) != 0U; ignition_can_cnt = 0U; } // Rivian R1S/T GEN1 exception if ((addr == 0x152) && (len == 8)) { // 0x152 overlaps with Subaru pre-global which has this bit as the high beam - int counter = GET_BYTE(to_push, 1) & 0xFU; // max is only 14 + int counter = msg->data[1] & 0xFU; // max is only 14 static int prev_counter_rivian = -1; if ((counter == ((prev_counter_rivian + 1) % 15)) && (prev_counter_rivian != -1)) { // VDM_OutputSignals->VDM_EpasPowerMode - ignition_can = ((GET_BYTE(to_push, 7) >> 4U) & 0x3U) == 1U; // VDM_EpasPowerMode_Drive_On=1 + ignition_can = ((msg->data[7] >> 4U) & 0x3U) == 1U; // VDM_EpasPowerMode_Drive_On=1 ignition_can_cnt = 0U; } prev_counter_rivian = counter; @@ -190,12 +190,12 @@ void ignition_can_hook(CANPacket_t *to_push) { // Tesla Model 3/Y exception if ((addr == 0x221) && (len == 8)) { // 0x221 overlaps with Rivian which has random data on byte 0 - int counter = GET_BYTE(to_push, 6) >> 4; + int counter = msg->data[6] >> 4; static int prev_counter_tesla = -1; if ((counter == ((prev_counter_tesla + 1) % 16)) && (prev_counter_tesla != -1)) { // VCFRONT_LVPowerState->VCFRONT_vehiclePowerState - int power_state = (GET_BYTE(to_push, 0) >> 5U) & 0x3U; + int power_state = (msg->data[0] >> 5U) & 0x3U; ignition_can = power_state == 0x3; // VEHICLE_POWER_STATE_DRIVE=3 ignition_can_cnt = 0U; } @@ -204,7 +204,7 @@ void ignition_can_hook(CANPacket_t *to_push) { // Mazda exception if ((addr == 0x9E) && (len == 8)) { - ignition_can = (GET_BYTE(to_push, 0) >> 5) == 0x6U; + ignition_can = (msg->data[0] >> 5) == 0x6U; ignition_can_cnt = 0U; } diff --git a/board/drivers/fake_siren.h b/board/drivers/fake_siren.h index 9468afd8..4bce95bd 100644 --- a/board/drivers/fake_siren.h +++ b/board/drivers/fake_siren.h @@ -1,4 +1,4 @@ -#include "stm32h7/lli2c.h" +#include "board/stm32h7/lli2c.h" #define CODEC_I2C_ADDR 0x10 diff --git a/board/drivers/harness.h b/board/drivers/harness.h index 1d8c5806..3ebf109f 100644 --- a/board/drivers/harness.h +++ b/board/drivers/harness.h @@ -4,31 +4,29 @@ struct harness_t harness; // The ignition relay is only used for testing purposes void set_intercept_relay(bool intercept, bool ignition_relay) { - if (current_board->harness_config->has_harness) { - bool drive_relay = intercept; - if (harness.status == HARNESS_STATUS_NC) { - // no harness, no relay to drive - drive_relay = false; - } + bool drive_relay = intercept; + if (harness.status == HARNESS_STATUS_NC) { + // no harness, no relay to drive + drive_relay = false; + } - if (drive_relay || ignition_relay) { - harness.relay_driven = true; - } + if (drive_relay || ignition_relay) { + harness.relay_driven = true; + } - // wait until we're not reading the analog voltages anymore - while (harness.sbu_adc_lock) {} + // wait until we're not reading the analog voltages anymore + while (harness.sbu_adc_lock) {} - if (harness.status == HARNESS_STATUS_NORMAL) { - set_gpio_output(current_board->harness_config->GPIO_relay_SBU1, current_board->harness_config->pin_relay_SBU1, !ignition_relay); - set_gpio_output(current_board->harness_config->GPIO_relay_SBU2, current_board->harness_config->pin_relay_SBU2, !drive_relay); - } else { - set_gpio_output(current_board->harness_config->GPIO_relay_SBU1, current_board->harness_config->pin_relay_SBU1, !drive_relay); - set_gpio_output(current_board->harness_config->GPIO_relay_SBU2, current_board->harness_config->pin_relay_SBU2, !ignition_relay); - } + if (harness.status == HARNESS_STATUS_NORMAL) { + set_gpio_output(current_board->harness_config->GPIO_relay_SBU1, current_board->harness_config->pin_relay_SBU1, !ignition_relay); + set_gpio_output(current_board->harness_config->GPIO_relay_SBU2, current_board->harness_config->pin_relay_SBU2, !drive_relay); + } else { + set_gpio_output(current_board->harness_config->GPIO_relay_SBU1, current_board->harness_config->pin_relay_SBU1, !drive_relay); + set_gpio_output(current_board->harness_config->GPIO_relay_SBU2, current_board->harness_config->pin_relay_SBU2, !ignition_relay); + } - if (!(drive_relay || ignition_relay)) { - harness.relay_driven = false; - } + if (!(drive_relay || ignition_relay)) { + harness.relay_driven = false; } } @@ -56,13 +54,13 @@ static uint8_t harness_detect_orientation(void) { #ifndef BOOTSTUB // We can't detect orientation if the relay is being driven - if (!harness.relay_driven && current_board->harness_config->has_harness) { + if (!harness.relay_driven) { harness.sbu_adc_lock = true; set_gpio_mode(current_board->harness_config->GPIO_SBU1, current_board->harness_config->pin_SBU1, MODE_ANALOG); set_gpio_mode(current_board->harness_config->GPIO_SBU2, current_board->harness_config->pin_SBU2, MODE_ANALOG); - harness.sbu1_voltage_mV = adc_get_mV(current_board->harness_config->adc_channel_SBU1); - harness.sbu2_voltage_mV = adc_get_mV(current_board->harness_config->adc_channel_SBU2); + harness.sbu1_voltage_mV = adc_get_mV(¤t_board->harness_config->adc_signal_SBU1); + harness.sbu2_voltage_mV = adc_get_mV(¤t_board->harness_config->adc_signal_SBU2); uint16_t detection_threshold = current_board->avdd_mV / 2U; // Detect connection and orientation diff --git a/board/drivers/harness_declarations.h b/board/drivers/harness_declarations.h index 953941f6..6f4327aa 100644 --- a/board/drivers/harness_declarations.h +++ b/board/drivers/harness_declarations.h @@ -14,7 +14,6 @@ struct harness_t { extern struct harness_t harness; struct harness_configuration { - const bool has_harness; GPIO_TypeDef * const GPIO_SBU1; GPIO_TypeDef * const GPIO_SBU2; GPIO_TypeDef * const GPIO_relay_SBU1; @@ -23,8 +22,8 @@ struct harness_configuration { 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; + const adc_signal_t adc_signal_SBU1; + const adc_signal_t adc_signal_SBU2; }; // The ignition relay is only used for testing purposes diff --git a/board/drivers/pwm.h b/board/drivers/pwm.h index 67e5181e..b8ff9302 100644 --- a/board/drivers/pwm.h +++ b/board/drivers/pwm.h @@ -3,54 +3,54 @@ // TODO: Implement for 32-bit timers void pwm_init(TIM_TypeDef *TIM, uint8_t channel){ - // Enable timer and auto-reload - register_set(&(TIM->CR1), TIM_CR1_CEN | TIM_CR1_ARPE, 0x3FU); + // Enable timer and auto-reload + register_set(&(TIM->CR1), TIM_CR1_CEN | TIM_CR1_ARPE, 0x3FU); - // Set channel as PWM mode 1 and enable output - switch(channel){ - case 1U: - register_set_bits(&(TIM->CCMR1), (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1PE)); - register_set_bits(&(TIM->CCER), TIM_CCER_CC1E); - break; - case 2U: - register_set_bits(&(TIM->CCMR1), (TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2PE)); - register_set_bits(&(TIM->CCER), TIM_CCER_CC2E); - break; - case 3U: - register_set_bits(&(TIM->CCMR2), (TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3PE)); - register_set_bits(&(TIM->CCER), TIM_CCER_CC3E); - break; - case 4U: - register_set_bits(&(TIM->CCMR2), (TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4PE)); - register_set_bits(&(TIM->CCER), TIM_CCER_CC4E); - break; - default: - break; - } + // Set channel as PWM mode 1 and enable output + switch(channel){ + case 1U: + register_set_bits(&(TIM->CCMR1), (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1PE)); + register_set_bits(&(TIM->CCER), TIM_CCER_CC1E); + break; + case 2U: + register_set_bits(&(TIM->CCMR1), (TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2PE)); + register_set_bits(&(TIM->CCER), TIM_CCER_CC2E); + break; + case 3U: + register_set_bits(&(TIM->CCMR2), (TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3PE)); + register_set_bits(&(TIM->CCER), TIM_CCER_CC3E); + break; + case 4U: + register_set_bits(&(TIM->CCMR2), (TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4PE)); + register_set_bits(&(TIM->CCER), TIM_CCER_CC4E); + break; + default: + break; + } - // Set max counter value - register_set(&(TIM->ARR), PWM_COUNTER_OVERFLOW, 0xFFFFU); + // Set max counter value + register_set(&(TIM->ARR), PWM_COUNTER_OVERFLOW, 0xFFFFU); - // Update registers and clear counter - TIM->EGR |= TIM_EGR_UG; + // Update registers and clear counter + TIM->EGR |= TIM_EGR_UG; } void pwm_set(TIM_TypeDef *TIM, uint8_t channel, uint8_t percentage){ - uint16_t comp_value = (((uint16_t) percentage * PWM_COUNTER_OVERFLOW) / 100U); - switch(channel){ - case 1U: - register_set(&(TIM->CCR1), comp_value, 0xFFFFU); - break; - case 2U: - register_set(&(TIM->CCR2), comp_value, 0xFFFFU); - break; - case 3U: - register_set(&(TIM->CCR3), comp_value, 0xFFFFU); - break; - case 4U: - register_set(&(TIM->CCR4), comp_value, 0xFFFFU); - break; - default: - break; - } + uint16_t comp_value = (((uint16_t) percentage * PWM_COUNTER_OVERFLOW) / 100U); + switch(channel){ + case 1U: + register_set(&(TIM->CCR1), comp_value, 0xFFFFU); + break; + case 2U: + register_set(&(TIM->CCR2), comp_value, 0xFFFFU); + break; + case 3U: + register_set(&(TIM->CCR3), comp_value, 0xFFFFU); + break; + case 4U: + register_set(&(TIM->CCR4), comp_value, 0xFFFFU); + break; + default: + break; + } } diff --git a/board/drivers/spi.h b/board/drivers/spi.h index 469243db..6bac6c0c 100644 --- a/board/drivers/spi.h +++ b/board/drivers/spi.h @@ -1,7 +1,7 @@ #pragma once -#include "spi_declarations.h" -#include "crc.h" +#include "board/drivers/spi_declarations.h" +#include "board/crc.h" #ifdef STM32H7 #define SPI_BUF_SIZE 2048U @@ -14,9 +14,8 @@ uint8_t spi_buf_rx[SPI_BUF_SIZE]; uint8_t spi_buf_tx[SPI_BUF_SIZE]; #endif -uint16_t spi_checksum_error_count = 0; +uint16_t spi_error_count = 0; -#if defined(ENABLE_SPI) || defined(BOOTSTUB) static uint8_t spi_state = SPI_STATE_HEADER; static uint16_t spi_data_len_mosi; static bool spi_can_tx_ready = false; @@ -153,9 +152,12 @@ void spi_rx_done(void) { print("SPI: did expect data for can_write\n"); } } else if (spi_endpoint == 0xABU) { - // test endpoint, send max response length + // test endpoint: mimics panda -> device transfer response_len = spi_data_len_miso; response_ack = true; + } else if (spi_endpoint == 0xACU) { + // test endpoint: mimics device -> panda transfer (with NACK) + response_ack = false; } else { print("SPI: unexpected endpoint"); puth(spi_endpoint); print("\n"); } @@ -206,8 +208,8 @@ 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)) { - spi_checksum_error_count += 1U; + if (!checksum_valid && (spi_error_count < UINT16_MAX)) { + spi_error_count += 1U; } } @@ -234,8 +236,3 @@ void spi_tx_done(bool reset) { void can_tx_comms_resume_spi(void) { spi_can_tx_ready = true; } -#else -void can_tx_comms_resume_spi(void) { - return; -} -#endif diff --git a/board/drivers/spi_declarations.h b/board/drivers/spi_declarations.h index 8c830e6b..d7fff9a4 100644 --- a/board/drivers/spi_declarations.h +++ b/board/drivers/spi_declarations.h @@ -1,6 +1,6 @@ #pragma once -#include "crc.h" +#include "board/crc.h" #define SPI_TIMEOUT_US 10000U @@ -35,7 +35,7 @@ enum { SPI_STATE_DATA_TX }; -extern uint16_t spi_checksum_error_count; +extern uint16_t spi_error_count; #define SPI_HEADER_SIZE 7U @@ -45,8 +45,6 @@ void llspi_mosi_dma(uint8_t *addr, int len); void llspi_miso_dma(uint8_t *addr, int len); void can_tx_comms_resume_spi(void); -#if defined(ENABLE_SPI) || defined(BOOTSTUB) void spi_init(void); void spi_rx_done(void); void spi_tx_done(bool reset); -#endif diff --git a/board/drivers/uart.h b/board/drivers/uart.h index ee15999a..da6f5e4d 100644 --- a/board/drivers/uart.h +++ b/board/drivers/uart.h @@ -1,7 +1,5 @@ #include "uart_declarations.h" -// IRQs: USART2, USART3, UART5 - // ***************************** Definitions ***************************** #define UART_BUFFER(x, size_rx, size_tx, uart_ptr, callback_ptr, overwrite_mode) \ @@ -112,15 +110,6 @@ bool put_char(uart_ring *q, char elem) { return ret; } -void clear_uart_buff(uart_ring *q) { - ENTER_CRITICAL(); - q->w_ptr_tx = 0; - q->r_ptr_tx = 0; - q->w_ptr_rx = 0; - q->r_ptr_rx = 0; - EXIT_CRITICAL(); -} - // ************************ High-level debug functions ********************** void putch(const char a) { // misra-c2012-17.7: serial debug function, ok to ignore output @@ -145,14 +134,14 @@ void puth(unsigned int i) { puthx(i, 8U); } -#if defined(ENABLE_SPI) || defined(BOOTSTUB) || defined(DEBUG) -void puth4(unsigned int i) { +#if defined(DEBUG_SPI) || defined(BOOTSTUB) || defined(DEBUG) +static void puth4(unsigned int i) { puthx(i, 4U); } #endif -#if defined(ENABLE_SPI) || defined(BOOTSTUB) || defined(DEBUG_USB) || defined(DEBUG_COMMS) -void hexdump(const void *a, int l) { +#if defined(DEBUG_SPI) || defined(BOOTSTUB) || defined(DEBUG_USB) || defined(DEBUG_COMMS) +static void hexdump(const void *a, int l) { if (a != NULL) { for (int i=0; i < l; i++) { if ((i != 0) && ((i & 0xf) == 0)) print("\n"); diff --git a/board/drivers/uart_declarations.h b/board/drivers/uart_declarations.h index f2775d3f..14ec2611 100644 --- a/board/drivers/uart_declarations.h +++ b/board/drivers/uart_declarations.h @@ -1,7 +1,5 @@ #pragma once -// IRQs: USART2, USART3, UART5 - // ***************************** Definitions ***************************** #define FIFO_SIZE_INT 0x400U @@ -33,7 +31,9 @@ void putch(const char a); void print(const char *a); void puthx(uint32_t i, uint8_t len); void puth(unsigned int i); -#if defined(ENABLE_SPI) || defined(BOOTSTUB) || defined(DEBUG) -void puth4(unsigned int i); +#if defined(DEBUG_SPI) || defined(BOOTSTUB) || defined(DEBUG) +static void puth4(unsigned int i); +#endif +#if defined(DEBUG_SPI) || defined(DEBUG_USB) || defined(DEBUG_COMMS) +static void hexdump(const void *a, int l); #endif -void hexdump(const void *a, int l); diff --git a/board/early_init.h b/board/early_init.h index e48a8063..d5131a42 100644 --- a/board/early_init.h +++ b/board/early_init.h @@ -57,9 +57,7 @@ void early_initialization(void) { if (enter_bootloader_mode == ENTER_BOOTLOADER_MAGIC) { led_init(); - #ifdef PANDA current_board->init_bootloader(); - #endif led_set(LED_GREEN, 1); jump_to_bootloader(); } diff --git a/board/fake_stm.h b/board/fake_stm.h index 984fde14..f526ad5a 100644 --- a/board/fake_stm.h +++ b/board/fake_stm.h @@ -7,7 +7,6 @@ #define CANFD #define ALLOW_DEBUG -#define PANDA #define ENTER_CRITICAL() 0 #define EXIT_CRITICAL() 0 diff --git a/board/flasher.h b/board/flasher.h index 9cf21542..13ce1ae7 100644 --- a/board/flasher.h +++ b/board/flasher.h @@ -134,15 +134,12 @@ void soft_flasher_start(void) { gpio_usb_init(); led_init(); - // enable USB + // enable comms usb_init(); - -#ifdef ENABLE_SPI if (current_board->has_spi) { gpio_spi_init(); spi_init(); } -#endif // green LED on for flashing led_set(LED_GREEN, 1); diff --git a/board/health.h b/board/health.h index 74d822dc..673fc12e 100644 --- a/board/health.h +++ b/board/health.h @@ -23,7 +23,7 @@ struct __attribute__((packed)) health_t { float interrupt_load_pkt; uint8_t fan_power; uint8_t safety_rx_checks_invalid_pkt; - uint16_t spi_checksum_error_count_pkt; + uint16_t spi_error_count_pkt; uint8_t fan_stall_count; uint16_t sbu1_voltage_mV; uint16_t sbu2_voltage_mV; diff --git a/board/jungle/SConscript b/board/jungle/SConscript deleted file mode 100644 index 3e40611a..00000000 --- a/board/jungle/SConscript +++ /dev/null @@ -1,18 +0,0 @@ -import os -import copy - -Import('build_project', 'base_project_f4', 'base_project_h7') - -build_projects = { - "panda_jungle": base_project_f4, - "panda_jungle_h7": base_project_h7, -} - -for project_name, project in build_projects.items(): - flags = [ - "-DPANDA_JUNGLE", - ] - if os.getenv("FINAL_PROVISIONING"): - flags += ["-DFINAL_PROVISIONING"] - - build_project(project_name, project, flags) diff --git a/board/jungle/__init__.py b/board/jungle/__init__.py index 0f968d80..85c1a4ff 100644 --- a/board/jungle/__init__.py +++ b/board/jungle/__init__.py @@ -7,7 +7,7 @@ from panda import Panda, PandaDFU from panda.python.constants import McuType BASEDIR = os.path.dirname(os.path.realpath(__file__)) -FW_PATH = os.path.join(BASEDIR, "obj/") +FW_PATH = os.path.join(BASEDIR, "../obj/") def ensure_jungle_health_packet_version(fn): diff --git a/board/jungle/boards/board_declarations.h b/board/jungle/boards/board_declarations.h index 88427041..aad54ded 100644 --- a/board/jungle/boards/board_declarations.h +++ b/board/jungle/boards/board_declarations.h @@ -2,6 +2,7 @@ typedef void (*board_init)(void); typedef void (*board_board_tick)(void); typedef bool (*board_get_button)(void); +typedef void (*board_init_bootloader)(void); typedef void (*board_set_panda_power)(bool enabled); typedef void (*board_set_panda_individual_power)(uint8_t port_num, bool enabled); typedef void (*board_set_ignition)(bool enabled); @@ -17,12 +18,11 @@ struct board { GPIO_TypeDef * const led_GPIO[3]; const uint8_t led_pin[3]; const uint8_t led_pwm_channels[3]; // leave at 0 to disable PWM - const bool has_canfd; - const bool has_sbu_sense; const uint16_t avdd_mV; board_init init; board_board_tick board_tick; board_get_button get_button; + board_init_bootloader init_bootloader; board_set_panda_power set_panda_power; board_set_panda_individual_power set_panda_individual_power; board_set_ignition set_ignition; @@ -40,7 +40,6 @@ struct board { // ******************* Definitions ******************** #define HW_TYPE_UNKNOWN 0U -#define HW_TYPE_V1 1U #define HW_TYPE_V2 2U // CAN modes @@ -59,18 +58,3 @@ struct board { uint8_t harness_orientation = HARNESS_ORIENTATION_NONE; uint8_t can_mode = CAN_MODE_NORMAL; uint8_t ignition = 0U; - - -void unused_set_individual_ignition(uint8_t bitmask) { - UNUSED(bitmask); -} - -void unused_board_enable_header_pin(uint8_t pin_num, bool enabled) { - UNUSED(pin_num); - UNUSED(enabled); -} - -void unused_set_panda_individual_power(uint8_t port_num, bool enabled) { - UNUSED(port_num); - UNUSED(enabled); -} diff --git a/board/jungle/boards/board_v1.h b/board/jungle/boards/board_v1.h deleted file mode 100644 index 44e90b8f..00000000 --- a/board/jungle/boards/board_v1.h +++ /dev/null @@ -1,158 +0,0 @@ -// ///////////////////////// // -// Jungle board v1 (STM32F4) // -// ///////////////////////// // - -void board_v1_enable_can_transceiver(uint8_t transceiver, bool enabled) { - switch (transceiver) { - case 1U: - set_gpio_output(GPIOC, 1, !enabled); - break; - case 2U: - set_gpio_output(GPIOC, 13, !enabled); - break; - case 3U: - set_gpio_output(GPIOA, 0, !enabled); - break; - case 4U: - set_gpio_output(GPIOB, 10, !enabled); - break; - default: - print("Invalid CAN transceiver ("); puth(transceiver); print("): enabling failed\n"); - break; - } -} - -void board_v1_set_can_mode(uint8_t mode) { - board_v1_enable_can_transceiver(2U, false); - board_v1_enable_can_transceiver(4U, false); - switch (mode) { - case CAN_MODE_NORMAL: - print("Setting normal CAN mode\n"); - // B12,B13: disable OBD mode - set_gpio_mode(GPIOB, 12, MODE_INPUT); - set_gpio_mode(GPIOB, 13, MODE_INPUT); - - // B5,B6: normal CAN2 mode - set_gpio_alternate(GPIOB, 5, GPIO_AF9_CAN2); - set_gpio_alternate(GPIOB, 6, GPIO_AF9_CAN2); - can_mode = CAN_MODE_NORMAL; - board_v1_enable_can_transceiver(2U, true); - break; - case CAN_MODE_OBD_CAN2: - print("Setting OBD CAN mode\n"); - // B5,B6: disable normal CAN2 mode - set_gpio_mode(GPIOB, 5, MODE_INPUT); - set_gpio_mode(GPIOB, 6, MODE_INPUT); - - // B12,B13: OBD mode - set_gpio_alternate(GPIOB, 12, GPIO_AF9_CAN2); - set_gpio_alternate(GPIOB, 13, GPIO_AF9_CAN2); - can_mode = CAN_MODE_OBD_CAN2; - board_v1_enable_can_transceiver(4U, true); - break; - default: - print("Tried to set unsupported CAN mode: "); puth(mode); print("\n"); - break; - } -} - -void board_v1_set_harness_orientation(uint8_t orientation) { - switch (orientation) { - case HARNESS_ORIENTATION_NONE: - set_gpio_output(GPIOA, 2, false); - set_gpio_output(GPIOA, 3, false); - set_gpio_output(GPIOA, 4, false); - set_gpio_output(GPIOA, 5, false); - harness_orientation = orientation; - break; - case HARNESS_ORIENTATION_1: - set_gpio_output(GPIOA, 2, false); - set_gpio_output(GPIOA, 3, (ignition != 0U)); - set_gpio_output(GPIOA, 4, true); - set_gpio_output(GPIOA, 5, false); - harness_orientation = orientation; - break; - case HARNESS_ORIENTATION_2: - set_gpio_output(GPIOA, 2, (ignition != 0U)); - set_gpio_output(GPIOA, 3, false); - set_gpio_output(GPIOA, 4, false); - set_gpio_output(GPIOA, 5, true); - harness_orientation = orientation; - break; - default: - print("Tried to set an unsupported harness orientation: "); puth(orientation); print("\n"); - break; - } -} - -bool panda_power = false; -void board_v1_set_panda_power(bool enable) { - panda_power = enable; - set_gpio_output(GPIOB, 14, enable); -} - -bool board_v1_get_button(void) { - return get_gpio_input(GPIOC, 8); -} - -void board_v1_set_ignition(bool enabled) { - ignition = enabled ? 0xFFU : 0U; - board_v1_set_harness_orientation(harness_orientation); -} - -float board_v1_get_channel_power(uint8_t channel) { - UNUSED(channel); - return 0.0f; -} - -uint16_t board_v1_get_sbu_mV(uint8_t channel, uint8_t sbu) { - UNUSED(channel); UNUSED(sbu); - return 0U; -} - -void board_v1_init(void) { - common_init_gpio(); - - // A8,A15: normal CAN3 mode - set_gpio_alternate(GPIOA, 8, GPIO_AF11_CAN3); - set_gpio_alternate(GPIOA, 15, GPIO_AF11_CAN3); - - board_v1_set_can_mode(CAN_MODE_NORMAL); - - // Enable CAN transceivers - for(uint8_t i = 1; i <= 4; i++) { - board_v1_enable_can_transceiver(i, true); - } - - // Set normal CAN mode - board_v1_set_can_mode(CAN_MODE_NORMAL); - - // Set to no harness orientation - board_v1_set_harness_orientation(HARNESS_ORIENTATION_NONE); - - // Enable panda power by default - board_v1_set_panda_power(true); -} - -void board_v1_tick(void) {} - -board board_v1 = { - .has_canfd = false, - .has_sbu_sense = false, - .avdd_mV = 3300U, - .init = &board_v1_init, - .led_GPIO = {GPIOC, GPIOC, GPIOC}, - .led_pin = {9, 7, 6}, - .board_tick = &board_v1_tick, - .get_button = &board_v1_get_button, - .set_panda_power = &board_v1_set_panda_power, - .set_panda_individual_power = &unused_set_panda_individual_power, - .set_ignition = &board_v1_set_ignition, - .set_individual_ignition = &unused_set_individual_ignition, - .set_harness_orientation = &board_v1_set_harness_orientation, - .set_can_mode = &board_v1_set_can_mode, - .enable_can_transceiver = &board_v1_enable_can_transceiver, - .enable_header_pin = &unused_board_enable_header_pin, - .get_channel_power = &board_v1_get_channel_power, - .get_sbu_mV = &board_v1_get_sbu_mV, -}; diff --git a/board/jungle/boards/board_v2.h b/board/jungle/boards/board_v2.h index ea0a099d..45f8fb92 100644 --- a/board/jungle/boards/board_v2.h +++ b/board/jungle/boards/board_v2.h @@ -2,6 +2,8 @@ // Jungle board v2 (STM32H7) // // ///////////////////////// // +#define ADC_CHANNEL(a, c) {.adc = (a), .channel = (c), .sample_time = SAMPLETIME_810_CYCLES, .oversampling = OVERSAMPLING_1} + gpio_t power_pins[] = { {.bank = GPIOA, .pin = 0}, {.bank = GPIOA, .pin = 1}, @@ -47,22 +49,22 @@ gpio_t sbu2_relay_pins[] = { {.bank = GPIOE, .pin = 12}, }; -adc_channel_t sbu1_channels[] = { - {.adc = ADC3, .channel = 12}, - {.adc = ADC3, .channel = 2}, - {.adc = ADC3, .channel = 4}, - {.adc = ADC3, .channel = 6}, - {.adc = ADC3, .channel = 8}, - {.adc = ADC3, .channel = 10}, +const adc_signal_t sbu1_channels[] = { + ADC_CHANNEL(ADC3, 12), + ADC_CHANNEL(ADC3, 2), + ADC_CHANNEL(ADC3, 4), + ADC_CHANNEL(ADC3, 6), + ADC_CHANNEL(ADC3, 8), + ADC_CHANNEL(ADC3, 10), }; -adc_channel_t sbu2_channels[] = { - {.adc = ADC1, .channel = 13}, - {.adc = ADC3, .channel = 3}, - {.adc = ADC3, .channel = 5}, - {.adc = ADC3, .channel = 7}, - {.adc = ADC3, .channel = 9}, - {.adc = ADC3, .channel = 11}, +const adc_signal_t sbu2_channels[] = { + ADC_CHANNEL(ADC1, 13), + ADC_CHANNEL(ADC3, 3), + ADC_CHANNEL(ADC3, 5), + ADC_CHANNEL(ADC3, 7), + ADC_CHANNEL(ADC3, 9), + ADC_CHANNEL(ADC3, 11), }; void board_v2_set_harness_orientation(uint8_t orientation) { @@ -204,8 +206,7 @@ void board_v2_set_individual_ignition(uint8_t bitmask) { float board_v2_get_channel_power(uint8_t channel) { float ret = 0.0f; if ((channel >= 1U) && (channel <= 6U)) { - uint16_t readout = adc_get_mV(ADC1, channel - 1U); // these are mapped nicely in hardware - + uint16_t readout = adc_get_mV(&(const adc_signal_t) ADC_CHANNEL(ADC1, channel - 1U)); // these are mapped nicely in hardware ret = (((float) readout / 33e6) - 0.8e-6) / 52e-6 * 12.0f; } else { print("Invalid channel ("); puth(channel); print(")\n"); @@ -218,10 +219,10 @@ uint16_t board_v2_get_sbu_mV(uint8_t channel, uint8_t sbu) { if ((channel >= 1U) && (channel <= 6U)) { switch(sbu){ case SBU1: - ret = adc_get_mV(sbu1_channels[channel - 1U].adc, sbu1_channels[channel - 1U].channel); + ret = adc_get_mV(&sbu1_channels[channel - 1U]); break; case SBU2: - ret = adc_get_mV(sbu2_channels[channel - 1U].adc, sbu2_channels[channel - 1U].channel); + ret = adc_get_mV(&sbu2_channels[channel - 1U]); break; default: print("Invalid SBU ("); puth(sbu); print(")\n"); @@ -287,10 +288,9 @@ void board_v2_init(void) { void board_v2_tick(void) {} board board_v2 = { - .has_canfd = true, - .has_sbu_sense = true, .avdd_mV = 3300U, .init = &board_v2_init, + .init_bootloader = &board_v2_tick, .led_GPIO = {GPIOE, GPIOE, GPIOE}, .led_pin = {4, 3, 2}, .board_tick = &board_v2_tick, diff --git a/board/jungle/main.c b/board/jungle/main.c index 664351c1..0c383091 100644 --- a/board/jungle/main.c +++ b/board/jungle/main.c @@ -11,20 +11,16 @@ #include "board/provision.h" #include "board/health.h" -#include "jungle_health.h" +#include "board/jungle/jungle_health.h" #include "board/drivers/can_common.h" -#ifdef STM32H7 - #include "board/drivers/fdcan.h" -#else - #include "board/drivers/bxcan.h" -#endif +#include "board/drivers/fdcan.h" #include "board/obj/gitversion.h" #include "board/can_comms.h" -#include "main_comms.h" +#include "board/jungle/main_comms.h" // ********************* Serial debugging ********************* @@ -106,17 +102,15 @@ void tick_handler(void) { current_board->set_individual_ignition(ignition_bitmask); // SBU voltage reporting - if (current_board->has_sbu_sense) { - for (uint8_t i = 0U; i < 6U; i++) { - CANPacket_t pkt = { 0 }; - pkt.data_len_code = 8U; - pkt.addr = 0x100U + i; - *(uint16_t *) &pkt.data[0] = current_board->get_sbu_mV(i + 1U, SBU1); - *(uint16_t *) &pkt.data[2] = current_board->get_sbu_mV(i + 1U, SBU2); - pkt.data[4] = (ignition_bitmask >> i) & 1U; - can_set_checksum(&pkt); - can_send(&pkt, 0U, false); - } + for (uint8_t i = 0U; i < 6U; i++) { + CANPacket_t pkt = { 0 }; + pkt.data_len_code = 8U; + pkt.addr = 0x100U + i; + *(uint16_t *) &pkt.data[0] = current_board->get_sbu_mV(i + 1U, SBU1); + *(uint16_t *) &pkt.data[2] = current_board->get_sbu_mV(i + 1U, SBU2); + pkt.data[4] = (ignition_bitmask >> i) & 1U; + can_set_checksum(&pkt); + can_send(&pkt, 0U, false); } #else // toggle ignition on button press diff --git a/board/jungle/main_comms.h b/board/jungle/main_comms.h index 83d7ad03..b646381d 100644 --- a/board/jungle/main_comms.h +++ b/board/jungle/main_comms.h @@ -219,11 +219,6 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) { print("Clearing CAN CAN ring buffer failed: wrong bus number\n"); } break; - // **** 0xf2: Clear debug ring buffer. - case 0xf2: - print("Clearing debug queue.\n"); - clear_uart_buff(get_ring_by_number(0)); - break; // **** 0xf4: Set CAN transceiver enable pin case 0xf4: current_board->enable_can_transceiver(req->param1, req->param2 > 0U); @@ -240,7 +235,6 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) { // **** 0xf9: set CAN FD data bitrate case 0xf9: if ((req->param1 < PANDA_CAN_CNT) && - current_board->has_canfd && is_speed_valid(req->param2, data_speeds, sizeof(data_speeds)/sizeof(data_speeds[0]))) { bus_config[req->param1].can_data_speed = req->param2; bus_config[req->param1].canfd_enabled = (req->param2 >= bus_config[req->param1].can_speed); @@ -251,7 +245,7 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) { break; // **** 0xfc: set CAN FD non-ISO mode case 0xfc: - if ((req->param1 < PANDA_CAN_CNT) && current_board->has_canfd) { + if (req->param1 < PANDA_CAN_CNT) { bus_config[req->param1].canfd_non_iso = (req->param2 != 0U); bool ret = can_init(CAN_NUM_FROM_BUS_NUM(req->param1)); UNUSED(ret); diff --git a/board/jungle/stm32f4/board.h b/board/jungle/stm32f4/board.h deleted file mode 100644 index 0adf7923..00000000 --- a/board/jungle/stm32f4/board.h +++ /dev/null @@ -1,7 +0,0 @@ -#include "boards/board_declarations.h" -#include "boards/board_v1.h" - -void detect_board_type(void) { - hw_type = HW_TYPE_V1; - current_board = &board_v1; -} diff --git a/board/jungle/stm32h7/board.h b/board/jungle/stm32h7/board.h index 4fe4fa46..760a7041 100644 --- a/board/jungle/stm32h7/board.h +++ b/board/jungle/stm32h7/board.h @@ -1,7 +1,7 @@ -#include "boards/board_declarations.h" +#include "board/jungle/boards/board_declarations.h" -#include "stm32h7/lladc.h" -#include "boards/board_v2.h" +#include "board/stm32h7/lladc.h" +#include "board/jungle/boards/board_v2.h" void detect_board_type(void) { hw_type = HW_TYPE_V2; diff --git a/board/jungle/stm32h7/lladc.h b/board/jungle/stm32h7/lladc.h deleted file mode 100644 index 06b742dd..00000000 --- a/board/jungle/stm32h7/lladc.h +++ /dev/null @@ -1,54 +0,0 @@ - -typedef struct { - ADC_TypeDef *adc; - uint8_t channel; -} adc_channel_t; - -void adc_init(ADC_TypeDef *adc) { - adc->CR &= ~(ADC_CR_DEEPPWD); // Reset deep-power-down mode - adc->CR |= ADC_CR_ADVREGEN; // Enable ADC regulator - while(!(adc->ISR & ADC_ISR_LDORDY) && (adc != ADC3)); - - if (adc != ADC3) { - adc->CR &= ~(ADC_CR_ADCALDIF); // Choose single-ended calibration - adc->CR |= ADC_CR_ADCALLIN; // Lineriality calibration - } - adc->CR |= ADC_CR_ADCAL; // Start calibrtation - while((adc->CR & ADC_CR_ADCAL) != 0); - - adc->ISR |= ADC_ISR_ADRDY; - adc->CR |= ADC_CR_ADEN; - while(!(adc->ISR & ADC_ISR_ADRDY)); -} - -uint16_t adc_get_raw(ADC_TypeDef *adc, uint8_t channel) { - adc->SQR1 &= ~(ADC_SQR1_L); - adc->SQR1 = ((uint32_t) channel << 6U); - - if (channel < 10U) { - adc->SMPR1 = (0x7U << (channel * 3U)); - } else { - adc->SMPR2 = (0x7U << ((channel - 10U) * 3U)); - } - adc->PCSEL_RES0 = (0x1U << channel); - - adc->CR |= ADC_CR_ADSTART; - while (!(adc->ISR & ADC_ISR_EOC)); - - uint16_t res = adc->DR; - - while (!(adc->ISR & ADC_ISR_EOS)); - adc->ISR |= ADC_ISR_EOS; - - return res; -} - -uint16_t adc_get_mV(ADC_TypeDef *adc, uint8_t channel) { - uint16_t ret = 0; - if ((adc == ADC1) || (adc == ADC2)) { - ret = (adc_get_raw(adc, channel) * current_board->avdd_mV) / 65535U; - } else if (adc == ADC3) { - ret = (adc_get_raw(adc, channel) * current_board->avdd_mV) / 4095U; - } else {} - return ret; -} diff --git a/board/main.c b/board/main.c index e3aadefe..55814293 100644 --- a/board/main.c +++ b/board/main.c @@ -1,60 +1,41 @@ // ********************* Includes ********************* -#include "config.h" +#include "board/config.h" -#include "drivers/led.h" -#include "drivers/pwm.h" -#include "drivers/usb.h" -#include "drivers/simple_watchdog.h" -#include "drivers/bootkick.h" +#include "board/drivers/led.h" +#include "board/drivers/pwm.h" +#include "board/drivers/usb.h" +#include "board/drivers/simple_watchdog.h" +#include "board/drivers/bootkick.h" -#include "early_init.h" -#include "provision.h" +#include "board/early_init.h" +#include "board/provision.h" #include "opendbc/safety/safety.h" -#include "health.h" +#include "board/health.h" -#include "drivers/can_common.h" +#include "board/drivers/can_common.h" #ifdef STM32H7 - #include "drivers/fdcan.h" + #include "board/drivers/fdcan.h" #else - #include "drivers/bxcan.h" + #include "board/drivers/bxcan.h" #endif -#include "power_saving.h" +#include "board/power_saving.h" -#include "obj/gitversion.h" +#include "board/obj/gitversion.h" -#include "can_comms.h" -#include "main_comms.h" +#include "board/can_comms.h" +#include "board/main_comms.h" // ********************* Serial debugging ********************* -static bool check_started(void) { - bool started = current_board->check_ignition() || ignition_can; - return started; -} - void debug_ring_callback(uart_ring *ring) { char rcv; while (get_char(ring, &rcv)) { (void)put_char(ring, rcv); // misra-c2012-17.7: cast to void is ok: debug function - - // only allow bootloader entry on debug builds - #ifdef ALLOW_DEBUG - // jump to DFU flash - if (rcv == 'z') { - enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC; - NVIC_SystemReset(); - } - #endif - - // normal reset - if (rcv == 'x') { - NVIC_SystemReset(); - } } } @@ -77,31 +58,26 @@ void set_safety_mode(uint16_t mode, uint16_t param) { switch (mode_copy) { case SAFETY_SILENT: set_intercept_relay(false, false); - if (current_board->harness_config->has_harness) { - current_board->set_can_mode(CAN_MODE_NORMAL); - } + current_board->set_can_mode(CAN_MODE_NORMAL); can_silent = ALL_CAN_SILENT; break; case SAFETY_NOOUTPUT: set_intercept_relay(false, false); - if (current_board->harness_config->has_harness) { - current_board->set_can_mode(CAN_MODE_NORMAL); - } + current_board->set_can_mode(CAN_MODE_NORMAL); can_silent = ALL_CAN_LIVE; break; case SAFETY_ELM327: set_intercept_relay(false, false); heartbeat_counter = 0U; heartbeat_lost = false; - if (current_board->harness_config->has_harness) { - // Clear any pending messages in the can core (i.e. sending while comma power is unplugged) - // TODO: rewrite using hardware queues rather than fifo to cancel specific messages - can_clear_send(CANIF_FROM_CAN_NUM(1), 1); - if (param == 0U) { - current_board->set_can_mode(CAN_MODE_OBD_CAN2); - } else { - current_board->set_can_mode(CAN_MODE_NORMAL); - } + + // Clear any pending messages in the can core (i.e. sending while comma power is unplugged) + // TODO: rewrite using hardware queues rather than fifo to cancel specific messages + can_clear_send(CANIF_FROM_CAN_NUM(1), 1); + if (param == 0U) { + current_board->set_can_mode(CAN_MODE_OBD_CAN2); + } else { + current_board->set_can_mode(CAN_MODE_NORMAL); } can_silent = ALL_CAN_LIVE; break; @@ -109,9 +85,7 @@ void set_safety_mode(uint16_t mode, uint16_t param) { set_intercept_relay(true, false); heartbeat_counter = 0U; heartbeat_lost = false; - if (current_board->harness_config->has_harness) { - current_board->set_can_mode(CAN_MODE_NORMAL); - } + current_board->set_can_mode(CAN_MODE_NORMAL); can_silent = ALL_CAN_LIVE; break; } @@ -199,7 +173,8 @@ static void tick_handler(void) { const bool recent_heartbeat = heartbeat_counter == 0U; // tick drivers at 1Hz - bootkick_tick(check_started(), recent_heartbeat); + bool started = harness_check_ignition() || ignition_can; + bootkick_tick(started, recent_heartbeat); // increase heartbeat counter and cap it at the uint32 limit if (heartbeat_counter < UINT32_MAX) { @@ -237,7 +212,7 @@ static void tick_handler(void) { if (!heartbeat_disabled) { // if the heartbeat has been gone for a while, go to SILENT safety mode and enter power save - if (heartbeat_counter >= (check_started() ? HEARTBEAT_IGNITION_CNT_ON : HEARTBEAT_IGNITION_CNT_OFF)) { + if (heartbeat_counter >= (started ? HEARTBEAT_IGNITION_CNT_ON : HEARTBEAT_IGNITION_CNT_OFF)) { print("device hasn't sent a heartbeat for 0x"); puth(heartbeat_counter); print(" seconds. Safety is set to SILENT mode.\n"); @@ -310,7 +285,7 @@ int main(void) { // red+green leds enabled until succesful USB/SPI init, as a debug indicator led_set(LED_RED, true); led_set(LED_GREEN, true); - adc_init(); + adc_init(ADC1); // print hello print("\n\n\n************************ MAIN START ************************\n"); @@ -324,9 +299,7 @@ int main(void) { // init board current_board->init(); current_board->set_can_mode(CAN_MODE_NORMAL); - if (current_board->harness_config->has_harness) { - harness_init(); - } + harness_init(); // panda has an FPU, let's use it! enable_fpu(); @@ -357,12 +330,10 @@ int main(void) { // enable USB (right before interrupts or enum can fail!) usb_init(); -#ifdef ENABLE_SPI if (current_board->has_spi) { gpio_spi_init(); spi_init(); } -#endif led_set(LED_RED, false); led_set(LED_GREEN, false); diff --git a/board/main_comms.h b/board/main_comms.h index d3d49ce7..83e0b590 100644 --- a/board/main_comms.h +++ b/board/main_comms.h @@ -12,8 +12,7 @@ static int get_health_pkt(void *dat) { 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()); + health->ignition_line_pkt = (uint8_t)(harness_check_ignition()); health->ignition_can_pkt = ignition_can; health->controls_allowed_pkt = controls_allowed; @@ -29,7 +28,9 @@ static int get_health_pkt(void *dat) { health->heartbeat_lost_pkt = heartbeat_lost; health->safety_rx_checks_invalid_pkt = safety_rx_checks_invalid; - health->spi_checksum_error_count_pkt = spi_checksum_error_count; + #ifndef STM32F4 + health->spi_error_count_pkt = spi_error_count; + #endif health->fault_status_pkt = fault_status; health->faults_pkt = faults; @@ -97,7 +98,7 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) { resp[1] = ((fan_state.rpm & 0xFF00U) >> 8U); resp_len = 2; break; - // **** 0xc0: reset communications + // **** 0xc0: reset communications state case 0xc0: comms_can_reset(); break; @@ -212,17 +213,14 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) { break; // **** 0xdb: set OBD CAN multiplexing mode case 0xdb: - if (current_board->harness_config->has_harness) { - if (req->param1 == 1U) { - // Enable OBD CAN - current_board->set_can_mode(CAN_MODE_OBD_CAN2); - } else { - // Disable OBD CAN - current_board->set_can_mode(CAN_MODE_NORMAL); - } + if (req->param1 == 1U) { + // Enable OBD CAN + current_board->set_can_mode(CAN_MODE_OBD_CAN2); + } else { + // Disable OBD CAN + current_board->set_can_mode(CAN_MODE_NORMAL); } break; - // **** 0xdc: set safety mode case 0xdc: set_safety_mode(req->param1, (uint16_t)req->param2); @@ -265,47 +263,6 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) { ++resp_len; } break; - // **** 0xe1: uart set baud rate - case 0xe1: - ur = get_ring_by_number(req->param1); - if (!ur) { - break; - } - uart_set_baud(ur->uart, req->param2); - break; - // **** 0xe2: uart set parity - case 0xe2: - ur = get_ring_by_number(req->param1); - if (!ur) { - break; - } - switch (req->param2) { - case 0: - // disable parity, 8-bit - ur->uart->CR1 &= ~(USART_CR1_PCE | USART_CR1_M); - break; - case 1: - // even parity, 9-bit - ur->uart->CR1 &= ~USART_CR1_PS; - ur->uart->CR1 |= USART_CR1_PCE | USART_CR1_M; - break; - case 2: - // odd parity, 9-bit - ur->uart->CR1 |= USART_CR1_PS; - ur->uart->CR1 |= USART_CR1_PCE | USART_CR1_M; - break; - default: - break; - } - break; - // **** 0xe4: uart set baud rate extended - case 0xe4: - ur = get_ring_by_number(req->param1); - if (!ur) { - break; - } - uart_set_baud(ur->uart, (int)req->param2*300); - break; // **** 0xe5: set CAN loopback (for testing) case 0xe5: can_loopback = req->param1 > 0U; @@ -335,16 +292,6 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) { print("Clearing CAN CAN ring buffer failed: wrong bus number\n"); } break; - // **** 0xf2: Clear UART ring buffer. - case 0xf2: - { - uart_ring * rb = get_ring_by_number(req->param1); - if (rb != NULL) { - print("Clearing UART queue.\n"); - clear_uart_buff(rb); - } - break; - } // **** 0xf3: Heartbeat. Resets heartbeat counter. case 0xf3: { @@ -372,7 +319,6 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) { // **** 0xf9: set CAN FD data bitrate case 0xf9: if ((req->param1 < PANDA_CAN_CNT) && - current_board->has_canfd && is_speed_valid(req->param2, data_speeds, sizeof(data_speeds)/sizeof(data_speeds[0]))) { bus_config[req->param1].can_data_speed = req->param2; bus_config[req->param1].canfd_enabled = (req->param2 >= bus_config[req->param1].can_speed); @@ -383,7 +329,7 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) { break; // **** 0xfc: set CAN FD non-ISO mode case 0xfc: - if ((req->param1 < PANDA_CAN_CNT) && current_board->has_canfd) { + if (req->param1 < PANDA_CAN_CNT) { bus_config[req->param1].canfd_non_iso = (req->param2 != 0U); bool ret = can_init(CAN_NUM_FROM_BUS_NUM(req->param1)); UNUSED(ret); diff --git a/board/main_declarations.h b/board/main_declarations.h index 3b4a807d..269d958c 100644 --- a/board/main_declarations.h +++ b/board/main_declarations.h @@ -3,8 +3,6 @@ // ******************** Prototypes ******************** void print(const char *a); void puth(unsigned int i); -void puth4(unsigned int i); -void hexdump(const void *a, int l); typedef struct board board; typedef struct harness_configuration harness_configuration; void pwm_init(TIM_TypeDef *TIM, uint8_t channel); diff --git a/board/power_saving.h b/board/power_saving.h index dea46491..1e95c951 100644 --- a/board/power_saving.h +++ b/board/power_saving.h @@ -7,7 +7,7 @@ int power_save_status = POWER_SAVE_STATUS_DISABLED; void enable_can_transceivers(bool enabled) { // Leave main CAN always on for CAN-based ignition detection - uint8_t main_bus = (current_board->harness_config->has_harness && (harness.status == HARNESS_STATUS_FLIPPED)) ? 3U : 1U; + uint8_t main_bus = (harness.status == HARNESS_STATUS_FLIPPED) ? 3U : 1U; for(uint8_t i=1U; i<=4U; i++){ current_board->enable_can_transceiver(i, (i == main_bus) || enabled); } diff --git a/board/stm32f4/board.h b/board/stm32f4/board.h index 3f1f78b3..455f7c3c 100644 --- a/board/stm32f4/board.h +++ b/board/stm32f4/board.h @@ -1,39 +1,23 @@ // ///////////////////////////////////////////////////////////// // // Hardware abstraction layer for all different supported boards // // ///////////////////////////////////////////////////////////// // -#include "boards/board_declarations.h" -#include "boards/unused_funcs.h" +#include "board/boards/board_declarations.h" +#include "board/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/black.h" -#include "boards/dos.h" - -// Unused functions on F4 -void sound_tick(void) {} +#include "board/stm32f4/lladc.h" +#include "board/drivers/harness.h" +#include "board/drivers/fan.h" +#include "board/stm32f4/llfan.h" +#include "board/drivers/clock_source.h" +#include "board/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)){ + 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 - // grey is deprecated - } else if(!detect_with_pull(GPIOB, 15, PULL_UP)) { - // uno is deprecated - } else { - hw_type = HW_TYPE_BLACK_PANDA; - current_board = &board_black; } // Return A13 to the alt mode to fix SWD diff --git a/board/stm32f4/lladc.h b/board/stm32f4/lladc.h index c2df10f1..cbd16895 100644 --- a/board/stm32f4/lladc.h +++ b/board/stm32f4/lladc.h @@ -1,24 +1,31 @@ +#include "lladc_declarations.h" void register_set(volatile uint32_t *addr, uint32_t val, uint32_t mask); -void adc_init(void) { +void adc_init(ADC_TypeDef *adc) { register_set(&(ADC->CCR), ADC_CCR_TSVREFE | ADC_CCR_VBATE, 0xC30000U); - register_set(&(ADC1->CR2), ADC_CR2_ADON, 0xFF7F0F03U); - register_set(&(ADC1->SMPR1), ADC_SMPR1_SMP12 | ADC_SMPR1_SMP13, 0x7FFFFFFU); + register_set(&(adc->CR2), ADC_CR2_ADON, 0xFF7F0F03U); } -uint16_t adc_get_raw(uint8_t channel) { - // Select channel - register_set(&(ADC1->JSQR), ((uint32_t) channel << 15U), 0x3FFFFFU); +static uint16_t adc_get_raw(const adc_signal_t *signal) { + // sample time + if (signal->channel < 10U) { + signal->adc->SMPR2 = ((uint32_t) signal->sample_time << (signal->channel * 3U)); + } else { + signal->adc->SMPR1 = ((uint32_t) signal->sample_time << ((signal->channel - 10U) * 3U)); + } - // Start conversion - ADC1->SR &= ~(ADC_SR_JEOC); - ADC1->CR2 |= ADC_CR2_JSWSTART; - while (!(ADC1->SR & ADC_SR_JEOC)); + // select channel + signal->adc->JSQR = ((uint32_t) signal->channel << 15U); - return ADC1->JDR1; + // start conversion + signal->adc->SR &= ~(ADC_SR_JEOC); + signal->adc->CR2 |= ADC_CR2_JSWSTART; + while (!(signal->adc->SR & ADC_SR_JEOC)); + + return signal->adc->JDR1; } -uint16_t adc_get_mV(uint8_t channel) { - return (adc_get_raw(channel) * current_board->avdd_mV) / 4095U; +uint16_t adc_get_mV(const adc_signal_t *signal) { + return (adc_get_raw(signal) * current_board->avdd_mV) / 4095U; } diff --git a/board/stm32f4/lladc_declarations.h b/board/stm32f4/lladc_declarations.h new file mode 100644 index 00000000..64a733a9 --- /dev/null +++ b/board/stm32f4/lladc_declarations.h @@ -0,0 +1,20 @@ +#pragma once + +typedef enum { + SAMPLETIME_3_CYCLES = 0, + SAMPLETIME_15_CYCLES = 1, + SAMPLETIME_28_CYCLES = 2, + SAMPLETIME_56_CYCLES = 3, + SAMPLETIME_84_CYCLES = 4, + SAMPLETIME_112_CYCLES = 5, + SAMPLETIME_144_CYCLES = 6, + SAMPLETIME_480_CYCLES = 7 +} adc_sample_time_t; + +typedef struct { + ADC_TypeDef *adc; + uint8_t channel; + adc_sample_time_t sample_time; +} adc_signal_t; + +#define ADC_CHANNEL_DEFAULT(a, c) {.adc = (a), .channel = (c), .sample_time = SAMPLETIME_480_CYCLES} diff --git a/board/stm32f4/llspi.h b/board/stm32f4/llspi.h index e986adb4..8cf9d811 100644 --- a/board/stm32f4/llspi.h +++ b/board/stm32f4/llspi.h @@ -1,91 +1,12 @@ -#if defined(ENABLE_SPI) || defined(BOOTSTUB) void llspi_miso_dma(uint8_t *addr, int len) { - // disable DMA - DMA2_Stream3->CR &= ~DMA_SxCR_EN; - register_clear_bits(&(SPI1->CR2), SPI_CR2_TXDMAEN); - - // setup source and length - register_set(&(DMA2_Stream3->M0AR), (uint32_t)addr, 0xFFFFFFFFU); - DMA2_Stream3->NDTR = len; - - // enable DMA - register_set_bits(&(SPI1->CR2), SPI_CR2_TXDMAEN); - DMA2_Stream3->CR |= DMA_SxCR_EN; + UNUSED(addr); + UNUSED(len); } void llspi_mosi_dma(uint8_t *addr, int len) { - // disable DMA - register_clear_bits(&(SPI1->CR2), SPI_CR2_RXDMAEN); - DMA2_Stream2->CR &= ~DMA_SxCR_EN; - - // drain the bus - volatile uint8_t dat = SPI1->DR; - (void)dat; - - // setup destination and length - register_set(&(DMA2_Stream2->M0AR), (uint32_t)addr, 0xFFFFFFFFU); - DMA2_Stream2->NDTR = len; - - // enable DMA - DMA2_Stream2->CR |= DMA_SxCR_EN; - register_set_bits(&(SPI1->CR2), SPI_CR2_RXDMAEN); -} -// SPI MOSI DMA FINISHED -static void DMA2_Stream2_IRQ_Handler(void) { - // Clear interrupt flag - ENTER_CRITICAL(); - DMA2->LIFCR = DMA_LIFCR_CTCIF2; - - spi_rx_done(); - - EXIT_CRITICAL(); + UNUSED(addr); + UNUSED(len); } -// SPI MISO DMA FINISHED -static void DMA2_Stream3_IRQ_Handler(void) { - // Clear interrupt flag - DMA2->LIFCR = DMA_LIFCR_CTCIF3; - - // Wait until the transaction is actually finished and clear the DR - // Timeout to prevent hang when the master clock stops. - bool timed_out = false; - uint32_t start_time = microsecond_timer_get(); - while (!(SPI1->SR & SPI_SR_TXE)) { - if (get_ts_elapsed(microsecond_timer_get(), start_time) > SPI_TIMEOUT_US) { - timed_out = true; - break; - } - } - volatile uint8_t dat = SPI1->DR; - (void)dat; - SPI1->DR = 0U; - - if (timed_out) { - print("SPI: TX timeout\n"); - } - - spi_tx_done(timed_out); -} - -// ***************************** SPI init ***************************** void llspi_init(void) { - REGISTER_INTERRUPT(DMA2_Stream2_IRQn, DMA2_Stream2_IRQ_Handler, SPI_IRQ_RATE, FAULT_INTERRUPT_RATE_SPI_DMA) - REGISTER_INTERRUPT(DMA2_Stream3_IRQn, DMA2_Stream3_IRQ_Handler, SPI_IRQ_RATE, FAULT_INTERRUPT_RATE_SPI_DMA) - - // Setup MOSI DMA - register_set(&(DMA2_Stream2->CR), (DMA_SxCR_CHSEL_1 | DMA_SxCR_CHSEL_0 | DMA_SxCR_MINC | DMA_SxCR_TCIE), 0x1E077EFEU); - register_set(&(DMA2_Stream2->PAR), (uint32_t)&(SPI1->DR), 0xFFFFFFFFU); - - // Setup MISO DMA - register_set(&(DMA2_Stream3->CR), (DMA_SxCR_CHSEL_1 | DMA_SxCR_CHSEL_0 | DMA_SxCR_MINC | DMA_SxCR_DIR_0 | DMA_SxCR_TCIE), 0x1E077EFEU); - register_set(&(DMA2_Stream3->PAR), (uint32_t)&(SPI1->DR), 0xFFFFFFFFU); - - // Enable SPI and the error interrupts - // TODO: verify clock phase and polarity - register_set(&(SPI1->CR1), SPI_CR1_SPE, 0xFFFFU); - register_set(&(SPI1->CR2), 0U, 0xF7U); - - NVIC_EnableIRQ(DMA2_Stream2_IRQn); - NVIC_EnableIRQ(DMA2_Stream3_IRQn); } -#endif diff --git a/board/stm32f4/lluart.h b/board/stm32f4/lluart.h index 660c1ce1..ceb51a30 100644 --- a/board/stm32f4/lluart.h +++ b/board/stm32f4/lluart.h @@ -29,7 +29,3 @@ void uart_tx_ring(uart_ring *q){ #define DIVMANT_(_PCLK_, _BAUD_) (DIV_((_PCLK_), (_BAUD_)) / 100U) #define DIVFRAQ_(_PCLK_, _BAUD_) ((((DIV_((_PCLK_), (_BAUD_)) - (DIVMANT_((_PCLK_), (_BAUD_)) * 100U)) * 16U) + 50U) / 100U) #define USART_BRR_(_PCLK_, _BAUD_) ((DIVMANT_((_PCLK_), (_BAUD_)) << 4) | (DIVFRAQ_((_PCLK_), (_BAUD_)) & 0x0FU)) - -void uart_set_baud(USART_TypeDef *u, unsigned int baud) { - u->BRR = USART_BRR_(APB1_FREQ*1000000U, baud); -} diff --git a/board/stm32f4/peripherals.h b/board/stm32f4/peripherals.h index fc974091..1725c2ed 100644 --- a/board/stm32f4/peripherals.h +++ b/board/stm32f4/peripherals.h @@ -9,16 +9,8 @@ static void gpio_usb_init(void) { GPIOA->OSPEEDR = GPIO_OSPEEDER_OSPEEDR11 | GPIO_OSPEEDER_OSPEEDR12; } -#ifdef ENABLE_SPI void gpio_spi_init(void) { - // A4-A7: SPI - set_gpio_alternate(GPIOA, 4, GPIO_AF5_SPI1); - set_gpio_alternate(GPIOA, 5, GPIO_AF5_SPI1); - set_gpio_alternate(GPIOA, 6, GPIO_AF5_SPI1); - set_gpio_alternate(GPIOA, 7, GPIO_AF5_SPI1); - register_set_bits(&(GPIOA->OSPEEDR), GPIO_OSPEEDER_OSPEEDR4 | GPIO_OSPEEDER_OSPEEDR5 | GPIO_OSPEEDER_OSPEEDR6 | GPIO_OSPEEDER_OSPEEDR7); } -#endif #ifdef BOOTSTUB void gpio_usart2_init(void) { @@ -30,8 +22,6 @@ void gpio_usart2_init(void) { // Common GPIO initialization void common_init_gpio(void) { - // TODO: Is this block actually doing something??? - // pull low to hold ESP in reset?? // enable OTG out tied to ground GPIOA->ODR = 0; GPIOB->ODR = 0; diff --git a/board/stm32f4/stm32f4_config.h b/board/stm32f4/stm32f4_config.h index b3fc2a89..1af38f8e 100644 --- a/board/stm32f4/stm32f4_config.h +++ b/board/stm32f4/stm32f4_config.h @@ -1,5 +1,5 @@ -#include "stm32f4/inc/stm32f4xx.h" -#include "stm32f4/inc/stm32f4xx_hal_gpio_ex.h" +#include "stm32f4xx.h" +#include "stm32f4xx_hal_gpio_ex.h" #define MCU_IDCODE 0x463U #define CORE_FREQ 96U // in MHz @@ -30,44 +30,46 @@ #define PROVISION_CHUNK_ADDRESS 0x1FFF79E0U #define DEVICE_SERIAL_NUMBER_ADDRESS 0x1FFF79C0U -#include "can.h" -#include "comms_definitions.h" +#include "board/can.h" +#include "board/comms_definitions.h" #ifndef BOOTSTUB - #include "main_definitions.h" + #include "board/main_definitions.h" #else - #include "bootstub_declarations.h" + #include "board/bootstub_declarations.h" #endif -#include "libc.h" -#include "critical.h" -#include "faults.h" -#include "utils.h" +#include "board/libc.h" +#include "board/critical.h" +#include "board/faults.h" +#include "board/utils.h" -#include "drivers/registers.h" -#include "drivers/interrupts.h" -#include "drivers/gpio.h" -#include "stm32f4/peripherals.h" -#include "stm32f4/interrupt_handlers.h" -#include "drivers/timers.h" -#include "stm32f4/board.h" -#include "stm32f4/clock.h" - -#include "drivers/spi.h" -#include "stm32f4/llspi.h" +#include "board/drivers/registers.h" +#include "board/drivers/interrupts.h" +#include "board/drivers/gpio.h" +#include "board/stm32f4/peripherals.h" +#include "board/stm32f4/interrupt_handlers.h" +#include "board/drivers/timers.h" +#include "board/stm32f4/board.h" +#include "board/stm32f4/clock.h" #if !defined(BOOTSTUB) - #include "drivers/uart.h" - #include "stm32f4/lluart.h" + #include "board/drivers/uart.h" + #include "board/stm32f4/lluart.h" #endif #ifdef BOOTSTUB - #include "stm32f4/llflash.h" + #include "board/stm32f4/llflash.h" #else - #include "stm32f4/llbxcan.h" + #include "board/stm32f4/llbxcan.h" #endif -#include "stm32f4/llusb.h" +#include "board/stm32f4/llusb.h" + +// unused +void spi_init(void) {}; +void sound_tick(void) {}; +void can_tx_comms_resume_spi(void) {}; void early_gpio_float(void) { RCC->AHB1ENR = RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN; diff --git a/board/stm32h7/board.h b/board/stm32h7/board.h index 0507ca3f..04c4162d 100644 --- a/board/stm32h7/board.h +++ b/board/stm32h7/board.h @@ -1,20 +1,20 @@ // ///////////////////////////////////////////////////////////// // // Hardware abstraction layer for all different supported boards // // ///////////////////////////////////////////////////////////// // -#include "boards/board_declarations.h" -#include "boards/unused_funcs.h" +#include "board/boards/board_declarations.h" +#include "board/boards/unused_funcs.h" // ///// Board definition and detection ///// // -#include "stm32h7/lladc.h" -#include "drivers/harness.h" -#include "drivers/fan.h" -#include "stm32h7/llfan.h" -#include "drivers/fake_siren.h" -#include "stm32h7/sound.h" -#include "drivers/clock_source.h" -#include "boards/red.h" -#include "boards/tres.h" -#include "boards/cuatro.h" +#include "board/stm32h7/lladc.h" +#include "board/drivers/harness.h" +#include "board/drivers/fan.h" +#include "board/stm32h7/llfan.h" +#include "board/drivers/fake_siren.h" +#include "board/stm32h7/sound.h" +#include "board/drivers/clock_source.h" +#include "board/boards/red.h" +#include "board/boards/tres.h" +#include "board/boards/cuatro.h" void detect_board_type(void) { diff --git a/board/stm32h7/lladc.h b/board/stm32h7/lladc.h index 9ff2b54f..0a7e983c 100644 --- a/board/stm32h7/lladc.h +++ b/board/stm32h7/lladc.h @@ -1,39 +1,80 @@ +#include "lladc_declarations.h" -void adc_init(void) { - ADC1->CR &= ~(ADC_CR_DEEPPWD); //Reset deep-power-down mode - ADC1->CR |= ADC_CR_ADVREGEN; // Enable ADC regulator - while(!(ADC1->ISR & ADC_ISR_LDORDY)); +static uint32_t adc_avdd_mV = 0U; - ADC1->CR &= ~(ADC_CR_ADCALDIF); // Choose single-ended calibration - ADC1->CR |= ADC_CR_ADCALLIN; // Lineriality calibration - ADC1->CR |= ADC_CR_ADCAL; // Start calibrtation - while((ADC1->CR & ADC_CR_ADCAL) != 0U); +void adc_init(ADC_TypeDef *adc) { + adc->CR &= ~(ADC_CR_ADEN); // Disable ADC + adc->CR &= ~(ADC_CR_DEEPPWD); // Reset deep-power-down mode + adc->CR |= ADC_CR_ADVREGEN; // Enable ADC regulator + while(!(adc->ISR & ADC_ISR_LDORDY) && (adc != ADC3)); - ADC1->ISR |= ADC_ISR_ADRDY; - ADC1->CR |= ADC_CR_ADEN; - while(!(ADC1->ISR & ADC_ISR_ADRDY)); + if (adc != ADC3) { + adc->CR &= ~(ADC_CR_ADCALDIF); // Choose single-ended calibration + adc->CR |= ADC_CR_ADCALLIN; // Lineriality calibration + } + adc->CR |= ADC_CR_ADCAL; // Start calibration + while((adc->CR & ADC_CR_ADCAL) != 0U); + + adc->ISR |= ADC_ISR_ADRDY; + adc->CR |= ADC_CR_ADEN; + while(!(adc->ISR & ADC_ISR_ADRDY)); } -static uint16_t adc_get_raw(uint8_t channel) { - uint16_t res = 0U; - ADC1->SQR1 &= ~(ADC_SQR1_L); - ADC1->SQR1 = (uint32_t)channel << 6U; +uint16_t adc_get_raw(const adc_signal_t *signal) { + signal->adc->SQR1 &= ~(ADC_SQR1_L); + signal->adc->SQR1 = ((uint32_t) signal->channel << 6U); - ADC1->SMPR1 = 0x4UL << (channel * 3UL); - ADC1->PCSEL_RES0 = (0x1UL << channel); - ADC1->CFGR2 = (63UL << ADC_CFGR2_OVSR_Pos) | (0x6U << ADC_CFGR2_OVSS_Pos) | ADC_CFGR2_ROVSE; + // sample time + if (signal->channel < 10U) { + signal->adc->SMPR1 = ((uint32_t) signal->sample_time << (signal->channel * 3U)); + } else { + signal->adc->SMPR2 = ((uint32_t) signal->sample_time << ((signal->channel - 10U) * 3U)); + } - ADC1->CR |= ADC_CR_ADSTART; - while (!(ADC1->ISR & ADC_ISR_EOC)); + // select channel + signal->adc->PCSEL_RES0 = (0x1UL << signal->channel); - res = ADC1->DR; + // oversampling + signal->adc->CFGR2 = (((1U << (uint32_t) signal->oversampling) - 1U) << ADC_CFGR2_OVSR_Pos) | ((uint32_t) signal->oversampling << ADC_CFGR2_OVSS_Pos); + signal->adc->CFGR2 |= (signal->oversampling != OVERSAMPLING_1) ? ADC_CFGR2_ROVSE : 0U; - while (!(ADC1->ISR & ADC_ISR_EOS)); - ADC1->ISR |= ADC_ISR_EOS; + // start conversion + signal->adc->CR |= ADC_CR_ADSTART; + while (!(signal->adc->ISR & ADC_ISR_EOC)); + + uint16_t res = signal->adc->DR; + + while (!(signal->adc->ISR & ADC_ISR_EOS)); + signal->adc->ISR |= ADC_ISR_EOS; return res; } -uint16_t adc_get_mV(uint8_t channel) { - return (adc_get_raw(channel) * current_board->avdd_mV) / 65535U; +static void adc_calibrate_vdda(void) { + // ADC2 used for calibration + adc_init(ADC2); + + // enable VREFINT channel + ADC3_COMMON->CCR |= ADC_CCR_VREFEN; + SYSCFG->ADC2ALT |= SYSCFG_ADC2ALT_ADC2_ROUT1; + + // measure VREFINT and derive AVDD + uint16_t raw_vrefint = adc_get_raw(&(adc_signal_t){.adc = ADC2, .channel = 17U, .sample_time = SAMPLETIME_810_CYCLES, .oversampling = OVERSAMPLING_256}); + adc_avdd_mV = (uint32_t) *VREFINT_CAL_ADDR * 16U * 3300U / raw_vrefint; + print(" AVDD: 0x"); puth(adc_avdd_mV); print(" mV\n"); +} + +uint16_t adc_get_mV(const adc_signal_t *signal) { + uint16_t ret = 0; + + if (adc_avdd_mV == 0U) { + adc_calibrate_vdda(); + } + + if ((signal->adc == ADC1) || (signal->adc == ADC2)) { + ret = (adc_get_raw(signal) * adc_avdd_mV) / 65535U; + } else if (signal->adc == ADC3) { + ret = (adc_get_raw(signal) * adc_avdd_mV) / 4095U; + } else {} + return ret; } diff --git a/board/stm32h7/lladc_declarations.h b/board/stm32h7/lladc_declarations.h new file mode 100644 index 00000000..979919c8 --- /dev/null +++ b/board/stm32h7/lladc_declarations.h @@ -0,0 +1,37 @@ +#pragma once + +typedef enum { + SAMPLETIME_1_CYCLE = 0, + SAMPLETIME_2_CYCLES = 1, + SAMPLETIME_8_CYCLES = 2, + SAMPLETIME_16_CYCLES = 3, + SAMPLETIME_32_CYCLES = 4, + SAMPLETIME_64_CYCLES = 5, + SAMPLETIME_387_CYCLES = 6, + SAMPLETIME_810_CYCLES = 7 +} adc_sample_time_t; + +typedef enum { + OVERSAMPLING_1 = 0, + OVERSAMPLING_2 = 1, + OVERSAMPLING_4 = 2, + OVERSAMPLING_8 = 3, + OVERSAMPLING_16 = 4, + OVERSAMPLING_32 = 5, + OVERSAMPLING_64 = 6, + OVERSAMPLING_128 = 7, + OVERSAMPLING_256 = 8, + OVERSAMPLING_512 = 9, + OVERSAMPLING_1024 = 10 +} adc_oversampling_t; + +typedef struct { + ADC_TypeDef *adc; + uint8_t channel; + adc_sample_time_t sample_time; + adc_oversampling_t oversampling; +} adc_signal_t; + +#define ADC_CHANNEL_DEFAULT(a, c) {.adc = (a), .channel = (c), .sample_time = SAMPLETIME_32_CYCLES, .oversampling = OVERSAMPLING_64} + +#define VREFINT_CAL_ADDR ((uint16_t *)0x1FF1E860UL) diff --git a/board/stm32h7/llspi.h b/board/stm32h7/llspi.h index a5dca37a..05f8e22f 100644 --- a/board/stm32h7/llspi.h +++ b/board/stm32h7/llspi.h @@ -1,4 +1,3 @@ -#if defined(ENABLE_SPI) || defined(BOOTSTUB) // master -> panda DMA start void llspi_mosi_dma(uint8_t *addr, int len) { // disable DMA + SPI @@ -106,4 +105,3 @@ void llspi_init(void) { NVIC_EnableIRQ(DMA2_Stream3_IRQn); NVIC_EnableIRQ(SPI4_IRQn); } -#endif diff --git a/board/stm32h7/lluart.h b/board/stm32h7/lluart.h index 742549bb..e18f1e9f 100644 --- a/board/stm32h7/lluart.h +++ b/board/stm32h7/lluart.h @@ -44,11 +44,6 @@ void uart_tx_ring(uart_ring *q){ EXIT_CRITICAL(); } -void uart_set_baud(USART_TypeDef *u, unsigned int baud) { - // UART7 is connected to APB1 at 60MHz - u->BRR = 60000000U / baud; -} - // This read after reading ISR clears all error interrupts. We don't want compiler warnings, nor optimizations #define UART_READ_RDR(uart) volatile uint8_t t = (uart)->RDR; UNUSED(t); @@ -90,11 +85,12 @@ static void uart_interrupt_handler(uart_ring *q) { static void UART7_IRQ_Handler(void) { uart_interrupt_handler(&uart_ring_som_debug); } -void uart_init(uart_ring *q, int baud) { +void uart_init(uart_ring *q, unsigned int baud) { if (q->uart == UART7) { REGISTER_INTERRUPT(UART7_IRQn, UART7_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_7) - uart_set_baud(q->uart, baud); + // UART7 is connected to APB1 at 60MHz + q->uart->BRR = 60000000U / baud; q->uart->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; // Enable interrupt on RX not empty diff --git a/board/stm32h7/peripherals.h b/board/stm32h7/peripherals.h index 3e9256da..8eb38430 100644 --- a/board/stm32h7/peripherals.h +++ b/board/stm32h7/peripherals.h @@ -9,7 +9,6 @@ static void gpio_usb_init(void) { GPIOA->OSPEEDR = GPIO_OSPEEDR_OSPEED11 | GPIO_OSPEEDR_OSPEED12; } -#ifdef ENABLE_SPI void gpio_spi_init(void) { set_gpio_alternate(GPIOE, 11, GPIO_AF5_SPI4); set_gpio_alternate(GPIOE, 12, GPIO_AF5_SPI4); @@ -17,7 +16,6 @@ void gpio_spi_init(void) { set_gpio_alternate(GPIOE, 14, GPIO_AF5_SPI4); register_set_bits(&(GPIOE->OSPEEDR), GPIO_OSPEEDR_OSPEED11 | GPIO_OSPEEDR_OSPEED12 | GPIO_OSPEEDR_OSPEED13 | GPIO_OSPEEDR_OSPEED14); } -#endif #ifdef BOOTSTUB void gpio_usart2_init(void) { @@ -110,6 +108,7 @@ void peripherals_init(void) { // Analog RCC->AHB1ENR |= RCC_AHB1ENR_ADC12EN; // Enable ADC12 clocks + RCC->AHB4ENR |= RCC_AHB4ENR_ADC3EN; // Enable ADC3 clocks RCC->APB1LENR |= RCC_APB1LENR_DAC12EN; // DAC // Audio @@ -128,7 +127,6 @@ void peripherals_init(void) { #ifdef PANDA_JUNGLE RCC->AHB3ENR |= RCC_AHB3ENR_SDMMC1EN; // SDMMC - RCC->AHB4ENR |= RCC_AHB4ENR_ADC3EN; // Enable ADC3 clocks #endif } diff --git a/board/stm32h7/sound.h b/board/stm32h7/sound.h index 467c3567..9c75e465 100644 --- a/board/stm32h7/sound.h +++ b/board/stm32h7/sound.h @@ -104,11 +104,33 @@ void sound_init(void) { REGISTER_INTERRUPT(BDMA_Channel0_IRQn, BDMA_Channel0_IRQ_Handler, 128U, FAULT_INTERRUPT_RATE_SOUND_DMA) REGISTER_INTERRUPT(DMA1_Stream0_IRQn, DMA1_Stream0_IRQ_Handler, 128U, FAULT_INTERRUPT_RATE_SOUND_DMA) + // *** tmp, remove soon *** + static const uint8_t olds[][12] = { + {0x44, 0x00, 0x10, 0x00, 0x19, 0x51, 0x32, 0x34, 0x39, 0x37, 0x37, 0x30}, + {0x14, 0x00, 0x13, 0x00, 0x18, 0x51, 0x32, 0x34, 0x39, 0x37, 0x37, 0x30}, + {0x04, 0x00, 0x30, 0x00, 0x18, 0x51, 0x32, 0x34, 0x39, 0x37, 0x37, 0x30}, + {0x2f, 0x00, 0x14, 0x00, 0x18, 0x51, 0x32, 0x34, 0x39, 0x37, 0x37, 0x30}, + {0x1e, 0x00, 0x2f, 0x00, 0x18, 0x51, 0x32, 0x34, 0x39, 0x37, 0x37, 0x30}, + {0x26, 0x00, 0x15, 0x00, 0x19, 0x51, 0x32, 0x34, 0x39, 0x37, 0x37, 0x30}, + {0x35, 0x00, 0x32, 0x00, 0x18, 0x51, 0x32, 0x34, 0x39, 0x37, 0x37, 0x30}, + {0x37, 0x00, 0x2f, 0x00, 0x18, 0x51, 0x32, 0x34, 0x39, 0x37, 0x37, 0x30}, + }; + bool is_old = false; + for (uint8_t i = 0U; i < (sizeof(olds) / sizeof(olds[0])); i++) { + is_old |= (memcmp(olds[i], ((uint8_t *)UID_BASE), 12) == 0); + } + // *** tmp end *** + // Init DAC DAC1->DHR12R1 = (1UL << 11); + if (!is_old) DAC1->DHR12R2 = (1UL << 11); register_set(&DAC1->MCR, 0U, 0xFFFFFFFFU); register_set(&DAC1->CR, DAC_CR_TEN1 | (4U << DAC_CR_TSEL1_Pos) | DAC_CR_DMAEN1, 0xFFFFFFFFU); - register_set_bits(&DAC1->CR, DAC_CR_EN1); + if (is_old) { + register_set_bits(&DAC1->CR, DAC_CR_EN1); + } else { + register_set_bits(&DAC1->CR, DAC_CR_EN1 | DAC_CR_EN2); + } // Setup DMAMUX (DAC_CH1_DMA as input) register_set(&DMAMUX1_Channel1->CCR, 67U, DMAMUX_CxCR_DMAREQ_ID_Msk); diff --git a/board/stm32h7/stm32h7_config.h b/board/stm32h7/stm32h7_config.h index 4355fe8e..5e7dcb0c 100644 --- a/board/stm32h7/stm32h7_config.h +++ b/board/stm32h7/stm32h7_config.h @@ -1,5 +1,5 @@ -#include "stm32h7/inc/stm32h7xx.h" -#include "stm32h7/inc/stm32h7xx_hal_gpio_ex.h" +#include "stm32h7xx.h" +#include "stm32h7xx_hal_gpio_ex.h" #define MCU_IDCODE 0x483U #define CORE_FREQ 240U // in Mhz @@ -43,45 +43,49 @@ separate IRQs for RX and TX. #define PROVISION_CHUNK_ADDRESS 0x080FFFE0U #define DEVICE_SERIAL_NUMBER_ADDRESS 0x080FFFC0U -#include "can.h" -#include "comms_definitions.h" +#include "board/can.h" +#include "board/comms_definitions.h" #ifndef BOOTSTUB - #include "main_definitions.h" + #include "board/main_definitions.h" #else - #include "bootstub_declarations.h" + #include "board/bootstub_declarations.h" #endif -#include "libc.h" -#include "critical.h" -#include "faults.h" -#include "utils.h" +#include "board/libc.h" +#include "board/critical.h" +#include "board/faults.h" +#include "board/utils.h" -#include "drivers/registers.h" -#include "drivers/interrupts.h" -#include "drivers/gpio.h" -#include "stm32h7/peripherals.h" -#include "stm32h7/interrupt_handlers.h" -#include "drivers/timers.h" +#include "board/drivers/registers.h" +#include "board/drivers/interrupts.h" +#include "board/drivers/gpio.h" +#include "board/stm32h7/peripherals.h" +#include "board/stm32h7/interrupt_handlers.h" +#include "board/drivers/timers.h" #if !defined(BOOTSTUB) - #include "drivers/uart.h" - #include "stm32h7/lluart.h" + #include "board/drivers/uart.h" + #include "board/stm32h7/lluart.h" #endif -#include "stm32h7/board.h" -#include "stm32h7/clock.h" +#ifdef PANDA_JUNGLE +#include "board/jungle/stm32h7/board.h" +#else +#include "board/stm32h7/board.h" +#endif +#include "board/stm32h7/clock.h" #ifdef BOOTSTUB - #include "stm32h7/llflash.h" + #include "board/stm32h7/llflash.h" #else - #include "stm32h7/llfdcan.h" + #include "board/stm32h7/llfdcan.h" #endif -#include "stm32h7/llusb.h" +#include "board/stm32h7/llusb.h" -#include "drivers/spi.h" -#include "stm32h7/llspi.h" +#include "board/drivers/spi.h" +#include "board/stm32h7/llspi.h" void early_gpio_float(void) { RCC->AHB4ENR = RCC_AHB4ENR_GPIOAEN | RCC_AHB4ENR_GPIOBEN | RCC_AHB4ENR_GPIOCEN | RCC_AHB4ENR_GPIODEN | RCC_AHB4ENR_GPIOEEN | RCC_AHB4ENR_GPIOFEN | RCC_AHB4ENR_GPIOGEN | RCC_AHB4ENR_GPIOHEN; diff --git a/examples/query_fw_versions.py b/examples/query_fw_versions.py index 302ece04..67807d5a 100755 --- a/examples/query_fw_versions.py +++ b/examples/query_fw_versions.py @@ -75,7 +75,7 @@ if __name__ == "__main__": if args.bus: bus = int(args.bus) else: - bus = 1 if panda.has_obd() else 0 + bus = 1 rx_addr = addr + int(args.rxoffset, base=16) if args.rxoffset else None # Try all sub-addresses for addr. By default, this is None diff --git a/pyproject.toml b/pyproject.toml index 23eb534b..1fa20287 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ name = "pandacan" version = "0.0.10" description = "Code powering the comma.ai panda" readme = "README.md" -requires-python = ">=3.11,<3.13" +requires-python = ">=3.11,<3.13" # macOS doesn't work with 3.13 due to pycapnp from opendbc license = {text = "MIT"} authors = [{name = "comma.ai"}] classifiers = [ @@ -13,7 +13,7 @@ classifiers = [ ] dependencies = [ "libusb1", - "opendbc @ git+https://github.com/sunnypilot/opendbc.git@c87940a6b5f0b74b8df95f5ef24d4003e7b932d4#egg=opendbc", + "opendbc @ git+https://github.com/sunnypilot/opendbc.git@master#egg=opendbc", ] [project.optional-dependencies] @@ -24,7 +24,6 @@ dev = [ "flaky", "pytest", "pytest-mock", - "pytest-xdist", "pytest-timeout", "pytest-randomly", "ruff", @@ -69,7 +68,7 @@ flake8-implicit-str-concat.allow-multiline=false "pytest.main".msg = "pytest.main requires special handling that is easy to mess up!" [tool.pytest.ini_options] -addopts = "-n0 -Werror --strict-config --strict-markers --durations=10 --ignore-glob='*.sh' --ignore=tests/misra --ignore=tests/som --ignore=tests/hitl" +addopts = "-Werror --strict-config --strict-markers --durations=10 --ignore-glob='*.sh' --ignore=tests/misra --ignore=tests/som --ignore=tests/hitl" python_files = "test_*.py" testpaths = [ "tests/" diff --git a/python/__init__.py b/python/__init__.py index e710616b..70d68d5b 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -105,9 +105,6 @@ ensure_health_packet_version = partial(ensure_version, "health", "HEALTH_PACKET_ class Panda: SERIAL_DEBUG = 0 - SERIAL_ESP = 1 - SERIAL_LIN1 = 2 - SERIAL_LIN2 = 3 SERIAL_SOM_DEBUG = 4 USB_VIDS = (0xbbaa, 0x3801) # 0x3801 is comma's registered VID @@ -115,15 +112,10 @@ class Panda: REQUEST_IN = usb1.ENDPOINT_IN | usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE REQUEST_OUT = usb1.ENDPOINT_OUT | usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE + # from https://github.com/commaai/openpilot/blob/103b4df18cbc38f4129555ab8b15824d1a672bdf/cereal/log.capnp#L648 HW_TYPE_UNKNOWN = b'\x00' - HW_TYPE_WHITE_PANDA = b'\x01' - HW_TYPE_GREY_PANDA = b'\x02' - HW_TYPE_BLACK_PANDA = b'\x03' - HW_TYPE_PEDAL = b'\x04' - HW_TYPE_UNO = b'\x05' HW_TYPE_DOS = b'\x06' HW_TYPE_RED_PANDA = b'\x07' - HW_TYPE_RED_PANDA_V2 = b'\x08' HW_TYPE_TRES = b'\x09' HW_TYPE_CUATRO = b'\x0a' @@ -133,14 +125,12 @@ class Panda: HEALTH_STRUCT = struct.Struct(" bool: + @classmethod + def wait_for_panda(cls, serial: str | None, timeout: int) -> bool: t_start = time.monotonic() - serials = Panda.list() + serials = cls.list() while (serial is None and len(serials) == 0) or (serial is not None and serial not in serials): logger.debug("waiting for panda...") time.sleep(0.1) if timeout is not None and (time.monotonic() - t_start) > timeout: return False - serials = Panda.list() + serials = cls.list() return True def up_to_date(self, fn=None) -> bool: @@ -572,7 +562,7 @@ class Panda: "interrupt_load": a[18], "fan_power": a[19], "safety_rx_checks_invalid": a[20], - "spi_checksum_error_count": a[21], + "spi_error_count": a[21], "fan_stall_count": a[22], "sbu1_voltage_mV": a[23], "sbu2_voltage_mV": a[24], @@ -669,9 +659,6 @@ class Panda: raise ValueError(f"unknown HW type: {hw_type}") - def has_obd(self): - return self.get_type() in Panda.HAS_OBD - def is_internal(self): return self.get_type() in Panda.INTERNAL_DEVICES @@ -816,16 +803,6 @@ class Panda: ret += self._handle.bulkWrite(2, struct.pack("B", port_number) + ln[i:i + 0x20]) return ret - def serial_clear(self, port_number): - """Clears all messages (tx and rx) from the specified internal uart - ringbuffer as though it were drained. - - Args: - port_number (int): port number of the uart to clear. - - """ - self._handle.controlWrite(Panda.REQUEST_OUT, 0xf2, port_number, 0, b'') - def send_heartbeat(self, engaged=True, engaged_mads=True): self._handle.controlWrite(Panda.REQUEST_OUT, 0xf3, engaged, engaged_mads, b'') diff --git a/scripts/black_white_loopback_test.py b/scripts/black_white_loopback_test.py deleted file mode 100755 index 4a243690..00000000 --- a/scripts/black_white_loopback_test.py +++ /dev/null @@ -1,157 +0,0 @@ -#!/usr/bin/env python3 - -# Loopback test between black panda (+ harness and power) and white/grey panda -# Tests all buses, including OBD CAN, which is on the same bus as CAN0 in this test. -# To be sure, the test should be run with both harness orientations - - -import os -import time -import random -import argparse -from opendbc.car.structs import CarParams -from panda import Panda - -def get_test_string(): - return b"test" + os.urandom(10) - -counter = 0 -nonzero_bus_errors = 0 -zero_bus_errors = 0 -content_errors = 0 - -def run_test(sleep_duration): - global counter - - pandas = Panda.list() - print(pandas) - - # make sure two pandas are connected - if len(pandas) != 2: - raise Exception("Connect white/grey and black panda to run this test!") - - # connect - pandas[0] = Panda(pandas[0]) - pandas[1] = Panda(pandas[1]) - - black_panda = None - other_panda = None - - # find out which one is black - if pandas[0].is_black() and not pandas[1].is_black(): - black_panda = pandas[0] - other_panda = pandas[1] - elif not pandas[0].is_black() and pandas[1].is_black(): - black_panda = pandas[1] - other_panda = pandas[0] - else: - raise Exception("Connect white/grey and black panda to run this test!") - - # disable safety modes - black_panda.set_safety_mode(CarParams.SafetyModel.allOutput) - other_panda.set_safety_mode(CarParams.SafetyModel.allOutput) - - # test health packet - print("black panda health", black_panda.health()) - print("other panda health", other_panda.health()) - - # test black -> other - while True: - test_buses(black_panda, other_panda, True, [(0, False, [0]), (1, False, [1]), (2, False, [2]), (1, True, [0])], sleep_duration) - test_buses(black_panda, other_panda, False, [(0, False, [0]), (1, False, [1]), (2, False, [2]), (0, True, [0, 1])], sleep_duration) - counter += 1 - print("Number of cycles:", counter, "Non-zero bus errors:", nonzero_bus_errors, "Zero bus errors:", zero_bus_errors, "Content errors:", content_errors) - - # Toggle relay - black_panda.set_safety_mode(CarParams.SafetyModel.silent) - time.sleep(1) - black_panda.set_safety_mode(CarParams.SafetyModel.allOutput) - time.sleep(1) - - -def test_buses(black_panda, other_panda, direction, test_array, sleep_duration): - global nonzero_bus_errors, zero_bus_errors, content_errors - - if direction: - print("***************** TESTING (BLACK --> OTHER) *****************") - else: - print("***************** TESTING (OTHER --> BLACK) *****************") - - for send_bus, obd, recv_buses in test_array: - black_panda.send_heartbeat() - other_panda.send_heartbeat() - print("\ntest can: ", send_bus, " OBD: ", obd) - - # set OBD on black panda - black_panda.set_obd(True if obd else None) - - # clear and flush - if direction: - black_panda.can_clear(send_bus) - else: - other_panda.can_clear(send_bus) - - for recv_bus in recv_buses: - if direction: - other_panda.can_clear(recv_bus) - else: - black_panda.can_clear(recv_bus) - - black_panda.can_recv() - other_panda.can_recv() - - # send the characters - at = random.randint(1, 2000) - st = get_test_string()[0:8] - if direction: - black_panda.can_send(at, st, send_bus) - else: - other_panda.can_send(at, st, send_bus) - time.sleep(0.1) - - # check for receive - if direction: - _ = black_panda.can_recv() # can echo - cans_loop = other_panda.can_recv() - else: - _ = other_panda.can_recv() # can echo - cans_loop = black_panda.can_recv() - - loop_buses = [] - for loop in cans_loop: - if (loop[0] != at) or (loop[1] != st): - content_errors += 1 - - print(" Loop on bus", str(loop[2])) - loop_buses.append(loop[2]) - if len(cans_loop) == 0: - print(" No loop") - assert not os.getenv("NOASSERT") - - # test loop buses - recv_buses.sort() - loop_buses.sort() - if(recv_buses != loop_buses): - if len(loop_buses) == 0: - zero_bus_errors += 1 - else: - nonzero_bus_errors += 1 - assert not os.getenv("NOASSERT") - else: - print(" TEST PASSED") - - time.sleep(sleep_duration) - print("\n") - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument("-n", type=int, help="Number of test iterations to run") - parser.add_argument("-sleep", type=int, help="Sleep time between tests", default=0) - args = parser.parse_args() - - if args.n is None: - while True: - run_test(sleep_duration=args.sleep) - else: - for _ in range(args.n): - run_test(sleep_duration=args.sleep) diff --git a/scripts/black_white_relay_endurance.py b/scripts/black_white_relay_endurance.py deleted file mode 100755 index 6cb0a190..00000000 --- a/scripts/black_white_relay_endurance.py +++ /dev/null @@ -1,165 +0,0 @@ -#!/usr/bin/env python3 - -# Loopback test between black panda (+ harness and power) and white/grey panda -# Tests all buses, including OBD CAN, which is on the same bus as CAN0 in this test. -# To be sure, the test should be run with both harness orientations - - -import os -import time -import random -import argparse - -from opendbc.car.structs import CarParams -from panda import Panda - -def get_test_string(): - return b"test" + os.urandom(10) - -counter = 0 -nonzero_bus_errors = 0 -zero_bus_errors = 0 -content_errors = 0 - -def run_test(sleep_duration): - global counter - - pandas = Panda.list() - print(pandas) - - # make sure two pandas are connected - if len(pandas) != 2: - raise Exception("Connect white/grey and black panda to run this test!") - - # connect - pandas[0] = Panda(pandas[0]) - pandas[1] = Panda(pandas[1]) - - black_panda = None - other_panda = None - - # find out which one is black - if pandas[0].is_black() and not pandas[1].is_black(): - black_panda = pandas[0] - other_panda = pandas[1] - elif not pandas[0].is_black() and pandas[1].is_black(): - black_panda = pandas[1] - other_panda = pandas[0] - else: - raise Exception("Connect white/grey and black panda to run this test!") - - # disable safety modes - black_panda.set_safety_mode(CarParams.SafetyModel.allOutput) - other_panda.set_safety_mode(CarParams.SafetyModel.allOutput) - - # test health packet - print("black panda health", black_panda.health()) - print("other panda health", other_panda.health()) - - # test black -> other - start_time = time.time() - temp_start_time = start_time - while True: - test_buses(black_panda, other_panda, True, [(0, False, [0]), (1, False, [1]), (2, False, [2]), (1, True, [0])], sleep_duration) - test_buses(black_panda, other_panda, False, [(0, False, [0]), (1, False, [1]), (2, False, [2]), (0, True, [0, 1])], sleep_duration) - counter += 1 - - runtime = time.time() - start_time - print("Number of cycles:", counter, "Non-zero bus errors:", nonzero_bus_errors, "Zero bus errors:", zero_bus_errors, - "Content errors:", content_errors, "Runtime: ", runtime) - - if (time.time() - temp_start_time) > 3600 * 6: - # Toggle relay - black_panda.set_safety_mode(CarParams.SafetyModel.silent) - time.sleep(1) - black_panda.set_safety_mode(CarParams.SafetyModel.allOutput) - time.sleep(1) - temp_start_time = time.time() - - -def test_buses(black_panda, other_panda, direction, test_array, sleep_duration): - global nonzero_bus_errors, zero_bus_errors, content_errors - - if direction: - print("***************** TESTING (BLACK --> OTHER) *****************") - else: - print("***************** TESTING (OTHER --> BLACK) *****************") - - for send_bus, obd, recv_buses in test_array: - black_panda.send_heartbeat() - other_panda.send_heartbeat() - print("\ntest can: ", send_bus, " OBD: ", obd) - - # set OBD on black panda - black_panda.set_obd(True if obd else None) - - # clear and flush - if direction: - black_panda.can_clear(send_bus) - else: - other_panda.can_clear(send_bus) - - for recv_bus in recv_buses: - if direction: - other_panda.can_clear(recv_bus) - else: - black_panda.can_clear(recv_bus) - - black_panda.can_recv() - other_panda.can_recv() - - # send the characters - at = random.randint(1, 2000) - st = get_test_string()[0:8] - if direction: - black_panda.can_send(at, st, send_bus) - else: - other_panda.can_send(at, st, send_bus) - time.sleep(0.1) - - # check for receive - if direction: - _ = black_panda.can_recv() # cans echo - cans_loop = other_panda.can_recv() - else: - _ = other_panda.can_recv() # cans echo - cans_loop = black_panda.can_recv() - - loop_buses = [] - for loop in cans_loop: - if (loop[0] != at) or (loop[1] != st): - content_errors += 1 - - print(" Loop on bus", str(loop[2])) - loop_buses.append(loop[2]) - if len(cans_loop) == 0: - print(" No loop") - assert os.getenv("NOASSERT") - - # test loop buses - recv_buses.sort() - loop_buses.sort() - if(recv_buses != loop_buses): - if len(loop_buses) == 0: - zero_bus_errors += 1 - else: - nonzero_bus_errors += 1 - assert os.getenv("NOASSERT") - else: - print(" TEST PASSED") - - time.sleep(sleep_duration) - print("\n") - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument("-n", type=int, help="Number of test iterations to run") - parser.add_argument("-sleep", type=int, help="Sleep time between tests", default=0) - args = parser.parse_args() - - if args.n is None: - while True: - run_test(sleep_duration=args.sleep) - else: - for _ in range(args.n): - run_test(sleep_duration=args.sleep) diff --git a/scripts/black_white_relay_test.py b/scripts/black_white_relay_test.py deleted file mode 100755 index 7526d1af..00000000 --- a/scripts/black_white_relay_test.py +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env python3 - -# Relay test with loopback between black panda (+ harness and power) and white/grey panda -# Tests the relay switching multiple times / second by looking at the buses on which loop occurs. - - -import os -import time -import random -import argparse - -from opendbc.car.structs import CarParams -from panda import Panda - -def get_test_string(): - return b"test" + os.urandom(10) - -counter = 0 -open_errors = 0 -closed_errors = 0 -content_errors = 0 - -def run_test(sleep_duration): - global counter, open_errors, closed_errors - - pandas = Panda.list() - print(pandas) - - # make sure two pandas are connected - if len(pandas) != 2: - raise Exception("Connect white/grey and black panda to run this test!") - - # connect - pandas[0] = Panda(pandas[0]) - pandas[1] = Panda(pandas[1]) - - # find out which one is black - type0 = pandas[0].get_type() - type1 = pandas[1].get_type() - - black_panda = None - other_panda = None - - if type0 == "\x03" and type1 != "\x03": - black_panda = pandas[0] - other_panda = pandas[1] - elif type0 != "\x03" and type1 == "\x03": - black_panda = pandas[1] - other_panda = pandas[0] - else: - raise Exception("Connect white/grey and black panda to run this test!") - - # disable safety modes - black_panda.set_safety_mode(CarParams.SafetyModel.allOutput) - other_panda.set_safety_mode(CarParams.SafetyModel.allOutput) - - # test health packet - print("black panda health", black_panda.health()) - print("other panda health", other_panda.health()) - - # test black -> other - while True: - # Switch on relay - black_panda.set_safety_mode(CarParams.SafetyModel.allOutput) - time.sleep(0.05) - - if not test_buses(black_panda, other_panda, (0, False, [0])): - open_errors += 1 - raise Exception("Open error") - - # Switch off relay - black_panda.set_safety_mode(CarParams.SafetyModel.silent) - time.sleep(0.05) - - if not test_buses(black_panda, other_panda, (0, False, [0, 2])): - closed_errors += 1 - raise Exception("Close error") - - counter += 1 - print("Number of cycles:", counter, "Open errors:", open_errors, "Closed errors:", closed_errors, "Content errors:", content_errors) - -def test_buses(black_panda, other_panda, test_obj): - global content_errors - send_bus, obd, recv_buses = test_obj - - black_panda.send_heartbeat() - other_panda.send_heartbeat() - - # Set OBD on send panda - other_panda.set_obd(True if obd else None) - - # clear and flush - other_panda.can_clear(send_bus) - - for recv_bus in recv_buses: - black_panda.can_clear(recv_bus) - - black_panda.can_recv() - other_panda.can_recv() - - # send the characters - at = random.randint(1, 2000) - st = get_test_string()[0:8] - other_panda.can_send(at, st, send_bus) - time.sleep(0.05) - - # check for receive - _ = other_panda.can_recv() # can echo - cans_loop = black_panda.can_recv() - - loop_buses = [] - for loop in cans_loop: - if (loop[0] != at) or (loop[1] != st): - content_errors += 1 - loop_buses.append(loop[2]) - - # test loop buses - recv_buses.sort() - loop_buses.sort() - if(recv_buses != loop_buses): - return False - else: - return True - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument("-n", type=int, help="Number of test iterations to run") - parser.add_argument("-sleep", type=int, help="Sleep time between tests", default=0) - args = parser.parse_args() - - if args.n is None: - while True: - run_test(sleep_duration=args.sleep) - else: - for _ in range(args.n): - run_test(sleep_duration=args.sleep) diff --git a/setup.sh b/setup.sh index 016b1820..41fb8ae2 100755 --- a/setup.sh +++ b/setup.sh @@ -12,11 +12,17 @@ if [[ $PLATFORM == "Darwin" ]]; then brew install --cask gcc-arm-embedded brew install python3 gcc@13 elif [[ $PLATFORM == "Linux" ]]; then + # for AGNOS since we clear the apt lists + if [[ ! -d /"var/lib/apt/" ]]; then + sudo apt update + fi + sudo apt-get install -y --no-install-recommends \ - curl \ + curl ca-certificates \ make g++ git libnewlib-arm-none-eabi \ libusb-1.0-0 \ - gcc-arm-none-eabi python3-pip python3-venv python3-dev + gcc-arm-none-eabi \ + python3-dev python3-pip python3-venv else echo "WARNING: unsupported platform. skipping apt/brew install." fi diff --git a/test.sh b/test.sh index 72879771..6412ce74 100755 --- a/test.sh +++ b/test.sh @@ -17,5 +17,5 @@ mypy python/ # *** test *** -# TODO: make xdist and randomly work -pytest -n0 --randomly-dont-reorganize tests/ +# TODO: make randomly work +pytest --randomly-dont-reorganize tests/ diff --git a/tests/hitl/3_usb_to_can.py b/tests/hitl/3_usb.py similarity index 95% rename from tests/hitl/3_usb_to_can.py rename to tests/hitl/3_usb.py index 638f4337..ba7081a4 100644 --- a/tests/hitl/3_usb_to_can.py +++ b/tests/hitl/3_usb.py @@ -1,10 +1,15 @@ import time +import pytest from flaky import flaky from opendbc.car.structs import CarParams from panda import Panda from panda.tests.hitl.helpers import time_many_sends +pytestmark = [ + pytest.mark.test_panda_types((Panda.HW_TYPE_DOS, Panda.HW_TYPE_RED_PANDA)) +] + def test_can_loopback(p): p.set_safety_mode(CarParams.SafetyModel.allOutput) p.set_can_loopback(True) diff --git a/tests/hitl/4_can_loopback.py b/tests/hitl/4_can_loopback.py index 4c7f926a..63fce9d9 100644 --- a/tests/hitl/4_can_loopback.py +++ b/tests/hitl/4_can_loopback.py @@ -7,7 +7,6 @@ from flaky import flaky from collections import defaultdict from opendbc.car.structs import CarParams -from panda.tests.hitl.conftest import PandaGroup from panda.tests.hitl.helpers import time_many_sends, get_random_can_messages, clear_can_buffers @flaky(max_runs=3, min_passes=1) @@ -90,7 +89,6 @@ def test_latency(p, panda_jungle): @pytest.mark.panda_expect_can_error -@pytest.mark.test_panda_types(PandaGroup.GEN2) def test_gen2_loopback(p, panda_jungle): def test(p_send, p_recv, address=None): for bus in range(4): diff --git a/tests/hitl/5_spi.py b/tests/hitl/5_spi.py index f9a4e28d..1861ffef 100644 --- a/tests/hitl/5_spi.py +++ b/tests/hitl/5_spi.py @@ -82,12 +82,12 @@ class TestSpi: self._ping(mocker, p) def test_bad_checksum(self, mocker, p): - cnt = p.health()['spi_checksum_error_count'] + cnt = p.health()['spi_error_count'] with patch('panda.python.spi.PandaSpiHandle._calc_checksum', return_value=0): with pytest.raises(PandaSpiNackResponse): p._handle.controlRead(Panda.REQUEST_IN, 0xd2, 0, 0, p.HEALTH_STRUCT.size, timeout=50) self._ping(mocker, p) - assert (p.health()['spi_checksum_error_count'] - cnt) > 0 + assert (p.health()['spi_error_count'] - cnt) > 0 def test_non_existent_endpoint(self, mocker, p): for _ in range(10): diff --git a/tests/hitl/9_harness.py b/tests/hitl/9_harness.py index d588fa0a..ddd3516e 100644 --- a/tests/hitl/9_harness.py +++ b/tests/hitl/9_harness.py @@ -4,12 +4,10 @@ import itertools from opendbc.car.structs import CarParams from panda import Panda -from panda.tests.hitl.conftest import PandaGroup # TODO: test relay @pytest.mark.panda_expect_can_error -@pytest.mark.test_panda_types(PandaGroup.GEN2) def test_harness_status(p, panda_jungle): # map from jungle orientations to panda orientations orientation_map = { @@ -61,7 +59,7 @@ def test_harness_status(p, panda_jungle): assert buses[2] == (0 if flipped else 2) # SBU voltages - supply_voltage_mV = 1800 if p.get_type() in [Panda.HW_TYPE_TRES, ] else 3300 + supply_voltage_mV = 1800 if p.get_type() in [Panda.HW_TYPE_TRES, Panda.HW_TYPE_CUATRO] else 3300 if orientation == Panda.HARNESS_STATUS_NC: assert health['sbu1_voltage_mV'] > 0.9 * supply_voltage_mV diff --git a/tests/hitl/conftest.py b/tests/hitl/conftest.py index 1c4db1e9..ecc3a455 100644 --- a/tests/hitl/conftest.py +++ b/tests/hitl/conftest.py @@ -1,62 +1,32 @@ import os import pytest -import concurrent.futures from panda import Panda, PandaDFU, PandaJungle from panda.tests.hitl.helpers import clear_can_buffers -# needed to get output when using xdist -if "DEBUG" in os.environ: - import sys - sys.stdout = sys.stderr - SPEED_NORMAL = 500 BUS_SPEEDS = [(0, SPEED_NORMAL), (1, SPEED_NORMAL), (2, SPEED_NORMAL)] - -JUNGLE_SERIAL = os.getenv("PANDAS_JUNGLE") +# test options NO_JUNGLE = os.environ.get("NO_JUNGLE", "0") == "1" -PANDAS_EXCLUDE = os.getenv("PANDAS_EXCLUDE", "").strip().split(" ") -HW_TYPES = os.environ.get("HW_TYPES", None) - -PARALLEL = "PARALLEL" in os.environ -NON_PARALLEL = "NON_PARALLEL" in os.environ -if PARALLEL: - NO_JUNGLE = True - -class PandaGroup: - H7 = (Panda.HW_TYPE_RED_PANDA, Panda.HW_TYPE_RED_PANDA_V2, Panda.HW_TYPE_TRES) - GEN2 = (Panda.HW_TYPE_BLACK_PANDA, Panda.HW_TYPE_UNO, Panda.HW_TYPE_DOS) + H7 - TESTED = (Panda.HW_TYPE_WHITE_PANDA, Panda.HW_TYPE_BLACK_PANDA, Panda.HW_TYPE_RED_PANDA, Panda.HW_TYPE_RED_PANDA_V2, Panda.HW_TYPE_UNO) - -if HW_TYPES is not None: - PandaGroup.TESTED = [bytes([int(x), ]) for x in HW_TYPES.strip().split(",")] # type: ignore - # Find all pandas connected -_all_pandas = {} _panda_jungle = None -def init_all_pandas(): +_panda_type = None +_panda_serial = None +def init_devices(): if not NO_JUNGLE: global _panda_jungle - _panda_jungle = PandaJungle(JUNGLE_SERIAL) + _panda_jungle = PandaJungle() _panda_jungle.set_panda_power(True) - for serial in Panda.list(): - if serial not in PANDAS_EXCLUDE: - with Panda(serial=serial, claim=False) as p: - ptype = bytes(p.get_type()) - if ptype in PandaGroup.TESTED: - _all_pandas[serial] = ptype - - # ensure we have all tested panda types - missing_types = set(PandaGroup.TESTED) - set(_all_pandas.values()) - assert len(missing_types) == 0, f"Missing panda types: {missing_types}" - - print(f"{len(_all_pandas)} total pandas") -init_all_pandas() -_all_panda_serials = sorted(_all_pandas.keys()) - + with Panda(serial=None, claim=False) as p: + global _panda_type + global _panda_serial + _panda_serial = p.get_usb_serial() + _panda_type = bytes(p.get_type()) + assert _panda_serial is not None, "No panda found!" +init_devices() def init_jungle(): if _panda_jungle is None: @@ -90,24 +60,9 @@ def pytest_collection_modifyitems(items): if item.get_closest_marker('timeout') is None: item.add_marker(pytest.mark.timeout(60)) - # xdist grouping by panda - serial = item.name.split("serial=")[1].split(",")[0] - assert len(serial) == 24 - item.add_marker(pytest.mark.xdist_group(serial)) - needs_jungle = "panda_jungle" in item.fixturenames - if PARALLEL and needs_jungle: - item.add_marker(pytest.mark.skip(reason="no jungle tests in PARALLEL mode")) - elif NON_PARALLEL and not needs_jungle: - item.add_marker(pytest.mark.skip(reason="only running jungle tests")) - -def pytest_make_parametrize_id(config, val, argname): - if val in _all_pandas: - # TODO: get nice string instead of int - hw_type = _all_pandas[val][0] - return f"serial={val}, hw_type={hw_type}" - return None - + if needs_jungle and NO_JUNGLE: + item.add_marker(pytest.mark.skip(reason="skipping tests that requires a jungle")) @pytest.fixture(name='panda_jungle', scope='function') def fixture_panda_jungle(request): @@ -116,6 +71,8 @@ def fixture_panda_jungle(request): @pytest.fixture(name='p', scope='function') def func_fixture_panda(request, module_panda): + # *** Setup *** + p = module_panda # Check if test is applicable to this panda @@ -123,14 +80,14 @@ def func_fixture_panda(request, module_panda): if mark: assert len(mark.args) > 0, "Missing panda types argument in mark" test_types = mark.args[0] - if _all_pandas[p.get_usb_serial()] not in test_types: + if _panda_type not in test_types: pytest.skip(f"Not applicable, {test_types} pandas only") mark = request.node.get_closest_marker('skip_panda_types') if mark: assert len(mark.args) > 0, "Missing panda types argument in mark" skip_types = mark.args[0] - if _all_pandas[p.get_usb_serial()] in skip_types: + if _panda_type in skip_types: pytest.skip(f"Not applicable to {skip_types}") # this is 2+ seconds on USB pandas due to slow @@ -140,10 +97,10 @@ def func_fixture_panda(request, module_panda): # ensure FW hasn't changed assert p.up_to_date() - # Run test + # *** Run test *** yield p - # Teardown + # *** Teardown *** # reconnect if p.get_dfu_serial() in PandaDFU.list(): @@ -164,7 +121,7 @@ def func_fixture_panda(request, module_panda): assert p.health()['fault_status'] == 0 # Check for SPI errors - #assert p.health()['spi_checksum_error_count'] == 0 + #assert p.health()['spi_error_count'] == 0 # Check health of each CAN core after test, normal to fail for test_gen2_loopback on OBD bus, so skipping mark = request.node.get_closest_marker('panda_expect_can_error') @@ -182,41 +139,27 @@ def func_fixture_panda(request, module_panda): assert can_health['total_error_cnt'] == 0 assert can_health['total_tx_checksum_error_cnt'] == 0 -@pytest.fixture(name='module_panda', params=_all_panda_serials, scope='module') +@pytest.fixture(name='module_panda', scope='module') def fixture_panda_setup(request): """ - Clean up all pandas + jungle and return the panda under test. + Clean up panda + jungle and return the panda under test. """ - panda_serial = request.param - - # Initialize jungle + # init jungle init_jungle() - # Connect to pandas - def cnnct(s): - if s == panda_serial: - p = Panda(serial=s) - p.reset(reconnect=True) + # init panda + p = Panda(serial=_panda_serial) + p.reset(reconnect=True) - p.set_can_loopback(False) - p.set_power_save(False) - for bus, speed in BUS_SPEEDS: - p.set_can_speed_kbps(bus, speed) - clear_can_buffers(p) - p.set_power_save(False) - return p - elif not PARALLEL: - with Panda(serial=s) as p: - p.reset(reconnect=False) - return None - - with concurrent.futures.ThreadPoolExecutor() as exc: - ps = list(exc.map(cnnct, _all_panda_serials, timeout=20)) - pandas = [p for p in ps if p is not None] + p.set_can_loopback(False) + p.set_power_save(False) + for bus, speed in BUS_SPEEDS: + p.set_can_speed_kbps(bus, speed) + clear_can_buffers(p) + p.set_power_save(False) # run test - yield pandas[0] + yield p - # Teardown - for p in pandas: - p.close() + # teardown + p.close() diff --git a/tests/hitl/reset_jungles.py b/tests/hitl/reset_jungles.py index fb946731..09bd04ad 100755 --- a/tests/hitl/reset_jungles.py +++ b/tests/hitl/reset_jungles.py @@ -4,7 +4,9 @@ import concurrent.futures from panda import PandaJungle, PandaJungleDFU, McuType from panda.tests.libs.resetter import Resetter -SERIALS = {'180019001451313236343430', '1d0017000c50435635333720'} +SERIALS = { + '180019001451313236343430', # jungle v2 +} def recover(s): with PandaJungleDFU(s) as pd: @@ -25,9 +27,9 @@ if __name__ == "__main__": for i in range(1, 4): r.enable_power(i, 0) r.cycle_power(ports=[1, 2], dfu=True) - + for s in SERIALS: + assert PandaJungle.wait_for_dfu(PandaJungleDFU.st_serial_to_dfu_serial(s, McuType.H7), timeout=10) dfu_serials = PandaJungleDFU.list() - print(len(dfu_serials), len(SERIALS)) assert len(dfu_serials) == len(SERIALS) with concurrent.futures.ProcessPoolExecutor(max_workers=len(dfu_serials)) as exc: @@ -36,7 +38,9 @@ if __name__ == "__main__": # power cycle for H7 bootloader bug r.cycle_power(ports=[1, 2]) - serials = PandaJungle.list() + # wait for them to come back up + for s in SERIALS: + assert PandaJungle.wait_for_panda(s, timeout=10) assert set(PandaJungle.list()) >= SERIALS mcu_types = list(exc.map(flash, SERIALS, timeout=20)) - assert set(mcu_types) == {McuType.F4, McuType.H7} + assert set(mcu_types) == {McuType.H7, } diff --git a/tests/hitl/run_parallel_tests.sh b/tests/hitl/run_parallel_tests.sh deleted file mode 100755 index f60d838c..00000000 --- a/tests/hitl/run_parallel_tests.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -set -e - -DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" -cd $DIR - -# n = number of pandas tested -PARALLEL=1 pytest --durations=0 *.py -n 5 --dist loadgroup -x diff --git a/tests/hitl/run_serial_tests.sh b/tests/hitl/run_serial_tests.sh deleted file mode 100755 index 4feae5e3..00000000 --- a/tests/hitl/run_serial_tests.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -set -e - -DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" -cd $DIR - -NON_PARALLEL=1 pytest --durations=0 *.py -x diff --git a/tests/libs/resetter.py b/tests/libs/resetter.py index 3868bde6..52c44e42 100644 --- a/tests/libs/resetter.py +++ b/tests/libs/resetter.py @@ -42,16 +42,17 @@ class Resetter(): def enable_boot(self, enabled): self._handle.controlWrite((usb1.ENDPOINT_OUT | usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE), 0xff, 0, enabled, b'') - def cycle_power(self, delay=5, dfu=False, ports=None): + def cycle_power(self, dfu=False, ports=None): if ports is None: ports = [1, 2, 3] self.enable_boot(dfu) for port in ports: self.enable_power(port, False) - time.sleep(0.5) + time.sleep(0.05) for port in ports: self.enable_power(port, True) - time.sleep(delay) + time.sleep(0.05) self.enable_boot(False) + time.sleep(0.12) # takes the kernel this long to detect the disconnect diff --git a/tests/misra/checkers.txt b/tests/misra/checkers.txt index 0b6bfc55..0c8b0d77 100644 --- a/tests/misra/checkers.txt +++ b/tests/misra/checkers.txt @@ -5,7 +5,7 @@ Cppcheck checkers list from test_misra.sh: TEST variant options: ---enable=all --disable=unusedFunction -DPANDA --addon=misra -DSTM32F4 -DSTM32F413xx /board/main.c +--enable=all --disable=unusedFunction --addon=misra -DSTM32F4 -DSTM32F413xx -I /board/stm32f4/inc/ /board/main.c Critical errors @@ -460,7 +460,7 @@ Not available, Cppcheck Premium is not used TEST variant options: ---enable=all --disable=unusedFunction -DPANDA --addon=misra -DSTM32H7 -DSTM32H725xx /board/main.c +--enable=all --disable=unusedFunction --addon=misra -DSTM32H7 -DSTM32H725xx -I /board/stm32h7/inc/ /board/main.c Critical errors diff --git a/tests/misra/test_misra.sh b/tests/misra/test_misra.sh index 3b16863b..f909ab9e 100755 --- a/tests/misra/test_misra.sh +++ b/tests/misra/test_misra.sh @@ -37,7 +37,7 @@ echo "Cppcheck checkers list from test_misra.sh:" > $CHECKLIST cppcheck() { # get all gcc defines: arm-none-eabi-gcc -dM -E - < /dev/null - COMMON_DEFINES="-D__GNUC__=9 -UCMSIS_NVIC_VIRTUAL -UCMSIS_VECTAB_VIRTUAL" + COMMON_DEFINES="-D__GNUC__=9 -UCMSIS_NVIC_VIRTUAL -UCMSIS_VECTAB_VIRTUAL -UPANDA_JUNGLE -UBOOTSTUB" # note that cppcheck build cache results in inconsistent results as of v2.13.0 OUTPUT=$DIR/.output.log @@ -45,9 +45,9 @@ cppcheck() { echo -e "\n\n\n\n\nTEST variant options:" >> $CHECKLIST echo -e ""${@//$PANDA_DIR/}"\n\n" >> $CHECKLIST # (absolute path removed) - $CPPCHECK_DIR/cppcheck --inline-suppr -I $PANDA_DIR/board/ \ + $CPPCHECK_DIR/cppcheck --inline-suppr \ + -I $PANDA_DIR \ -I "$(arm-none-eabi-gcc -print-file-name=include)" \ - -I $PANDA_DIR/board/stm32f4/inc/ -I $PANDA_DIR/board/stm32h7/inc/ \ -I $OPENDBC_ROOT \ --suppressions-list=$DIR/suppressions.txt --suppress=*:*inc/* \ --suppress=*:*include/* --error-exitcode=2 --check-level=exhaustive --safety \ @@ -64,13 +64,13 @@ cppcheck() { fi } -PANDA_OPTS="--enable=all --disable=unusedFunction -DPANDA --addon=misra" +PANDA_OPTS="--enable=all --disable=unusedFunction --addon=misra" printf "\n${GREEN}** PANDA F4 CODE **${NC}\n" -cppcheck $PANDA_OPTS -DSTM32F4 -DSTM32F413xx $PANDA_DIR/board/main.c +cppcheck $PANDA_OPTS -DSTM32F4 -DSTM32F413xx -I $PANDA_DIR/board/stm32f4/inc/ $PANDA_DIR/board/main.c printf "\n${GREEN}** PANDA H7 CODE **${NC}\n" -cppcheck $PANDA_OPTS -DSTM32H7 -DSTM32H725xx $PANDA_DIR/board/main.c +cppcheck $PANDA_OPTS -DSTM32H7 -DSTM32H725xx -I $PANDA_DIR/board/stm32h7/inc/ $PANDA_DIR/board/main.c # unused needs to run globally #printf "\n${GREEN}** UNUSED ALL CODE **${NC}\n" diff --git a/tests/som/test_bootkick.py b/tests/som/test_bootkick.py index ba63cff8..497cfd81 100644 --- a/tests/som/test_bootkick.py +++ b/tests/som/test_bootkick.py @@ -4,7 +4,7 @@ import pytest from opendbc.car.structs import CarParams from panda import Panda, PandaJungle -PANDA_SERIAL = "28002d000451323431333839" +PANDA_SERIAL = "300008001851333037333932" JUNGLE_SERIAL = "26001c001451313236343430" OBDC_PORT = 1