Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 133 additions & 12 deletions SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,16 @@ def build_project(project_name, project, extra_flags):
'.',
'..',
panda_root,
f"{panda_root}/board/",
f"{panda_root}/../opendbc/safety/",
f"{panda_root}/../opendbc",
f"{panda_root}/../opendbc/safety",
f"{panda_root}/include/",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it possible to use something like f"{panda_root}/include/**" to avoid having to list every folder?

Copy link
Copy Markdown
Contributor Author

@aubsw aubsw Apr 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suprisingly, niether GCC nor SCons provides recursive directory include search. We have a few options:

  1. leave it how it is
  2. write a helper function to recursively get search paths
  3. add only top-level directories to the search path, adjust all header includes to use the full path. I.e. #include "registers.h" would become #include "drivers/registers.h" everywhere.

I kind of prefer option 3 because it clarifies the directory structure of included headers in the source code.

f"{panda_root}/include/board/",
f"{panda_root}/include/board/stm32h7",
f"{panda_root}/include/board/stm32f4",
f"{panda_root}/include/board/boards/",
f"{panda_root}/include/board/drivers/",
f"{panda_root}/include/board/jungle/",
f"{panda_root}/include/board/jungle/boards/",
]

env = Environment(
Expand All @@ -104,21 +112,135 @@ def build_project(project_name, project, extra_flags):
tools=["default", "compilation_db"],
)

startup = env.Object(f"obj/startup_{project_name}", project["STARTUP_FILE"])
def make_object(_env, name, path):
return _env.Object(f"{name}-{project_name}", path)

startup = make_object(env, 'obj/startup', 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")
make_object(env, 'rsa', f"{panda_root}/crypto/rsa.c"),
make_object(env, 'sha', f"{panda_root}/crypto/sha.c")
]

