common.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. # WizIO 2022 Georgi Angelov
  2. # http://www.wizio.eu/
  3. # https://github.com/Wiz-IO/wizio-pico
  4. from distutils.log import error
  5. import os
  6. from os.path import join
  7. from shutil import copyfile
  8. from colorama import Fore
  9. from pico import *
  10. from uf2conv import dev_uploader
  11. from SCons.Script import Builder
  12. bynary_type_info = []
  13. def do_copy(src, dst, name):
  14. file_name = join(dst, name)
  15. if False == os.path.isfile( file_name ):
  16. copyfile( join(src, name), file_name )
  17. return file_name
  18. def do_mkdir(path, name):
  19. dir = join(path, name)
  20. if False == os.path.isdir( dir ):
  21. try:
  22. os.mkdir(dir)
  23. except OSError:
  24. print ("[ERROR] Creation of the directory %s failed" % dir)
  25. exit(1)
  26. return dir
  27. def ini_file(env): # add defaut keys
  28. ini = join( env.subst("$PROJECT_DIR"), 'platformio.ini' )
  29. f = open(ini, "r")
  30. txt = f.read()
  31. f.close()
  32. f = open(ini, "a+")
  33. if 'monitor_port' not in txt: f.write("\n;monitor_port = SELECT SERIAL PORT\n")
  34. if 'monitor_speed' not in txt: f.write(";monitor_speed = 115200\n")
  35. if 'lib_deps' not in txt: f.write("\n;lib_deps = \n")
  36. if True == env.wifi:
  37. if 'build_flags' not in txt: f.write("\n;build_flags = \n")
  38. else:
  39. if 'build_flags' not in txt: f.write("\nbuild_flags = -D PICO_CYW43_ARCH_POLL ; select wifi driver mode\n")
  40. f.close()
  41. def dev_create_template(env):
  42. ini_file(env)
  43. src = join(env.PioPlatform().get_package_dir("framework-wizio-pico"), "templates")
  44. dst = do_mkdir( env.subst("$PROJECT_DIR"), "include" )
  45. do_copy(src, dst, "tusb_config.h")
  46. if "freertos" in env.GetProjectOption("lib_deps", []) or "USE_FREERTOS" in env.get("CPPDEFINES"):
  47. do_copy(src, dst, "FreeRTOSConfig.h")
  48. if "VFS" in env.GetProjectOption("lib_deps", []) or "USE_VFS" in env.get("CPPDEFINES"):
  49. do_copy(src, dst, "vfs_config.h")
  50. if 'APPLICATION'== env.get("PROGNAME"):
  51. if "fatfs" in env.GetProjectOption("lib_deps", []):
  52. do_copy(src, dst, "ffconf.h")
  53. dst = do_mkdir( env.subst("$PROJECT_DIR"), join("include", "pico") )
  54. autogen_filename = join(dst, "config_autogen.h")
  55. if False == os.path.isfile( autogen_filename ):
  56. default_board = "pico.h"
  57. autogen_board = env.BoardConfig().get("build.autogen_board", default_board )
  58. f = open(autogen_filename, "w")
  59. f.write("/* SELECT OTHER BOARD */\n")
  60. f.write('#include "boards/{}"\n'.format(autogen_board))
  61. f.close()
  62. dst = join(env.subst("$PROJECT_DIR"), "src")
  63. if False == os.path.isfile( join(dst, "main.cpp") ):
  64. do_copy(src, dst, "main.c" )
  65. if 'BOOT-2'== env.get("PROGNAME"):
  66. dst = do_mkdir( env.subst("$PROJECT_DIR"), join("include", "pico") )
  67. do_copy(src, dst, "config_autogen.h" )
  68. def dev_nano(env):
  69. enable_nano = env.BoardConfig().get("build.nano", "enable") # no <sys/lock>
  70. nano = []
  71. if enable_nano == "enable":
  72. nano = ["-specs=nano.specs", "-u", "_printf_float", "-u", "_scanf_float" ]
  73. if len(nano) > 0: print(' * SPECS :', nano[0][7:])
  74. else: print(' * SPECS : default')
  75. return nano
  76. def dev_compiler(env, application_name = 'APPLICATION'):
  77. env["FRAMEWORK_DIR"] = env.framework_dir
  78. env.sdk = env.BoardConfig().get("build.sdk", "SDK") # get/set default SDK
  79. env.variant = env.BoardConfig().get("build.variant", 'raspberry-pi-pico')
  80. env.wifi = env.BoardConfig().get("build.WIFI", False )
  81. print()
  82. print( Fore.BLUE + "%s RASPBERRYPI PI PICO RP2040 ( PICO - %s )" % (env.platform.upper(), env.sdk.upper()) )
  83. env.Replace(
  84. BUILD_DIR = env.subst("$BUILD_DIR").replace("\\", "/"),
  85. AR="arm-none-eabi-ar",
  86. AS="arm-none-eabi-as",
  87. CC="arm-none-eabi-gcc",
  88. GDB="arm-none-eabi-gdb",
  89. CXX="arm-none-eabi-g++",
  90. OBJCOPY="arm-none-eabi-objcopy",
  91. RANLIB="arm-none-eabi-ranlib",
  92. SIZETOOL="arm-none-eabi-size",
  93. ARFLAGS=["rc"],
  94. SIZEPROGREGEXP=r"^(?:\.text|\.data|\.boot2|\.rodata)\s+(\d+).*",
  95. SIZEDATAREGEXP=r"^(?:\.data|\.bss|\.ram_vector_table)\s+(\d+).*",
  96. SIZECHECKCMD="$SIZETOOL -A -d $SOURCES",
  97. SIZEPRINTCMD='$SIZETOOL --mcu=$BOARD_MCU -C -d $SOURCES',
  98. PROGSUFFIX=".elf",
  99. PROGNAME = application_name
  100. )
  101. cortex = ["-march=armv6-m", "-mcpu=cortex-m0plus", "-mthumb"]
  102. env.heap_size = env.BoardConfig().get("build.heap", "2048")
  103. optimization = env.BoardConfig().get("build.optimization", "-Os")
  104. stack_size = env.BoardConfig().get("build.stack", "2048")
  105. print(' * OPTIMIZATION :', optimization)
  106. if 'ARDUINO' == env.get("PROGNAME"):
  107. if "freertos" in env.GetProjectOption("lib_deps", []) or "USE_FREERTOS" in env.get("CPPDEFINES"):
  108. pass
  109. else:
  110. print(' * STACK :', stack_size)
  111. print(' * HEAP : maximum')
  112. else:
  113. print(' * STACK :', stack_size)
  114. print(' * HEAP :', env.heap_size)
  115. #fix_old_new_stdio(env)
  116. env.Append(
  117. ASFLAGS=[ cortex, "-x", "assembler-with-cpp" ],
  118. CPPPATH = [
  119. join("$PROJECT_DIR", "src"),
  120. join("$PROJECT_DIR", "lib"),
  121. join("$PROJECT_DIR", "include"),
  122. join( env.framework_dir, "wizio", "pico"),
  123. join( env.framework_dir, "wizio", "newlib"),
  124. join( env.framework_dir, env.sdk, "include"),
  125. join( env.framework_dir, env.sdk, "cmsis", "include"), #
  126. ],
  127. CPPDEFINES = [
  128. "NDEBUG",
  129. "PICO_ON_DEVICE=1",
  130. "PICO_HEAP_SIZE=" + env.heap_size,
  131. "PICO_STACK_SIZE=" + stack_size,
  132. ],
  133. CCFLAGS = [
  134. cortex,
  135. optimization,
  136. "-fdata-sections",
  137. "-ffunction-sections",
  138. "-Wall",
  139. "-Wextra",
  140. "-Wfatal-errors",
  141. "-Wno-sign-compare",
  142. "-Wno-type-limits",
  143. "-Wno-unused-parameter",
  144. "-Wno-unused-function",
  145. "-Wno-unused-but-set-variable",
  146. "-Wno-unused-variable",
  147. "-Wno-unused-value",
  148. "-Wno-strict-aliasing",
  149. "-Wno-maybe-uninitialized"
  150. ],
  151. CFLAGS = [
  152. cortex,
  153. "-Wno-discarded-qualifiers",
  154. "-Wno-ignored-qualifiers",
  155. "-Wno-attributes", #
  156. ],
  157. CXXFLAGS = [
  158. "-fno-rtti",
  159. "-fno-exceptions",
  160. "-fno-threadsafe-statics",
  161. "-fno-non-call-exceptions",
  162. "-fno-use-cxa-atexit",
  163. ],
  164. LINKFLAGS = [
  165. cortex,
  166. optimization,
  167. "-nostartfiles",
  168. "-Xlinker", "--gc-sections",
  169. "-Wl,--gc-sections",
  170. "--entry=_entry_point",
  171. dev_nano(env)
  172. ],
  173. LIBSOURCE_DIRS = [ join(env.framework_dir, "library"), ],
  174. LIBPATH = [ join(env.framework_dir, "library"), join("$PROJECT_DIR", "lib") ],
  175. LIBS = ['m', 'gcc'],
  176. BUILDERS = dict(
  177. ElfToBin = Builder(
  178. action = env.VerboseAction(" ".join([
  179. "$OBJCOPY", "-O", "binary",
  180. "$SOURCES", "$TARGET",
  181. ]), "Building $TARGET"),
  182. suffix = ".bin"
  183. )
  184. ),
  185. UPLOADCMD = dev_uploader
  186. )
  187. if False == env.wifi:
  188. env.Append( CPPDEFINES = [ "PICO_WIFI" ] )
  189. def add_libraries(env): # is PIO LIB-s
  190. if "freertos" in env.GetProjectOption("lib_deps", []) or "USE_FREERTOS" in env.get("CPPDEFINES"):
  191. env.Append( CPPPATH = [ join( env.framework_dir, "library", "freertos", "include" ), ] )
  192. print(' * RTOS : FreeRTOS')
  193. if "USE_FREERTOS" not in env.get("CPPDEFINES"):
  194. env.Append( CPPDEFINES = [ "USE_FREERTOS"] )
  195. if "cmsis-dap" in env.GetProjectOption("lib_deps", []):
  196. env.Append( CPPDEFINES = [ "DAP" ], )
  197. def add_boot(env):
  198. boot = env.BoardConfig().get("build.boot", "w25q080") # get boot
  199. if "w25q080" != boot and "$PROJECT_DIR" in boot:
  200. boot = boot.replace('$PROJECT_DIR', env["PROJECT_DIR"]).replace("\\", "/")
  201. bynary_type_info.append(boot)
  202. env.BuildSources( join("$BUILD_DIR", env.platform, "wizio", "boot"), join(env.framework_dir, "boot", boot) )
  203. def add_bynary_type(env):
  204. add_boot(env)
  205. bynary_type = env.BoardConfig().get("build.bynary_type", 'default')
  206. env.address = env.BoardConfig().get("build.address", "empty")
  207. linker = env.BoardConfig().get("build.linker", "empty")
  208. if "empty" != linker and "$PROJECT_DIR" in linker:
  209. linker = linker.replace('$PROJECT_DIR', env["PROJECT_DIR"]).replace("\\", "/")
  210. if 'copy_to_ram' == bynary_type:
  211. if "empty" == env.address: env.address = '0x10000000'
  212. if "empty" == linker: linker = 'memmap_copy_to_ram.ld'
  213. env.Append( CPPDEFINES = ['PICO_COPY_TO_RAM'] )
  214. elif 'no_flash' == bynary_type:
  215. if "empty" == env.address: env.address = '0x20000000'
  216. if "empty" == linker: linker = 'memmap_no_flash.ld'
  217. env.Append( CPPDEFINES = ['PICO_NO_FLASH'] )
  218. elif 'blocked_ram' == bynary_type:
  219. print('TODO: blocked_ram is not supported yet')
  220. exit(0)
  221. if "empty" == env.address: env.address = ''
  222. if "empty" == linker: linker = ''
  223. env.Append( CPPDEFINES = ['PICO_USE_BLOCKED_RAM'] )
  224. else: #default
  225. if "empty" == env.address: env.address = '0x10000000'
  226. if "empty" == linker: linker = 'memmap_default.ld'
  227. env.Append( LDSCRIPT_PATH = join(env.framework_dir, env.sdk, "pico", "pico_standard_link", linker) )
  228. bynary_type_info.append(linker)
  229. bynary_type_info.append(env.address)
  230. print(' * BINARY TYPE :' , bynary_type, bynary_type_info )
  231. add_libraries(env)
  232. def dev_finalize(env):
  233. # WIZIO
  234. env.BuildSources( join("$BUILD_DIR", env.platform, "wizio"), join(env.framework_dir, "wizio") )
  235. # SDK
  236. add_bynary_type(env)
  237. add_sdk(env)
  238. env.Append(LIBS = env.libs)
  239. dev_add_modules(env)
  240. print()
  241. def dev_config_board(env):
  242. src = join(env.PioPlatform().get_package_dir("framework-wizio-pico"), "templates")
  243. dst = do_mkdir( env.subst("$PROJECT_DIR"), "include" )
  244. if False == env.wifi:
  245. print(" * WIFI : NO")
  246. return
  247. ### pico w board
  248. else:
  249. do_copy(src, dst, "lwipopts.h") # for user edit
  250. env.Append(
  251. CPPDEFINES = [ "PICO_W", 'CYW43_SPI_PIO', 'CYW43_USE_SPI' ],
  252. CPPPATH = [
  253. join( env.framework_dir, env.sdk, "lib", "lwip", "src", "include" ),
  254. join( env.framework_dir, env.sdk, "lib", "cyw43-driver", "src" ),
  255. join( env.framework_dir, env.sdk, "lib", "cyw43-driver", "firmware" ),
  256. ],
  257. )
  258. ### pico wifi support
  259. env.BuildSources(
  260. join( "$BUILD_DIR", "wifi", "pico" ),
  261. join(env.framework_dir, env.sdk),
  262. [ "-<*>", "+<pico/pico_cyw43_arch>", "+<pico/pico_lwip>", ]
  263. )
  264. ### wifi spi driver & firmware
  265. env.BuildSources(
  266. join( "$BUILD_DIR", "wifi" , "cyw43-driver" ),
  267. join( env.framework_dir, env.sdk, "lib", "cyw43-driver", "src" ),
  268. [ "+<*>", "-<cyw43_sdio.c>", ] # remove sdio driver
  269. )
  270. ### LWIP: for add other files, use PRE:SCRIPT.PY
  271. env.BuildSources(
  272. join( "$BUILD_DIR", env.platform, "lwip", "api" ),
  273. join( env.framework_dir, env.sdk, "lib", "lwip", "src", "api" ),
  274. )
  275. env.BuildSources(
  276. join( "$BUILD_DIR", env.platform, "lwip", "core" ),
  277. join( env.framework_dir, env.sdk, "lib", "lwip", "src", "core" ),
  278. [ "+<*>", "-<ipv6>", ] # remove ipv6
  279. )
  280. env.BuildSources(
  281. join( "$BUILD_DIR", env.platform, "lwip", "netif" ),
  282. join( env.framework_dir, env.sdk, "lib", "lwip", "src", "netif" ),
  283. [ "-<*>", "+<ethernet.c>", ]
  284. )
  285. ### wifi firmware object
  286. """
  287. BUILD_DIR = env.subst( "$BUILD_DIR" )
  288. do_mkdir( BUILD_DIR, "wifi" )
  289. do_mkdir( join( BUILD_DIR, "wifi" ), "firmware" )
  290. WIFI_FIRMWARE_DIR = join( BUILD_DIR, "wifi", "firmware" )
  291. WIFI_FIRMWARE_OBJ = join( WIFI_FIRMWARE_DIR, "wifi_firmware.o" )
  292. WIFI_FIRMWARE_BIN = join( env.framework_dir, env.sdk, "lib", "cyw43-driver", "firmware", "43439A0-7.95.49.00.combined" )
  293. old_name = WIFI_FIRMWARE_BIN
  294. old_name = '_binary_' + old_name.replace('\\', '_').replace('/', '_').replace('.', '_').replace(':', '_').replace('-', '_')
  295. cmd = [ "$OBJCOPY", "-I", "binary", "-O", "elf32-littlearm", "-B", "arm", "--readonly-text",
  296. "--rename-section", ".data=.big_const,contents,alloc,load,readonly,data",
  297. "--redefine-sym", old_name + "_start=fw_43439A0_7_95_49_00_start",
  298. "--redefine-sym", old_name + "_end=fw_43439A0_7_95_49_00_end",
  299. "--redefine-sym", old_name + "_size=fw_43439A0_7_95_49_00_size",
  300. WIFI_FIRMWARE_BIN, # SOURCE BIN
  301. WIFI_FIRMWARE_OBJ # TARGET OBJ
  302. ]
  303. env.AddPreAction(
  304. join( "$BUILD_DIR", "wifi" , "cyw43-driver", "cyw43_bus_pio_spi.o" ), # TRIGER
  305. env.VerboseAction(" ".join(cmd), "Compiling wifi/firmware/wifi_firmware.o")
  306. )
  307. print( " * WIFI : Compile Firmware Object" )
  308. env.Append( LINKFLAGS = [ WIFI_FIRMWARE_OBJ ] )
  309. return
  310. """
  311. ### use pre-compiled wifi_firmware.o
  312. print( " * WIFI : Firmware Object" )
  313. env.Append( LINKFLAGS = [ join( env.framework_dir, env.sdk, "lib", "cyw43-driver", "src", "wifi_firmware.o" ) ] )
  314. return
  315. ### use pre-compiled libwifi_firmware.a
  316. print( " * WIFI : Firmware Library" )
  317. env.Append( # AS LIB
  318. LIBPATH = [ join( env.framework_dir, env.sdk, "lib", "cyw43-driver", "src" ) ],
  319. LIBS = ['wifi_firmware']
  320. )
  321. # EXPERIMENTAL FEATURE: LOAD MODULES
  322. '''
  323. ### Add & Compile not compiled sources with main builder
  324. ###[INI] custom_modules =
  325. $PROJECT_DIR/modules/MODULE_SCRYPT.py = parameters if need
  326. $PROJECT_DIR/any_folder_with_py_scripts
  327. ### example: MODULE_VERNO.py
  328. from os.path import join
  329. def module_init(env, parameter=''): # if parameter: string separated by space
  330. name = "verno"
  331. print( " *", name.upper() ) # just info
  332. path = join( env.framework_dir, "sdk", "middleware", name)
  333. env.Append( CPPPATH = [ join( path, "inc" ) ] )
  334. env.BuildSources( join( "$BUILD_DIR", "modules", name ), join( path, "src" ) )
  335. '''
  336. from importlib.machinery import SourceFileLoader
  337. # private
  338. def dev_load_module(filename, params, env):
  339. name = 'module_' + str( abs(hash( filename )) )
  340. m = SourceFileLoader(name, filename).load_module()
  341. m.module_init( env, params )
  342. # public: call it at builder end
  343. def dev_add_modules(env):
  344. #lines = env.BoardConfig().get("build.modules", "0")
  345. lines = env.GetProjectOption("custom_modules", "0")
  346. if '0' != lines:
  347. print("Project Modules:")
  348. for line in lines.split("\n"):
  349. if line == '': continue
  350. ### Cleaning the INI line
  351. line = line.strip().replace("\r", "").replace("\t", "")
  352. delim = '=' # for parameters
  353. params = '' # from ini line
  354. if delim in line:
  355. params = line[ line.index( delim ) + 1 : ].strip() # remove delim and whitespaces
  356. params = " ".join( params.split() ) # remove double spaces, params are separated by a space
  357. line = line.partition( delim )[0].strip() # remove delim and whitespaces
  358. module_path = env.subst( line ).strip().replace("\\", "/")
  359. ### Loading
  360. if False == os.path.exists(module_path):
  361. print("[ERROR] MODULE PATH NOT EXIST: %s" % module_path)
  362. exit(0)
  363. if True == os.path.isdir( module_path ): # files in folder
  364. for root, dirs, files in os.walk( module_path ):
  365. files = [ f for f in files if f.endswith(".py") ] # filter py files
  366. for file in files:
  367. dev_load_module( join(root, file), params, env)
  368. else: # single file
  369. dev_load_module( module_path, params, env)