@@ -681,18 +681,28 @@ def add_dynamic_boards_from_hwdef_dir(base_type, hwdef_dir):
681681 newclass = type (d , (base_type ,), {'name' : d })
682682
683683def add_dynamic_boards_esp32 ():
684- '''add boards based on existence of hwdef.dat in subdirectories for ESP32'''
685- dirname , dirlist , filenames = next (os .walk ('libraries/AP_HAL_ESP32/hwdef' ))
686- for d in dirlist :
687- if d in _board_classes .keys ():
688- continue
689- hwdef = os .path .join (dirname , d , 'hwdef.dat' )
690- if os .path .exists (hwdef ):
691- mcu_esp32s3 = True if (d [0 :7 ] == "esp32s3" ) else False
692- if mcu_esp32s3 :
693- newclass = type (d , (esp32s3 ,), {'name' : d })
694- else :
695- newclass = type (d , (esp32 ,), {'name' : d })
684+ '''add boards based on existence of hwdef.dat in hwdef subdirectories or legacy headers in boards directory'''
685+ hwdef_base = 'libraries/AP_HAL_ESP32/hwdef'
686+ if os .path .exists (hwdef_base ):
687+ dirname , dirlist , filenames = next (os .walk (hwdef_base ))
688+ for d in dirlist :
689+ if d in _board_classes .keys () or d == 'scripts' :
690+ continue
691+ hwdef_path = os .path .join (dirname , d , 'hwdef.dat' )
692+ if os .path .exists (hwdef_path ):
693+ mcu_esp32s3 = True if (d [0 :7 ] == "esp32s3" ) else False
694+ type (d , (esp32s3 if mcu_esp32s3 else esp32 ,), {'name' : d , 'hwdef' : hwdef_path })
695+
696+ # Check for legacy headers in boards directory
697+ legacy_base = 'libraries/AP_HAL_ESP32/boards'
698+ if os .path .exists (legacy_base ):
699+ dirname , dirlist , filenames = next (os .walk (legacy_base ))
700+ for f in filenames :
701+ if f .endswith ('.h' ):
702+ board_name = f [:- 2 ]
703+ if board_name not in _board_classes :
704+ mcu_esp32s3 = True if (board_name [0 :7 ] == "esp32s3" ) else False
705+ type (board_name , (esp32s3 if mcu_esp32s3 else esp32 ,), {'name' : board_name })
696706
697707def get_boards_names ():
698708 add_dynamic_boards_chibios ()
@@ -995,13 +1005,44 @@ class esp32(Board):
9951005 abstract = True
9961006 toolchain = 'xtensa-esp32-elf'
9971007
1008+ def __init__ (self ):
1009+ super ().__init__ ()
1010+ self .with_can = True
1011+
9981012 def configure (self , cfg ):
1013+ # run hwdef to get MCU if this is an hwdef board
1014+ hwdef_dat = getattr (self , 'hwdef' , None )
1015+ if hwdef_dat :
1016+ sys .path .append (os .path .join (os .path .dirname (os .path .realpath (__file__ )), '../../libraries/AP_HAL_ESP32/hwdef/scripts' ))
1017+ import esp32_hwdef
1018+ if not os .path .exists (cfg .bldnode .abspath ()):
1019+ os .makedirs (cfg .bldnode .abspath ())
1020+ eh = esp32_hwdef .ESP32HWDef (
1021+ outdir = cfg .bldnode .abspath (),
1022+ hwdef = [hwdef_dat ],
1023+ quiet = True ,
1024+ )
1025+ eh .run ()
1026+ mcu = eh .mcu
1027+ cfg .env .MCU = mcu
1028+ cfg .env .append_value ('DEFINES' , 'HAL_ESP32_HWDEF_BUILD=1' )
1029+ else :
1030+ # Fallback for legacy boards
1031+ mcu = 'esp32s3' if 'esp32s3' in self .name else 'esp32'
1032+ cfg .env .MCU = mcu
1033+ cfg .env .append_value ('DEFINES' , 'HAL_ESP32_HWDEF_BUILD=0' )
1034+ cfg .env .append_value ('DEFINES' , f'HAL_BOARD_NAME_{ self .name .upper ()} =1' )
1035+
1036+ # Select toolchain based on MCU architecture (Xtensa vs RISC-V)
1037+ mcu_lower = mcu .lower ()
1038+ if mcu_lower in ['esp32c3' , 'esp32c6' , 'esp32h2' , 'esp32p4' ]:
1039+ self .toolchain = 'riscv32-esp-elf'
1040+ else :
1041+ self .toolchain = 'xtensa-%s-elf' % mcu_lower
1042+
9991043 super (esp32 , self ).configure (cfg )
10001044 if cfg .env .TOOLCHAIN :
10011045 self .toolchain = cfg .env .TOOLCHAIN
1002- else :
1003- # default tool-chain for esp32-based boards:
1004- self .toolchain = 'xtensa-esp32-elf'
10051046
10061047 def configure_env (self , cfg , env ):
10071048 env .BOARD_CLASS = "ESP32"
@@ -1057,13 +1098,33 @@ def expand_path(p):
10571098 '-fdata-sections' ,
10581099 '-fno-exceptions' ,
10591100 '-fno-rtti' ,
1060- '-nostdlib' ,
10611101 '-fstrict-volatile-bitfields' ,
10621102 '-Wno-sign-compare' ,
10631103 '-fno-inline-functions' ,
10641104 '-mlongcalls' ,
1065- '-fsingle-precision-constant' , # force const vals to be float , not double. so 100.0 means 100.0f
1105+ '-fsingle-precision-constant' , # force const vals to be float , not double. so 100.0 means 100.0f
10661106 '-fno-threadsafe-statics' ]
1107+ # Detect IDF version from the IDF_PATH set during configure()
1108+ idf_major = 5
1109+ idf_version_h = os .path .join (os .environ .get ('IDF_PATH' , '' ),
1110+ 'components/esp_common/include/esp_idf_version.h' )
1111+ if os .path .exists (idf_version_h ):
1112+ with open (idf_version_h , 'r' ) as f :
1113+ for line in f :
1114+ m = re .match (r'#define\s+ESP_IDF_VERSION_MAJOR\s+(\d+)' , line )
1115+ if m :
1116+ idf_major = int (m .group (1 ))
1117+ break
1118+ if idf_major >= 6 :
1119+ # IDF 6.0 uses PicoLibC which is incompatible with -nostdlib.
1120+ # The -specs=picolibc.specs flag is needed so the compiler finds
1121+ # PicoLibC headers. The cmath std:: namespace fix is handled in
1122+ # libraries/AP_Common/missing/cmath via ESP_PLATFORM guard.
1123+ env .CFLAGS += ['-specs=picolibc.specs' ]
1124+ env .CXXFLAGS += ['-specs=picolibc.specs' ]
1125+ else :
1126+ # IDF 5.x uses Newlib which works with -nostdlib
1127+ env .CXXFLAGS += ['-nostdlib' ]
10671128 env .CXXFLAGS .remove ('-Werror=undef' )
10681129 env .CXXFLAGS .remove ('-Werror=shadow' )
10691130
@@ -1079,6 +1140,29 @@ def expand_path(p):
10791140 HAL_PARAM_DEFAULTS_PATH = '"@ROMFS/defaults.parm"' ,
10801141 )
10811142
1143+ # Use generated board headers instead of static ones
1144+ env .INCLUDES += [
1145+ cfg .bldnode .find_or_declare ('boards' ).abspath (),
1146+ ]
1147+
1148+ # Include hwdef.h in compilation for ESP32 builds
1149+ hwdef_h = cfg .bldnode .find_or_declare ('hwdef.h' ).abspath ()
1150+ env .CFLAGS += ['-include' , hwdef_h ]
1151+ env .CXXFLAGS += ['-include' , hwdef_h ]
1152+
1153+ # Parse hwdef.dat for APA102 pins to set environment variables
1154+ hwdef_path = 'libraries/AP_HAL_ESP32/hwdef/%s/hwdef.dat' % self .get_name ()
1155+ if os .path .exists (hwdef_path ):
1156+ with open (hwdef_path , 'r' ) as f :
1157+ for line in f :
1158+ line = line .strip ()
1159+ if line .startswith ('APA102_DATA_PIN=' ):
1160+ pin_num = line .split ('=' )[1 ]
1161+ env .APA102_DATA = pin_num
1162+ elif line .startswith ('APA102_CLOCK_PIN=' ):
1163+ pin_num = line .split ('=' )[1 ]
1164+ env .APA102_CLOCK = pin_num
1165+
10821166 env .AP_PROGRAM_AS_STLIB = True
10831167 #if cfg.options.enable_profile:
10841168 # env.CXXFLAGS += ['-pg',
0 commit comments