mirror of
https://github.com/infiniteCable2/panda.git
synced 2026-02-18 17:23:52 +08:00
Sync: commaai/panda:master into sunnypilot/panda:master
This commit is contained in:
2
.github/workflows/test.yaml
vendored
2
.github/workflows/test.yaml
vendored
@@ -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"
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -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
|
||||
|
||||
26
Dockerfile
26
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
|
||||
|
||||
15
Jenkinsfile
vendored
15
Jenkinsfile
vendored
@@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
95
SConscript
95
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'):
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
};
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "stm32h7/lli2c.h"
|
||||
#include "board/stm32h7/lli2c.h"
|
||||
|
||||
#define CODEC_I2C_ADDR 0x10
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
#define CANFD
|
||||
#define ALLOW_DEBUG
|
||||
#define PANDA
|
||||
|
||||
#define ENTER_CRITICAL() 0
|
||||
#define EXIT_CRITICAL() 0
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
@@ -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):
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
93
board/main.c
93
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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
20
board/stm32f4/lladc_declarations.h
Normal file
20
board/stm32f4/lladc_declarations.h
Normal file
@@ -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}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
37
board/stm32h7/lladc_declarations.h
Normal file
37
board/stm32h7/lladc_declarations.h
Normal file
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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/"
|
||||
|
||||
@@ -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("<IIIIIIIIBBBBBHBBBHfBBHBHHB")
|
||||
CAN_HEALTH_STRUCT = struct.Struct("<BIBBBBBBBBIIIIIIIHHBBBIIII")
|
||||
|
||||
F4_DEVICES = [HW_TYPE_WHITE_PANDA, HW_TYPE_GREY_PANDA, HW_TYPE_BLACK_PANDA, HW_TYPE_UNO, HW_TYPE_DOS]
|
||||
H7_DEVICES = [HW_TYPE_RED_PANDA, HW_TYPE_RED_PANDA_V2, HW_TYPE_TRES, HW_TYPE_CUATRO]
|
||||
F4_DEVICES = [HW_TYPE_DOS, ]
|
||||
H7_DEVICES = [HW_TYPE_RED_PANDA, HW_TYPE_TRES, HW_TYPE_CUATRO]
|
||||
|
||||
INTERNAL_DEVICES = (HW_TYPE_UNO, HW_TYPE_DOS, HW_TYPE_TRES, HW_TYPE_CUATRO)
|
||||
HAS_OBD = (HW_TYPE_BLACK_PANDA, HW_TYPE_UNO, HW_TYPE_DOS, HW_TYPE_RED_PANDA, HW_TYPE_RED_PANDA_V2, HW_TYPE_TRES, HW_TYPE_CUATRO)
|
||||
INTERNAL_DEVICES = (HW_TYPE_DOS, HW_TYPE_TRES, HW_TYPE_CUATRO)
|
||||
|
||||
MAX_FAN_RPMs = {
|
||||
HW_TYPE_UNO: 5100,
|
||||
HW_TYPE_DOS: 6500,
|
||||
HW_TYPE_TRES: 6600,
|
||||
HW_TYPE_CUATRO: 12500,
|
||||
@@ -522,16 +512,16 @@ class Panda:
|
||||
dfu_list = PandaDFU.list()
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def wait_for_panda(serial: str | None, timeout: int) -> 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'')
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
10
setup.sh
10
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
|
||||
|
||||
4
test.sh
4
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/
|
||||
|
||||
@@ -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)
|
||||
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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, }
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user