Add LittleFS build support, move filesystem size parser code here
This commit is contained in:
		
							
								
								
									
										125
									
								
								builder/main.py
									
									
									
									
									
								
							
							
						
						
									
										125
									
								
								builder/main.py
									
									
									
									
									
								
							| @@ -16,6 +16,7 @@ import sys | |||||||
| from platform import system | from platform import system | ||||||
| from os import makedirs | from os import makedirs | ||||||
| from os.path import isdir, join | from os.path import isdir, join | ||||||
|  | import re | ||||||
|  |  | ||||||
| from platformio.util import get_serial_ports | from platformio.util import get_serial_ports | ||||||
|  |  | ||||||
| @@ -67,6 +68,9 @@ env.Replace( | |||||||
|  |  | ||||||
|     ARFLAGS=["rc"], |     ARFLAGS=["rc"], | ||||||
|  |  | ||||||
|  |     MKFSTOOL="mklittlefs", | ||||||
|  |     PICO_FS_IMAGE_NAME=env.get("PICO_FS_IMAGE_NAME", "littlefs"), | ||||||
|  |  | ||||||
|     SIZEPROGREGEXP=r"^(?:\.text|\.data|\.rodata|\.text.align|\.ARM.exidx)\s+(\d+).*", |     SIZEPROGREGEXP=r"^(?:\.text|\.data|\.rodata|\.text.align|\.ARM.exidx)\s+(\d+).*", | ||||||
|     SIZEDATAREGEXP=r"^(?:\.data|\.bss|\.noinit)\s+(\d+).*", |     SIZEDATAREGEXP=r"^(?:\.data|\.bss|\.noinit)\s+(\d+).*", | ||||||
|     SIZECHECKCMD="$SIZETOOL -A -d $SOURCES", |     SIZECHECKCMD="$SIZETOOL -A -d $SOURCES", | ||||||
| @@ -109,6 +113,100 @@ env.Append( | |||||||
| if not env.get("PIOFRAMEWORK"): | if not env.get("PIOFRAMEWORK"): | ||||||
|     env.SConscript("frameworks/_bare.py") |     env.SConscript("frameworks/_bare.py") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def convert_size_expression_to_int(expression): | ||||||
|  |     conversion_factors = { | ||||||
|  |         "M": 1024*1024, | ||||||
|  |         "MB": 1024*1024, | ||||||
|  |         "K": 1024, | ||||||
|  |         "KB": 1024, | ||||||
|  |         "B": 1, | ||||||
|  |         "": 1 # giving no conversion factor is factor 1. | ||||||
|  |     } | ||||||
|  |     # match <floating pointer number><conversion factor>. | ||||||
|  |     extract_regex = r'^((?:[0-9]*[.])?[0-9]+)([mkbMKB]*)$' | ||||||
|  |     res = re.findall(extract_regex, expression) | ||||||
|  |     # unparsable expression? Warning. | ||||||
|  |     if len(res) == 0: | ||||||
|  |         sys.stderr.write( | ||||||
|  |             "Error: Could not parse filesystem size expression '%s'." | ||||||
|  |             " Will treat as size = 0.\n" % str(expression)) | ||||||
|  |         return 0 | ||||||
|  |     # access first result | ||||||
|  |     number, factor = res[0] | ||||||
|  |     number = float(number) | ||||||
|  |     number *= conversion_factors[factor.upper()] | ||||||
|  |     return int(number) | ||||||
|  |  | ||||||
|  | def fetch_fs_size(env): | ||||||
|  |     # follow generation formulas from makeboards.py for Earle Philhower core | ||||||
|  |     # given the total flash size, a user can specify | ||||||
|  |     # the amount for the filesystem (0MB, 2MB, 4MB, 8MB, 16MB) | ||||||
|  |     # via board_build.filesystem_size, | ||||||
|  |     # and we will calculate the flash size and eeprom size from that. | ||||||
|  |     flash_size = board.get("upload.maximum_size") | ||||||
|  |     filesystem_size = board.get("build.filesystem_size", "0MB") | ||||||
|  |     filesystem_size_int = convert_size_expression_to_int(filesystem_size) | ||||||
|  |  | ||||||
|  |     maximum_size = flash_size - 4096 - filesystem_size_int | ||||||
|  |  | ||||||
|  |     print("Flash size: %.2fMB" % (flash_size / 1024.0 / 1024.0)) | ||||||
|  |     print("Sketch size: %.2fMB" % (maximum_size / 1024.0 / 1024.0)) | ||||||
|  |     print("Filesystem size: %.2fMB" % (filesystem_size_int / 1024.0 / 1024.0)) | ||||||
|  |  | ||||||
|  |     flash_length = maximum_size | ||||||
|  |     eeprom_start = 0x10000000 + flash_size - 4096 | ||||||
|  |     fs_start = 0x10000000 + flash_size - 4096 - filesystem_size_int | ||||||
|  |     fs_end = 0x10000000 + flash_size - 4096 | ||||||
|  |  | ||||||
|  |     if maximum_size <= 0: | ||||||
|  |         sys.stderr.write( | ||||||
|  |             "Error: Filesystem too large for given flash. " | ||||||
|  |             "Can at max be flash size - 4096 bytes. " | ||||||
|  |             "Available sketch size with current " | ||||||
|  |             "config would be %d bytes.\n" % maximum_size) | ||||||
|  |         sys.stderr.flush() | ||||||
|  |         env.Exit(-1) | ||||||
|  |  | ||||||
|  |     env["PICO_FLASH_LENGTH"] = flash_length | ||||||
|  |     env["PICO_EEPROM_START"] = eeprom_start | ||||||
|  |     env["FS_START"] = fs_start | ||||||
|  |     env["FS_END"] = fs_end | ||||||
|  |     # LittleFS configuration paramters taken from | ||||||
|  |     # https://github.com/earlephilhower/arduino-pico-littlefs-plugin/blob/master/src/PicoLittleFS.java | ||||||
|  |     env["FS_PAGE"] = 256 | ||||||
|  |     env["FS_BLOCK"] = 4096 | ||||||
|  |  | ||||||
|  |     print("Maximium size: %d Flash Length: %d " | ||||||
|  |         "EEPROM Start: %d Filesystem start %d " | ||||||
|  |         "Filesystem end %s" %  | ||||||
|  |         (maximum_size,flash_length, eeprom_start, fs_start, fs_end)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def __fetch_fs_size(target, source, env): | ||||||
|  |     fetch_fs_size(env) | ||||||
|  |     return (target, source) | ||||||
|  |  | ||||||
|  | env.Append( | ||||||
|  |     BUILDERS=dict( | ||||||
|  |         DataToBin=Builder( | ||||||
|  |             action=env.VerboseAction(" ".join([ | ||||||
|  |                 '"$MKFSTOOL"', | ||||||
|  |                 "-c", "$SOURCES", | ||||||
|  |                 "-p", "$FS_PAGE", | ||||||
|  |                 "-b", "$FS_BLOCK", | ||||||
|  |                 "-s", "${FS_END - FS_START}", | ||||||
|  |                 "$TARGET" | ||||||
|  |             ]), "Building file system image from '$SOURCES' directory to $TARGET"), | ||||||
|  |             emitter=__fetch_fs_size, | ||||||
|  |             source_factory=env.Dir, | ||||||
|  |             suffix=".bin" | ||||||
|  |         ) | ||||||
|  |     ) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | env["fetch_fs_size"] = fetch_fs_size | ||||||
|  |  | ||||||
| # | # | ||||||
| # Target: Build executable and linkable firmware | # Target: Build executable and linkable firmware | ||||||
| # | # | ||||||
| @@ -119,9 +217,15 @@ if "nobuild" in COMMAND_LINE_TARGETS: | |||||||
|     target_firm = join("$BUILD_DIR", "${PROGNAME}.bin") |     target_firm = join("$BUILD_DIR", "${PROGNAME}.bin") | ||||||
| else: | else: | ||||||
|     target_elf = env.BuildProgram() |     target_elf = env.BuildProgram() | ||||||
|     target_firm = env.ElfToBin(join("$BUILD_DIR", "${PROGNAME}"), target_elf) |     if set(["buildfs", "uploadfs"]) & set(COMMAND_LINE_TARGETS): | ||||||
|     env.Depends(target_firm, "checkprogsize") |         target_firm = env.DataToBin( | ||||||
|  |             join("$BUILD_DIR", "${PICO_FS_IMAGE_NAME}"), "$PROJECTDATA_DIR") | ||||||
|  |         AlwaysBuild(target_firm) | ||||||
|  |     else: | ||||||
|  |         target_firm = env.ElfToBin(join("$BUILD_DIR", "${PROGNAME}"), target_elf) | ||||||
|  |         env.Depends(target_firm, "checkprogsize") | ||||||
|  |  | ||||||
|  | env.AddPlatformTarget("buildfs", target_firm, target_firm, "Build Filesystem Image") | ||||||
| AlwaysBuild(env.Alias("nobuild", target_firm)) | AlwaysBuild(env.Alias("nobuild", target_firm)) | ||||||
| target_buildprog = env.Alias("buildprog", target_firm, target_firm) | target_buildprog = env.Alias("buildprog", target_firm, target_firm) | ||||||
|  |  | ||||||
| @@ -129,6 +233,21 @@ env.AddPostAction( | |||||||
|     target_elf, env.VerboseAction(generate_uf2, "Generating UF2 image") |     target_elf, env.VerboseAction(generate_uf2, "Generating UF2 image") | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | def _update_max_upload_size(env): | ||||||
|  |     fetch_fs_size(env) | ||||||
|  |     env.BoardConfig().update("upload.maximum_size", env["PICO_FLASH_LENGTH"]) | ||||||
|  |  | ||||||
|  | # update max upload size based on CSV file | ||||||
|  | if env.get("PIOMAINPROG"): | ||||||
|  |     env.AddPreAction( | ||||||
|  |         "checkprogsize", | ||||||
|  |         env.VerboseAction( | ||||||
|  |             lambda source, target, env: _update_max_upload_size(env), | ||||||
|  |             "Retrieving maximum program size $SOURCE")) | ||||||
|  | # remove after PIO Core 3.6 release | ||||||
|  | elif set(["checkprogsize", "upload"]) & set(COMMAND_LINE_TARGETS): | ||||||
|  |     _update_max_upload_size(env) | ||||||
|  |  | ||||||
| # | # | ||||||
| # Target: Print binary size | # Target: Print binary size | ||||||
| # | # | ||||||
| @@ -232,7 +351,7 @@ if not upload_actions: | |||||||
|     sys.stderr.write("Warning! Unknown upload protocol %s\n" % upload_protocol) |     sys.stderr.write("Warning! Unknown upload protocol %s\n" % upload_protocol) | ||||||
|  |  | ||||||
| AlwaysBuild(env.Alias("upload", upload_source, upload_actions)) | AlwaysBuild(env.Alias("upload", upload_source, upload_actions)) | ||||||
|  | env.AddPlatformTarget("uploadfs", target_firm, upload_actions, "Upload Filesystem Image") | ||||||
| # | # | ||||||
| # Default targets | # Default targets | ||||||
| # | # | ||||||
|   | |||||||
| @@ -65,6 +65,12 @@ | |||||||
|       "optional": true, |       "optional": true, | ||||||
|       "owner": "platformio", |       "owner": "platformio", | ||||||
|       "version": "~1.72000.0" |       "version": "~1.72000.0" | ||||||
|  |     }, | ||||||
|  |     "tool-mklittlefs": { | ||||||
|  |       "type": "uploader", | ||||||
|  |       "optional": true, | ||||||
|  |       "owner": "platformio", | ||||||
|  |       "version": "~1.203.0" | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -46,6 +46,10 @@ class RaspberrypiPlatform(PlatformBase): | |||||||
|                 sys.stderr.write( |                 sys.stderr.write( | ||||||
|                     "Error! Unknown build.core value '%s'. Don't know which Arduino core package to use." % build_core) |                     "Error! Unknown build.core value '%s'. Don't know which Arduino core package to use." % build_core) | ||||||
|  |  | ||||||
|  |         # if we want to build a filesystem, we need the tools. | ||||||
|  |         if "buildfs" in targets: | ||||||
|  |             self.packages['tool-mklittlefs']['optional'] = False | ||||||
|  |  | ||||||
|         # configure J-LINK tool |         # configure J-LINK tool | ||||||
|         jlink_conds = [ |         jlink_conds = [ | ||||||
|             "jlink" in variables.get(option, "") |             "jlink" in variables.get(option, "") | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user