import os import sys from esptool.bin_image import ELFFile from esptool.targets import CHIP_DEFS def elf2image(target, source, env): e = ELFFile("rtthread.elf") print("Creating esp32c6 image...") image = CHIP_DEFS["esp32c6"].BOOTLOADER_IMAGE() image.entrypoint = e.entrypoint image.flash_mode = 2 # dio image.segments = e.sections image.flash_size_freq = image.ROM_LOADER.parse_flash_size_arg("8MB") image.flash_size_freq += image.ROM_LOADER.parse_flash_freq_arg("80m") image.elf_sha256 = e.sha256() image.elf_sha256_offset = 0xb0 before = len(image.segments) image.merge_adjacent_segments() if len(image.segments) != before: delta = before - len(image.segments) print("Merged %d ELF section%s" % (delta, "s" if delta > 1 else "")) image.verify() image.save("rtthread.bin") print("Successfully created esp32c6 image.") if os.getenv('RTT_ROOT'): RTT_ROOT = os.getenv('RTT_ROOT') else: RTT_ROOT = os.path.join(os.getcwd(), '..', '..', '..') sys.path = sys.path + [os.path.join(RTT_ROOT, 'tools')] import rtconfig from building import * TARGET = 'rtthread.' + rtconfig.TARGET_EXT SDK_ROOT = os.path.abspath('./') if os.path.exists(SDK_ROOT + '/libraries'): libraries_path_prefix = SDK_ROOT + '/libraries' else: libraries_path_prefix = os.path.dirname(SDK_ROOT) + '/libraries' SDK_LIB = libraries_path_prefix Export('SDK_LIB') DefaultEnvironment(tools=[]) env = Environment(tools = ['mingw'], AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS, CC = rtconfig.CC, CFLAGS = rtconfig.CFLAGS, CXX = rtconfig.CXX, CXXFLAGS = rtconfig.CXXFLAGS, AR = rtconfig.AR, ARFLAGS = '-rc', LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS) env.PrependENVPath('PATH', rtconfig.EXEC_PATH) env['ASCOM'] = env['ASPPCOM'] Export('RTT_ROOT') Export('rtconfig') C6_IDF_COMMIT = '4fa003074a73774369d38123749fe64b7b4acbd3' def _use_c6_idf_when_official_has_none(): """CI pkgs --update fetches RT-Thread-packages/esp-idf, which only sets CPPDEFINES for ESP32-C3. Swap in one reviewed C6 commit before the package SConscript runs. A tree that already has the C6 target is left as-is. The package may sit under this BSP's packages/ or under libraries/. The replacement is fetched by commit, not by the moving branch tip. """ import shutil import subprocess from env_package import find_package_path dest = os.path.abspath(find_package_path(SDK_ROOT, 'ESP-IDF-latest')) sc = os.path.join(dest, 'SConscript') if not os.path.isfile(sc): return with open(sc, 'r', encoding='utf-8', errors='replace') as f: text = f.read() if 'esp32c6' in text: return tmp = dest + '.c6' if os.path.isdir(tmp): shutil.rmtree(tmp) subprocess.check_call(['git', 'init', tmp]) subprocess.check_call([ 'git', '-C', tmp, 'remote', 'add', 'origin', 'https://github.com/cms19859230182-lang/esp-idf.git', ]) subprocess.check_call([ 'git', '-C', tmp, 'fetch', '--depth', '1', 'origin', C6_IDF_COMMIT, ]) subprocess.check_call(['git', '-C', tmp, 'checkout', '--detach', 'FETCH_HEAD']) head = subprocess.check_output( ['git', '-C', tmp, 'rev-parse', 'HEAD']).decode().strip() if head != C6_IDF_COMMIT: shutil.rmtree(tmp) raise RuntimeError('fetched esp-idf is %s, this BSP expects %s' % (head, C6_IDF_COMMIT)) subprocess.check_call([ 'git', '-C', tmp, 'submodule', 'update', '--init', '--depth', '1', 'components/mbedtls/mbedtls', 'components/heap/tlsf', ]) git_meta = os.path.join(tmp, '.git') if os.path.isdir(git_meta): shutil.rmtree(git_meta) shutil.rmtree(dest) os.rename(tmp, dest) _use_c6_idf_when_official_has_none() def _match_idf_spi_lock_stub_to_spi_config(): """components/esp_hw_support/port/esp32c6/spi_lock_stub.c defines spicommon_bus_using_iomux() and spi_bus_lock_get_by_id() as always-true/always-0, and the package's C6 block compiles it because its directory scan takes every .c under that port directory that is not in skip_name. It is there because the package does not build components/driver/spi_common.c for C6, and components/spi_flash/ esp_flash_spi_init.c needs those two names: with SPI off this BSP has the same hole, so the stub stays. idf_port/SConscript compiles spi_common.c itself once BSP_USING_SPI is selected, and spi_common.c:726 and :743 define the same two names -- the real ones, the second of which hands the master driver a bus lock instead of the stub's 0. Two strong definitions of both names in one image is a link error, so the scan has to skip the stub in that configuration only. The switch is written into the package's own SConscript because that scan lives nowhere else; packages/ is not in the repository, so this is redone on every build and on every re-fetch of the package, and it is written as bytes to keep the file's own line endings. """ import re from env_package import find_package_path with open(os.path.join(SDK_ROOT, 'rtconfig.h'), 'r', encoding='utf-8', errors='replace') as f: spi_selected = re.search(r'^[ \t]*#[ \t]*define[ \t]+BSP_USING_SPI[ \t]*$', f.read(), re.M) is not None sc = os.path.join(os.path.abspath( find_package_path(SDK_ROOT, 'ESP-IDF-latest')), 'SConscript') if not os.path.isfile(sc): return with open(sc, 'rb') as f: text = f.read() entry = b"\n 'spi_lock_stub'," have = entry in text if have == spi_selected: return if spi_selected: marker = b'skip_name = (' if marker not in text: # In ESP-IDF v6.1+, spi_lock_stub is no longer present; spi_common.c is built directly. return text = text.replace(marker, marker + entry, 1) else: text = text.replace(entry, b'', 1) with open(sc, 'wb') as f: f.write(text) _match_idf_spi_lock_stub_to_spi_config() objs = PrepareBuilding(env, RTT_ROOT, remove_components = ['libc']) objs.extend(SConscript(os.path.join(libraries_path_prefix, 'drivers', 'SConscript'), variant_dir='build/libraries/drivers', duplicate=0)) DoBuilding(TARGET, objs) env.AddPostAction(TARGET, elf2image)