import os
import opendbc
import subprocess
PREFIX = " arm-none-eabi- "
BUILDER = " DEV "
common_flags = [ ]
if os . getenv ( " RELEASE " ) :
BUILD_TYPE = " RELEASE "
cert_fn = os . getenv ( " CERT " )
assert cert_fn is not None , ' No certificate file specified. Please set CERT env variable '
assert os . path . exists ( cert_fn ) , ' Certificate file not found. Please specify absolute path '
else :
BUILD_TYPE = " DEBUG "
cert_fn = File ( " ./certs/debug " ) . srcnode ( ) . relpath
common_flags + = [ " -DALLOW_DEBUG " ]
if os . getenv ( " DEBUG " ) :
common_flags + = [ " -DDEBUG " ]
def objcopy ( source , target , env , for_signature ) :
return ' $OBJCOPY -O binary %s %s ' % ( source [ 0 ] , target [ 0 ] )
def get_version ( builder , build_type ) :
try :
git = subprocess . check_output ( [ " git " , " rev-parse " , " --short=8 " , " HEAD " ] , encoding = ' utf8 ' ) . strip ( )
except subprocess . CalledProcessError :
git = " unknown "
return f " { builder } - { git } - { build_type } "
def get_key_header ( name ) :
from Crypto . PublicKey import RSA
public_fn = File ( f ' ./certs/ { name } .pub ' ) . srcnode ( ) . get_path ( )
with open ( public_fn ) as f :
rsa = RSA . importKey ( f . read ( ) )
assert ( rsa . size_in_bits ( ) == 1024 )
rr = pow ( 2 * * 1024 , 2 , rsa . n )
n0inv = 2 * * 32 - pow ( rsa . n , - 1 , 2 * * 32 )
r = [
f " RSAPublicKey { name } _rsa_key = {{ " ,
f " .len = 0x20, " ,
f " .n0inv = { n0inv } U, " ,
f " .n = { to_c_uint32 ( rsa . n ) } , " ,
f " .rr = { to_c_uint32 ( rr ) } , " ,
f " .exponent = { rsa . e } , " ,
f " }} ; " ,
]
return r
def to_c_uint32 ( x ) :
nums = [ ]
for _ in range ( 0x20 ) :
nums . append ( x % ( 2 * * 32 ) )
x / / = ( 2 * * 32 )
return " { " + ' U, ' . join ( map ( str , nums ) ) + " U} "
def build_project ( project_name , project , main , extra_flags ) :
project_dir = Dir ( f ' ./board/obj/ { project_name } / ' )
flags = project [ " FLAGS " ] + extra_flags + common_flags + [
" -Wall " ,
" -Wextra " ,
" -Wstrict-prototypes " ,
" -Werror " ,
" -mlittle-endian " ,
" -mthumb " ,
" -nostdlib " ,
" -fno-builtin " ,
" -std=gnu11 " ,
" -fmax-errors=1 " ,
f " -T { File ( project [ ' LINKER_SCRIPT ' ] ) . srcnode ( ) . relpath } " ,
" -fsingle-precision-constant " ,
" -Os " ,
" -g " ,
]
env = Environment (
ENV = os . environ ,
CC = PREFIX + ' gcc ' ,
AS = PREFIX + ' gcc ' ,
OBJCOPY = PREFIX + ' objcopy ' ,
OBJDUMP = PREFIX + ' objdump ' ,
OBJPREFIX = project_dir ,
CFLAGS = flags ,
ASFLAGS = flags ,
LINKFLAGS = flags ,
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 ' )
} ,
tools = [ " default " , " compilation_db " ] ,
)
startup = env . Object ( project [ " STARTUP_FILE " ] )
# 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 + 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 = {
" STARTUP_FILE " : " ./board/stm32f4/startup_stm32f413xx.s " ,
" LINKER_SCRIPT " : " ./board/stm32f4/stm32f4_flash.ld " ,
" APP_START_ADDRESS " : " 0x8004000 " ,
" FLAGS " : [
" -mcpu=cortex-m4 " ,
" -mhard-float " ,
" -DSTM32F4 " ,
" -DSTM32F413xx " ,
" -Iboard/stm32f4/inc " ,
" -mfpu=fpv4-sp-d16 " ,
] ,
}
base_project_h7 = {
" STARTUP_FILE " : " ./board/stm32h7/startup_stm32h7x5xx.s " ,
" LINKER_SCRIPT " : " ./board/stm32h7/stm32h7x5_flash.ld " ,
" APP_START_ADDRESS " : " 0x8020000 " ,
" FLAGS " : [
" -mcpu=cortex-m7 " ,
" -mhard-float " ,
" -DSTM32H7 " ,
" -DSTM32H725xx " ,
" -Iboard/stm32h7/inc " ,
" -mfpu=fpv5-d16 " ,
] ,
}
# 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 ' )
with open ( " board/obj/version " , " w " ) as f :
f . write ( f ' { get_version ( BUILDER , BUILD_TYPE ) } ' )
certs = [ get_key_header ( n ) for n in [ " debug " , " release " ] ]
with open ( " board/obj/cert.h " , " w " ) as f :
for cert in certs :
f . write ( " \n " . join ( cert ) + " \n " )
# panda fw
build_project ( " panda " , base_project_f4 , " ./board/main.c " , [ ] )
build_project ( " panda_h7 " , base_project_h7 , " ./board/main.c " , [ ] )
# panda jungle fw
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 ' ) :
SConscript ( ' tests/libpanda/SConscript ' )