# Sources shared by all Panda variants
sources = [
("can", f"{panda_root}/board/can.c"),
("critical", f"{panda_root}/board/critical.c"),
("drivers_clock_source", f"{panda_root}/board/drivers/clock_source.c"),
("drivers_gpio", f"{panda_root}/board/drivers/gpio.c"),
("drivers_interrupts", f"{panda_root}/board/drivers/interrupts.c"),
("drivers_registers", f"{panda_root}/board/drivers/registers.c"),
("drivers_spi", f"{panda_root}/board/drivers/spi.c"),
("drivers_timers", f"{panda_root}/board/drivers/timers.c"),
("drivers_usb", f"{panda_root}/board/drivers/usb.c"),
("early_init", f"{panda_root}/board/early_init.c"),
("faults", f"{panda_root}/board/faults.c"),
("libc", f"{panda_root}/board/libc.c"),
("safety", f"{panda_root}/board/safety.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)

_is_panda_jungle = "PANDA_JUNGLE" in " ".join(extra_flags)
_is_stm32h7 = "DSTM32H7" in " ".join(project["PROJECT_FLAGS"])
_is_stm32f4 = "DSTM32F4" in " ".join(project["PROJECT_FLAGS"])

# Jungle does not get these drivers.
if not _is_panda_jungle:
sources.extend([
("drivers_harness", f"{panda_root}/board/drivers/harness.c"),
("drivers_simple_watchdog", f"{panda_root}/board/drivers/simple_watchdog.c"),
("drivers_fan", f"{panda_root}/board/drivers/fan.c"),
])

if _is_stm32h7:
sources.extend([
("drivers_fake_siren", f"{panda_root}/board/drivers/fake_siren.c"),
("stm32h7_clock", f"{panda_root}/board/stm32h7/clock.c"),
("stm32h7_lldac", f"{panda_root}/board/stm32h7/lldac.c"),
("stm32h7_llflash", f"{panda_root}/board/stm32h7/llflash.c"),
("stm32h7_lli2c", f"{panda_root}/board/stm32h7/lli2c.c"),
("stm32h7_llspi", f"{panda_root}/board/stm32h7/llspi.c"),
("stm32h7_llusb", f"{panda_root}/board/stm32h7/llusb.c"),
("stm32h7_peripherals", f"{panda_root}/board/stm32h7/peripherals.c"),
])
if _is_panda_jungle:
sources.extend([
("stm32h7_jungle_lladc", f"{panda_root}/board/jungle/stm32h7/lladc.c"),
])
else:
sources.extend([
("stm32h7_lladc", f"{panda_root}/board/stm32h7/lladc.c"),
("stm32h7_llfan", f"{panda_root}/board/stm32h7/llfan.c"),
("stm32h7_sound", f"{panda_root}/board/stm32h7/sound.c"),
])

if _is_stm32f4:
sources.extend([
("stm32f4_clock", f"{panda_root}/board/stm32f4/clock.c"),
("stm32f4_llusb", f"{panda_root}/board/stm32f4/llusb.c"),
("stm32f4_lladc", f"{panda_root}/board/stm32f4/lladc.c"),
("stm32f4_llflash", f"{panda_root}/board/stm32f4/llflash.c"),
("stm32f4_llspi", f"{panda_root}/board/stm32f4/llspi.c"),
("stm32f4_peripherals", f"{panda_root}/board/stm32f4/peripherals.c"),
])
if not _is_panda_jungle:
sources.extend([
("stm32f4_llfan", f"{panda_root}/board/stm32f4/llfan.c"),
])

# Create a bootstub-specific environment with -DBOOTSTUB flag
bootstub_env = env.Clone()
bootstub_env.Append(CFLAGS=["-DBOOTSTUB"])
bootstub_env.Append(ASFLAGS=["-DBOOTSTUB"])
bootstub_env.Append(LINKFLAGS=["-DBOOTSTUB"])

# Recompile all sources with the bootstub_env for bootstub use
bootstub_definitions = (f"bootstub_definitions", f"{panda_root}/board/bootstub_definitions.c")
flasher = (f"flasher", f"{panda_root}/board/flasher.c")
bootstub_sources = [
make_object(bootstub_env, f"bootstub-{name}", path)
for name, path in sources + [bootstub_definitions, flasher]]

# Compile bootstub.c
bootstub_obj = make_object(bootstub_env, "bootstub", f"{panda_root}/board/bootstub.c")
bootstub_elf = bootstub_env.Program(f"obj/bootstub.{project_name}.elf",
[startup] + bootstub_sources + crypto_obj + [bootstub_obj])
bootstub_env.Objcopy(f"obj/bootstub.{project_name}.bin", bootstub_elf)

# Needed for full build.
sources.extend([
("can_comms", f"{panda_root}/board/can_comms.c"),
("drivers_can_common", f"{panda_root}/board/drivers/can_common.c"),
("drivers_uart", f"{panda_root}/board/drivers/uart.c"),
("main_definitions", f"{panda_root}/board/main_definitions.c"),
])
if _is_panda_jungle:
sources.extend([
("jungle_main_comms", f"{panda_root}/board/jungle/main_comms.c"),
])
else:
sources.extend([
("drivers_bootkick", f"{panda_root}/board/drivers/bootkick.c"),
("main_comms", f"{panda_root}/board/main_comms.c"),
("power_saving", f"{panda_root}/board/power_saving.c"),
])
if _is_stm32h7:
sources.extend([
("drivers_fdcan", f"{panda_root}/board/drivers/fdcan.c"),
("stm32h7_llfdcan", f"{panda_root}/board/stm32h7/llfdcan.c"),
("stm32h7_lluart", f"{panda_root}/board/stm32h7/lluart.c"),
])
if _is_stm32f4:
sources.extend([
("drivers_bxcan", f"{panda_root}/board/drivers/bxcan.c"),
("stm32f4_llbxcan", f"{panda_root}/board/stm32f4/llbxcan.c"),
("stm32f4_lluart", f"{panda_root}/board/stm32f4/lluart.c"),
])

# Build main
main_sources = [make_object(env, name, path) for name, path in sources]
main_obj = env.Object(f"main-{project_name}", project["MAIN"])
main_elf = env.Program(f"obj/{project_name}.elf", [startup, main_obj],
main_elf = env.Program(f"obj/{project_name}.elf", [startup, main_obj] + main_sources,
LINKFLAGS=[f"-Wl,--section-start,.isr_vector={project['APP_START_ADDRESS']}"] + flags)
main_bin = env.Objcopy(f"obj/{project_name}.bin", main_elf)

Expand Down Expand Up @@ -169,8 +291,7 @@ 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)
f.write(f'extern const uint8_t gitversion[{len(version)}];\n')
f.write(f'const uint8_t gitversion[{len(version)}] = "{version}";\n')
f.write(f'static const uint8_t gitversion[{len(version)}] = "{version}";\n')

with open("board/obj/version", "w") as f:
f.write(f'{get_version(BUILDER, BUILD_TYPE)}')
Expand Down
14 changes: 11 additions & 3 deletions board/bootstub.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
#define BOOTSTUB

#define VERS_TAG 0x53524556
#define MIN_VERSION 2

// ********************* Includes *********************
#include "flasher.h"

#include "boards/board.h"
#include "config.h"
#include "critical.h"
// platform includes
#ifdef STM32H7
#include "stm32h7/stm32h7_config.h"
#elif defined(STM32F4)
#include "stm32f4/stm32f4_config.h"
#endif

#include "drivers/led.h"
#include "drivers/pwm.h"
Expand All @@ -18,7 +26,7 @@

#include "obj/cert.h"
#include "obj/gitversion.h"
#include "flasher.h"


// cppcheck-suppress unusedFunction ; used in headers not included in cppcheck
void __initialize_hardware_early(void) {
Expand Down
19 changes: 13 additions & 6 deletions board/bootstub_declarations.h → board/bootstub_definitions.c
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
// ******************** Prototypes ********************
#include "bootstub_definitions.h"
#include "utils.h"

void print(const char *a){ UNUSED(a); }
void puth(uint8_t i){ UNUSED(i); }
void puth2(uint8_t i){ UNUSED(i); }
void puth4(uint8_t i){ UNUSED(i); }
void hexdump(const void *a, int l){ UNUSED(a); UNUSED(l); }
typedef struct board board;
typedef struct harness_configuration harness_configuration;
void pwm_init(TIM_TypeDef *TIM, uint8_t channel);
void pwm_set(TIM_TypeDef *TIM, uint8_t channel, uint8_t percentage);
// No UART support in bootloader
typedef struct uart_ring {} uart_ring;
uart_ring uart_ring_som_debug;
uart_ring uart_ring_debug;
uart_ring *get_ring_by_number(int a);
void uart_init(uart_ring *q, int baud) { UNUSED(q); UNUSED(baud); }
bool put_char(uart_ring *q, char elem);

// ********************* Globals **********************
uint8_t hw_type = 0;
board *current_board;

uint32_t uptime_cnt;
bool ignition_can;
bool heartbeat_lost;
bool bootkick_reset_triggered;

void refresh_can_tx_slots_available(void);
3 changes: 3 additions & 0 deletions board/can.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include "can.h"

const unsigned char dlc_to_len[] = {0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 12U, 16U, 20U, 24U, 32U, 48U, 64U};
7 changes: 0 additions & 7 deletions board/can.h

This file was deleted.

17 changes: 4 additions & 13 deletions board/can_comms.h → board/can_comms.c
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
/*
CAN transactions to and from the host come in the form of
a certain number of CANPacket_t. The transaction is split
into multiple transfers or chunks.

* comms_can_read outputs this buffer in chunks of a specified length.
chunks are always the given length, except the last one.
* comms_can_write reads in this buffer in chunks.
* both functions maintain an overflow buffer for a partial CANPacket_t that
spans multiple transfers/chunks.
* the overflow buffers are reset by a dedicated control transfer handler,
which is sent by the host on each start of a connection.
*/
#include "can.h"
#include "can_comms.h"
#include "libc.h"
#include "utils.h"

typedef struct {
uint32_t ptr;
Expand Down
29 changes: 0 additions & 29 deletions board/can_declarations.h

This file was deleted.

6 changes: 4 additions & 2 deletions board/critical.h → board/critical.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#include "critical_declarations.h"
#include "critical.h"
#include <stdbool.h>
#include "drivers/interrupts.h"

// ********************* Critical section helpers *********************
uint8_t global_critical_depth = 0U;

static volatile bool interrupts_enabled = false;
volatile bool interrupts_enabled = false;

void enable_interrupts(void) {
interrupts_enabled = true;
Expand Down
6 changes: 5 additions & 1 deletion board/drivers/bootkick.h → board/drivers/bootkick.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
#include "bootkick_declarations.h"
#include "bootkick.h"
#include <stdint.h>
#include "config.h"
#include "drivers/harness.h"
#include "drivers/uart.h"

bool bootkick_reset_triggered = false;

Expand Down
10 changes: 9 additions & 1 deletion board/drivers/bxcan.h → board/drivers/bxcan.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
#include "bxcan_declarations.h"
#include "bxcan.h"
#include "can_common.h"
#include "can_comms.h"
#include "can.h"
#include "critical.h"
#include "drivers/led.h"
#include "drivers/interrupts.h"
#include "libc.h"
#include "stm32f4/llbxcan.h"

// IRQs: CAN1_TX, CAN1_RX0, CAN1_SCE
// CAN2_TX, CAN2_RX0, CAN2_SCE
Expand Down
42 changes: 22 additions & 20 deletions board/drivers/can_common.h → board/drivers/can_common.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,25 @@
#include "can_common_declarations.h"
#include "can_common.h"

#include "boards/board.h"
#include "can_comms.h"
#include "config.h"
#include "utils.h"

#ifndef LIBPANDA
#include "critical.h"
#endif

#ifdef STM32H7
// ITCM RAM and DTCM RAM are the fastest for Cortex-M7 core access
__attribute__((section(".axisram"))) can_buffer(rx_q, CAN_RX_BUFFER_SIZE)
__attribute__((section(".itcmram"))) can_buffer(tx1_q, CAN_TX_BUFFER_SIZE)
__attribute__((section(".itcmram"))) can_buffer(tx2_q, CAN_TX_BUFFER_SIZE)
#else
can_buffer(rx_q, CAN_RX_BUFFER_SIZE)
can_buffer(tx1_q, CAN_TX_BUFFER_SIZE)
can_buffer(tx2_q, CAN_TX_BUFFER_SIZE)
#endif
can_buffer(tx3_q, CAN_TX_BUFFER_SIZE)

uint32_t safety_tx_blocked = 0;
uint32_t safety_rx_invalid = 0;
Expand All @@ -17,25 +38,6 @@ int can_silent = ALL_CAN_SILENT;
bool can_loopback = false;

// ********************* instantiate queues *********************
#define can_buffer(x, size) \
static CANPacket_t elems_##x[size]; \
extern can_ring can_##x; \
can_ring can_##x = { .w_ptr = 0, .r_ptr = 0, .fifo_size = (size), .elems = (CANPacket_t *)&(elems_##x) };

#define CAN_RX_BUFFER_SIZE 4096U
#define CAN_TX_BUFFER_SIZE 416U

#ifdef STM32H7
// ITCM RAM and DTCM RAM are the fastest for Cortex-M7 core access
__attribute__((section(".axisram"))) can_buffer(rx_q, CAN_RX_BUFFER_SIZE)
__attribute__((section(".itcmram"))) can_buffer(tx1_q, CAN_TX_BUFFER_SIZE)
__attribute__((section(".itcmram"))) can_buffer(tx2_q, CAN_TX_BUFFER_SIZE)
#else
can_buffer(rx_q, CAN_RX_BUFFER_SIZE)
can_buffer(tx1_q, CAN_TX_BUFFER_SIZE)
can_buffer(tx2_q, CAN_TX_BUFFER_SIZE)
#endif
can_buffer(tx3_q, CAN_TX_BUFFER_SIZE)

// FIXME:
// cppcheck-suppress misra-c2012-9.3
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include "clock_source_declarations.h"
#include "clock_source.h"
#include "gpio.h"
#include "registers.h"

void clock_source_set_period(uint8_t period) {
register_set(&(TIM1->ARR), ((period*10U) - 1U), 0xFFFFU);
Expand Down
Loading
Loading