wscript 60 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730
  1. import json
  2. import os
  3. import subprocess
  4. import sys
  5. import pexpect
  6. import zipfile
  7. import datetime
  8. import time
  9. import waflib
  10. from waflib import Node, Logs
  11. from waflib.Build import BuildContext
  12. waf_dir = sys.path[0]
  13. sys.path.append(os.path.join(waf_dir, 'tools'))
  14. sys.path.append(os.path.join(waf_dir, 'tools/log_hashing'))
  15. sys.path.append(os.path.join(waf_dir, 'sdk/tools/'))
  16. sys.path.append(os.path.join(waf_dir, 'waftools'))
  17. import waftools.asm
  18. import waftools.gitinfo
  19. import waftools.ldscript
  20. import waftools.openocd
  21. import waftools.xcode_pebble
  22. LOGHASH_OUT_PATH = 'src/fw/loghash_dict.json'
  23. def truncate(msg):
  24. if msg is None:
  25. return msg
  26. # Don't truncate exceptions thrown by waf itself
  27. if "Traceback " in msg:
  28. return msg
  29. truncate_length = 600
  30. if len(msg) > truncate_length:
  31. msg = msg[:truncate_length-4] + '...\n' + waflib.Logs.colors.NORMAL
  32. return msg
  33. def run_arm_gdb(ctx, elf_node, cmd_str="", target_server_port=3333):
  34. from tools.gdb_driver import find_gdb_path
  35. arm_none_eabi_path = find_gdb_path()
  36. if arm_none_eabi_path is None:
  37. ctx.fatal("pebble-gdb not found!")
  38. os.system('{} {} {} --ex="target remote :{}"'.format(
  39. arm_none_eabi_path, elf_node.path_from(ctx.path),
  40. cmd_str, target_server_port)
  41. )
  42. def options(opt):
  43. opt.load('pebble_arm_gcc', tooldir='waftools')
  44. opt.load('show_configure', tooldir='waftools')
  45. opt.recurse('applib-targets')
  46. opt.recurse('tests')
  47. opt.recurse('src/bluetooth-fw')
  48. opt.recurse('src/fw')
  49. opt.recurse('src/idl')
  50. opt.recurse('sdk')
  51. opt.add_option('--board', action='store',
  52. choices=[ 'bb2',
  53. 'ev2_4',
  54. 'v1_5',
  55. 'v2_0',
  56. 'snowy_bb2', # alias for snowy_dvt, but with #define IS_BIGBOARD
  57. 'snowy_evt2',
  58. 'snowy_dvt',
  59. 'snowy_s3',
  60. 'spalding_bb2', # snowy_bb2 with s4 display
  61. 'spalding_evt',
  62. 'spalding',
  63. 'silk_evt',
  64. 'silk_bb',
  65. 'silk',
  66. 'silk_bb2',
  67. 'cutts_bb',
  68. 'robert_bb',
  69. 'robert_bb2',
  70. 'robert_evt',
  71. 'robert_es',
  72. 'asterix',],
  73. help='Which board we are targeting '
  74. 'bb2, snowy_dvt, spalding, silk...')
  75. opt.add_option('--jtag', action='store', default=None, dest='jtag', # default is bb2 (below)
  76. choices=waftools.openocd.JTAG_OPTIONS.keys(),
  77. help='Which JTAG programmer we are using '
  78. '(bb2 (default), olimex, ev2, etc)')
  79. opt.add_option('--internal_sdk_build', action='store_true',
  80. help='Build the internal version of the SDK')
  81. opt.add_option('--future_ux', action='store_true',
  82. help='Build future UX features and APIs. Implies --internal_sdk_build.')
  83. opt.add_option('--nosleep', action='store_true',
  84. help='Disable sleep and stop mode (to use JTAG+GDB)')
  85. opt.add_option('--nostop', action='store_true',
  86. help='Disable stop mode (to use JTAG+GDB)')
  87. opt.add_option('--lowpowerdebug', action='store_true',
  88. help='Lowpowerdebug can be toggled from the CLI but is off by default. This just turns it on by default')
  89. opt.add_option('--nowatch', action='store_true',
  90. help='Disable the watchface idle timeout')
  91. opt.add_option('--nowatchdog', action='store_true',
  92. help='Disable automatic reboots when watchdog fires')
  93. opt.add_option('--test_apps', action='store_true',
  94. help='Enables test apps (off by default)')
  95. opt.add_option('--test_apps_list', type=str,
  96. help='Specify AppInstallId\'s of the test apps to be compiled with the firmware')
  97. opt.add_option('--performance_tests', action='store_true',
  98. help='Enables instrumentation + apps for performance testing (off by default)')
  99. opt.add_option('--verbose_logs', action='store_true',
  100. help='Enables verbose logs (off by default)')
  101. opt.add_option('--ui_debug', action='store_true',
  102. help='Enable window dump & layer nudge CLI cmd (off by default)')
  103. opt.add_option('--qemu', action='store_true',
  104. help='Build an image for qemu instead of a real board.')
  105. opt.add_option('--nojs', action='store_true', help='Removes js support from the current build.')
  106. opt.add_option('--sdkshell', action='store_true',
  107. help='Use the sdk shell instead of the normal shell')
  108. opt.add_option('--nolog', action='store_true',
  109. help='Disable PBL_LOG macros to save space')
  110. opt.add_option('--nohash', action='store_true',
  111. help='Disable log hashing and make the logs human readable')
  112. opt.add_option('--log-level', default='debug', choices=['error', 'warn', 'info', 'debug', 'debug_verbose'],
  113. help='Default global log level')
  114. opt.add_option('--lang',
  115. action='store',
  116. default='en_US',
  117. help='Which language to package (isocode)')
  118. opt.add_option('--compile_commands', action='store_true', help='Create a clang compile_commands.json')
  119. opt.add_option('--file', action='store', help='Specify a file to use with the flash_fw command')
  120. opt.add_option('--tty',
  121. help='Selects a tty to use for serial imaging. Must be specified for all image commands')
  122. opt.add_option('--baudrate', action='store', type=int, help='Optional: specifies the baudrate to run the targetted uart at')
  123. opt.add_option('--onlysdk', action='store_true', help="only build the sdk")
  124. opt.add_option('--qemu_host', default='localhost:12345',
  125. help='host:port for the emulator console connection')
  126. opt.add_option('--force-fit-tintin', action='store_true',
  127. help='Force fit for Tintin')
  128. opt.add_option('--no-link', action='store_true',
  129. help='Do not link the final firmware binary. This is used for static analysis')
  130. opt.add_option('--noprompt', action='store_true',
  131. help='Disable the serial console to save space')
  132. opt.add_option('--build_test_apps', action='store_true',
  133. help='Turns on building of test apps')
  134. opt.add_option('--bb_large_spi', action='store_true',
  135. help='Sets a flag to use all 8MB of BigBoard flash')
  136. opt.add_option('--profiler', action='store_true', help='Enable the profiler.')
  137. opt.add_option('--profile_interrupts', action='store_true',
  138. help='Enable profiling of all interrupts.')
  139. opt.add_option('--voice_debug', action='store_true',
  140. help='Enable all voice logging.')
  141. opt.add_option('--voice_codec_tests', action='store_true',
  142. help='Enable voice codec tests. Enables the profiler')
  143. opt.add_option('--battery_debug', action='store_true',
  144. help='Set the PMIC\'s max charging voltage to 4.3V.')
  145. opt.add_option('--no_sandbox', action='store_true',
  146. help='Disable the MPU for 3rd party apps.')
  147. opt.add_option('--malloc_instrumentation', action='store_true',
  148. help='Enables malloc instrumentation')
  149. opt.add_option('--infinite_backlight', action='store_true',
  150. help='Makes the backlight never time-out.')
  151. opt.add_option('--mfg', action='store_true', help='Enable specific MFG-only options in the PRF build')
  152. opt.add_option('--no-pulse-everywhere',
  153. action='store_true',
  154. help='Disables PULSE everywhere, uses legacy logs and prompt')
  155. opt.add_option('--bootloader-test', action='store', default='none',
  156. choices=['none', 'stage1', 'stage2'],
  157. help='Build bootloader test (stage1 or stage2). Implies --mfg.')
  158. opt.add_option('--reboot_on_bt_crash', action='store_true', help='Forces a BT '
  159. 'chip crash to immediately force a system reboot instead of just cycling airplane mode. '
  160. 'This makes it easier for us to actually get crash info')
  161. def handle_configure_options(conf):
  162. if conf.options.noprompt:
  163. conf.env.append_value('DEFINES', 'DISABLE_PROMPT')
  164. conf.env.DISABLE_PROMPT = True
  165. if conf.options.beta or conf.options.release:
  166. conf.env.append_value('DEFINES', 'RELEASE')
  167. if conf.options.malloc_instrumentation:
  168. conf.env.append_value('DEFINES', 'MALLOC_INSTRUMENTATION')
  169. print("Enabling malloc instrumentation")
  170. if conf.options.qemu:
  171. conf.env.append_value('DEFINES', 'TARGET_QEMU')
  172. if conf.options.test_apps_list:
  173. conf.options.test_apps = True
  174. conf.env.test_apps_list = conf.options.test_apps_list.split(",")
  175. print("Enabling test apps: " + str(conf.options.test_apps_list))
  176. if conf.options.build_test_apps or conf.options.test_apps:
  177. conf.env.BUILD_TEST_APPS = True
  178. if conf.options.performance_tests:
  179. conf.env.PERFORMANCE_TESTS = True
  180. if conf.options.voice_debug:
  181. conf.env.VOICE_DEBUG = True
  182. if conf.options.voice_codec_tests:
  183. conf.env.VOICE_CODEC_TESTS = True
  184. conf.env.append_value('DEFINES', 'VOICE_CODEC_TESTS')
  185. conf.options.profiler = True
  186. if conf.env.MICRO_FAMILY == 'STM32F4':
  187. if conf.options.lowpowerdebug and not conf.options.nosleep:
  188. Logs.warn('On snowy --lowpowerdebug can only be used with --nosleep. Forcing --nosleep on!\n'
  189. 'See PBL-10174.')
  190. conf.env.append_value('DEFINES', 'PBL_NOSLEEP')
  191. if 'bb' in conf.options.board:
  192. conf.env.append_value('DEFINES', 'IS_BIGBOARD')
  193. if conf.options.nosleep:
  194. conf.env.append_value('DEFINES', 'PBL_NOSLEEP')
  195. print("Sleep/stop mode disabled")
  196. if conf.options.nostop:
  197. conf.env.append_value('DEFINES', 'PBL_NOSTOP')
  198. print("Stop mode disabled")
  199. if conf.options.lowpowerdebug:
  200. conf.env.append_value('DEFINES', 'LOW_POWER_DEBUG')
  201. print("Sleep and Stop mode debugging enabled")
  202. if conf.options.nowatch:
  203. conf.env.append_value('DEFINES', 'NO_WATCH_TIMEOUT')
  204. print("Watch watchdog disabled")
  205. if conf.options.nowatchdog:
  206. conf.env.append_value('DEFINES', 'NO_WATCHDOG')
  207. conf.env.NO_WATCHDOG = True
  208. print("Watchdog reboot disabled")
  209. if conf.options.reboot_on_bt_crash:
  210. conf.env.append_value('DEFINES', 'REBOOT_ON_BT_CRASH=1')
  211. print("BT now crash will trigger an MCU reboot")
  212. if conf.options.test_apps:
  213. conf.env.append_value('DEFINES', 'ENABLE_TEST_APPS')
  214. print("Im in ur firmware, bloatin ur binz! (Test apps enabled)")
  215. if conf.options.performance_tests:
  216. conf.env.append_value('DEFINES', 'PERFORMANCE_TESTS')
  217. conf.options.profiler = True
  218. print("Instrumentation and apps for performance measurement enabled (enables profiler)")
  219. if conf.options.verbose_logs:
  220. conf.env.append_value('DEFINES', 'VERBOSE_LOGGING')
  221. print("Verbose logging enabled")
  222. print(f"Log level: {conf.options.log_level.upper()}")
  223. conf.env.append_value('DEFINES', f'DEFAULT_LOG_LEVEL=LOG_LEVEL_{conf.options.log_level.upper()}')
  224. if conf.options.ui_debug:
  225. conf.env.append_value('DEFINES', 'UI_DEBUG')
  226. if conf.options.no_sandbox or conf.options.qemu:
  227. print("Sandbox disabled")
  228. else:
  229. conf.env.append_value('DEFINES', 'APP_SANDBOX')
  230. if conf.options.bb_large_spi:
  231. conf.env.append_value('DEFINES', 'LARGE_SPI_FLASH')
  232. print("Enabling 8MB BigBoard flash")
  233. if not conf.options.nolog:
  234. conf.env.append_value('DEFINES', 'PBL_LOG_ENABLED')
  235. if not conf.options.nohash:
  236. conf.env.append_value('DEFINES', 'PBL_LOGS_HASHED')
  237. if conf.options.profile_interrupts:
  238. conf.env.append_value('DEFINES', 'PROFILE_INTERRUPTS')
  239. if not conf.options.profiler:
  240. # Can't profile interrupts without the profiler enabled
  241. print("Enabling profiler")
  242. conf.options.profiler = True
  243. if conf.options.profiler:
  244. conf.env.append_value('DEFINES', 'PROFILER')
  245. if not conf.options.nostop:
  246. print("Enable --nostop for accurate profiling.")
  247. conf.env.append_value('DEFINES', 'PBL_NOSTOP')
  248. if conf.options.voice_debug:
  249. conf.env.append_value('DEFINES', 'VOICE_DEBUG')
  250. if conf.options.battery_debug:
  251. conf.env.append_value('DEFINES', 'BATTERY_DEBUG')
  252. print("Enabling higher battery charge voltage.")
  253. if conf.options.future_ux and not conf.is_tintin():
  254. print("Future UX features enabled.")
  255. conf.env.FUTURE_UX = True
  256. conf.env.INTERNAL_SDK_BUILD = bool(conf.options.internal_sdk_build)
  257. if conf.env.INTERNAL_SDK_BUILD:
  258. print("Internal SDK enabled")
  259. if conf.options.force_fit_tintin:
  260. conf.env.append_value('DEFINES', 'TINTIN_FORCE_FIT')
  261. print("Functionality is secondary to usability")
  262. if (conf.is_snowy_compatible() and not conf.options.no_lto) or conf.options.lto:
  263. conf.options.lto = True
  264. print("Turning on LTO.")
  265. if conf.options.no_link:
  266. conf.env.NO_LINK = True
  267. print("Not linking firmware")
  268. if conf.options.infinite_backlight and 'bb' in conf.options.board:
  269. conf.env.append_value('DEFINES', 'INFINITE_BACKLIGHT')
  270. print("Enabling infinite backlight.")
  271. if conf.options.bootloader_test in ['stage1', 'stage2']:
  272. print("Forcing MFG on for bootloader test build.")
  273. conf.options.mfg = True
  274. if conf.options.bootloader_test == 'stage1':
  275. conf.env.append_value('DEFINES', 'BOOTLOADER_TEST_STAGE1=1')
  276. conf.env.append_value('DEFINES', 'BOOTLOADER_TEST_STAGE2=0')
  277. elif conf.options.bootloader_test == 'stage2':
  278. conf.env.append_value('DEFINES', 'BOOTLOADER_TEST_STAGE1=0')
  279. conf.env.append_value('DEFINES', 'BOOTLOADER_TEST_STAGE2=1')
  280. else:
  281. conf.env.append_value('DEFINES', 'BOOTLOADER_TEST_STAGE1=0')
  282. conf.env.append_value('DEFINES', 'BOOTLOADER_TEST_STAGE2=0')
  283. if not conf.options.no_pulse_everywhere:
  284. conf.env.append_value('DEFINES', 'PULSE_EVERYWHERE=1')
  285. def _create_cm0_env(conf):
  286. prev_env = conf.env
  287. prev_variant = conf.variant
  288. # Create a new Cortex M0 environment that's used to build for the DA14681:
  289. conf.setenv('cortex-m0')
  290. # Copy the defines fron the stock env into our m0 env
  291. conf.env.append_unique('DEFINES', prev_env.DEFINES)
  292. Logs.pprint('CYAN', 'Configuring ARM cortex-m0 environment')
  293. conf.env.append_unique('DEFINES', 'ARCH_NO_NATIVE_LONG_DIVIDE')
  294. CPU_FLAGS = ['-mcpu=cortex-m0', '-mthumb']
  295. OPT_FLAGS = [
  296. '-fvar-tracking-assignments', # Track variable locations better
  297. '-fmessage-length=0', '-fsigned-char',
  298. '-fbuiltin',
  299. '-fno-builtin-itoa',
  300. '-ffreestanding',
  301. '-Os',
  302. ]
  303. if not conf.options.no_debug:
  304. OPT_FLAGS += [
  305. '-g3',
  306. '-gdwarf-4', # More detailed debug info
  307. ]
  308. C_FLAGS = ['-std=c11', '-ffunction-sections',
  309. '-Wall', '-Wextra', '-Werror', '-Wpointer-arith',
  310. '-Wno-unused-parameter', '-Wno-missing-field-initializers',
  311. '-Wno-error=unused-parameter',
  312. '-Wno-error=unused-const-variable',
  313. '-Wno-packed-bitfield-compat',
  314. '-Wno-address-of-packed-member',
  315. '-Wno-expansion-to-defined',
  316. '-Wno-enum-int-mismatch',
  317. '-Wno-enum-conversion']
  318. conf.find_program('arm-none-eabi-gcc', var='CC', mandatory=True)
  319. conf.env.AS = conf.env.CC
  320. for tool in ['ar', 'objcopy']:
  321. conf.find_program('arm-none-eabi-' + tool, var=tool.upper(),
  322. mandatory=True)
  323. conf.env.append_unique('CFLAGS', CPU_FLAGS + OPT_FLAGS + C_FLAGS)
  324. ASFLAGS = ['-x', 'assembler-with-cpp']
  325. conf.env.append_unique('ASFLAGS', ASFLAGS + CPU_FLAGS + OPT_FLAGS)
  326. conf.env.append_unique('LINKFLAGS',
  327. ['-Wl,--cref',
  328. '-Wl,--gc-sections',
  329. '-nostdlib',
  330. ] + CPU_FLAGS + OPT_FLAGS)
  331. conf.load('gcc gas objcopy ldscript')
  332. conf.load('file_name_c_define')
  333. conf.variant = prev_variant
  334. conf.env = prev_env
  335. def configure(conf):
  336. if not conf.options.board:
  337. conf.fatal('No board selected! '
  338. 'You must pass a --board argument when configuring.')
  339. # Has to be 'waftools.gettext' as unadorned 'gettext' will find the gettext
  340. # module in the standard library.
  341. conf.load('waftools.gettext')
  342. conf.recurse('platform')
  343. conf.env.QEMU = conf.options.qemu
  344. conf.env.NOJS = conf.options.nojs
  345. # The BT controller is the only thing different between robert_es and robert_evt, so just
  346. # retend robert_es is robert_evt. We'll be removing robert_es fairly soon anyways.
  347. bt_board = None
  348. if conf.options.board == 'robert_es':
  349. bt_board = 'robert_es'
  350. conf.options.board = 'robert_evt'
  351. if conf.options.jtag:
  352. conf.env.JTAG = conf.options.jtag
  353. elif conf.options.board in ('snowy_bb2', 'spalding_bb2'):
  354. conf.env.JTAG = 'jtag_ftdi'
  355. elif conf.options.board in ('cutts_bb', 'robert_bb', 'robert_bb2', 'robert_evt',
  356. 'silk_evt', 'silk_bb', 'silk_bb2', 'silk'):
  357. conf.env.JTAG = 'swd_ftdi'
  358. elif conf.options.board in ('asterix'):
  359. conf.env.JTAG = 'swd_cmsisdap'
  360. else:
  361. # default to bb2
  362. conf.env.JTAG = 'bb2'
  363. # Cutts and Robert access flash through the ITCM bus (except in QEMU)
  364. if (conf.is_cutts() or conf.is_robert()) and not conf.env.QEMU:
  365. conf.env.FLASH_ITCM = True
  366. else:
  367. conf.env.FLASH_ITCM = False
  368. # Set platform used for building the SDK
  369. if conf.is_tintin():
  370. conf.env.PLATFORM_NAME = 'aplite'
  371. conf.env.MIN_SDK_VERSION = 2
  372. elif conf.is_spalding():
  373. conf.env.PLATFORM_NAME = 'chalk'
  374. conf.env.MIN_SDK_VERSION = 3
  375. elif conf.is_snowy_compatible():
  376. conf.env.PLATFORM_NAME = 'basalt'
  377. conf.env.MIN_SDK_VERSION = 2
  378. elif conf.is_silk() or conf.is_asterix():
  379. conf.env.PLATFORM_NAME = 'diorite'
  380. conf.env.MIN_SDK_VERSION = 2
  381. elif conf.is_cutts() or conf.is_robert():
  382. conf.env.PLATFORM_NAME = 'emery'
  383. conf.env.MIN_SDK_VERSION = 3
  384. else:
  385. conf.fatal('No platform specified for {}!'.format(conf.options.board))
  386. # Save this for later
  387. conf.env.BOARD = conf.options.board
  388. if conf.is_tintin():
  389. conf.env.MICRO_FAMILY = 'STM32F2'
  390. elif conf.is_snowy_compatible() or conf.is_silk():
  391. conf.env.MICRO_FAMILY = 'STM32F4'
  392. elif conf.is_cutts() or conf.is_robert():
  393. conf.env.MICRO_FAMILY = 'STM32F7'
  394. elif conf.is_asterix():
  395. conf.env.MICRO_FAMILY = 'NRF52840'
  396. else:
  397. conf.fatal('No micro family specified for {}!'.format(conf.options.board))
  398. if conf.options.mfg:
  399. # Note that for the most part PRF and MFG firmwares are the same, so for MFG PRF builds
  400. # both MANUFACTURING_FW and RECOVERY_FW will be defined.
  401. conf.env.IS_MFG = True
  402. conf.env.append_value('DEFINES', ['MANUFACTURING_FW'])
  403. conf.find_program('node nodejs', var='NODE',
  404. errmsg="Unable to locate the Node command. "
  405. "Please check your Node installation and try again.")
  406. conf.recurse('third_party')
  407. conf.recurse('src/idl')
  408. conf.recurse('src/fw')
  409. conf.recurse('sdk')
  410. conf.recurse('bin/boot')
  411. waftools.openocd.write_cfg(conf)
  412. # Save a baseline environment that we'll use for unit tests
  413. # Detach so operations against conf.env don't affect unit_test_env
  414. unit_test_env = conf.env.derive()
  415. unit_test_env.detach()
  416. # Save a baseline environment that we'll use for ARM environments
  417. base_env = conf.env
  418. handle_configure_options(conf)
  419. # robert_es is the exact same as robert_evt, except for the BT chip, so gets converted to
  420. # robert_evt above, but we need to handle it as robert_es here.
  421. if bt_board is None:
  422. bt_board = conf.get_board()
  423. # Select BT controller based on configuration:
  424. if conf.env.QEMU:
  425. conf.env.bt_controller = 'qemu'
  426. conf.env.append_value('DEFINES', ['BT_CONTROLLER_QEMU'])
  427. elif conf.is_tintin() or conf.is_snowy() or conf.is_spalding():
  428. conf.env.bt_controller = 'cc2564x'
  429. conf.env.append_value('DEFINES', ['BT_CONTROLLER_CC2564X'])
  430. elif conf.is_asterix():
  431. conf.env.bt_controller = 'nrf52'
  432. conf.env.append_value('DEFINES', ['BT_CONTROLLER_NRF52'])
  433. elif bt_board in ('silk_bb2', 'silk', 'robert_bb2', 'robert_evt'):
  434. conf.env.bt_controller = 'da14681-01'
  435. conf.env.append_value('DEFINES', ['BT_CONTROLLER_DA14681'])
  436. else:
  437. conf.env.bt_controller = 'da14681-00'
  438. conf.env.append_value('DEFINES', ['BT_CONTROLLER_DA14681'])
  439. _create_cm0_env(conf)
  440. conf.recurse('src/bluetooth-fw')
  441. Logs.pprint('CYAN', 'Configuring arm_firmware environment')
  442. conf.setenv('', base_env)
  443. conf.load('pebble_arm_gcc', tooldir='waftools')
  444. conf.setenv('arm_prf_mode', env=conf.env)
  445. conf.env.append_value('DEFINES', ['RECOVERY_FW'])
  446. Logs.pprint('CYAN', 'Configuring unit test environment')
  447. conf.setenv('local', unit_test_env)
  448. # if sys.platform.startswith('linux'):
  449. # libclang_path = subprocess.check_output(['llvm-config', '--libdir']).strip()
  450. # conf.env.append_value('INCLUDES', [os.path.join(libclang_path, 'clang/3.2/include/'),])
  451. # The waf clang tool likes to use llvm-ar as it's ar tool, but that doesn't work on our build
  452. # servers. Fall back to boring old ar. This will populate the 'AR' env variable so future
  453. # searches for what value to put into env['AR'] will find this one.
  454. conf.find_program('ar')
  455. conf.load('clang')
  456. conf.load('pebble_test', tooldir='waftools')
  457. conf.env.CLAR_DIR = conf.path.make_node('tools/clar/').abspath()
  458. conf.env.CFLAGS = [ '-std=c11',
  459. '-Wall',
  460. '-Werror',
  461. '-Wno-error=unused-variable',
  462. '-Wno-error=unused-function',
  463. '-Wno-error=missing-braces',
  464. '-Wno-error=unused-const-variable',
  465. '-Wno-error=address-of-packed-member',
  466. '-Wno-enum-conversion',
  467. '-g3',
  468. '-gdwarf-4',
  469. '-O0',
  470. '-fdata-sections',
  471. '-ffunction-sections' ]
  472. conf.env.append_value('DEFINES', 'CLAR_FIXTURE_PATH="' +
  473. conf.path.make_node('tests/fixtures/').abspath() + '"')
  474. conf.env.append_value('DEFINES', 'PBL_LOG_ENABLED')
  475. if conf.options.compile_commands:
  476. conf.load('clang_compilation_database', tooldir='waftools')
  477. if not os.path.lexists('compile_commands.json'):
  478. filename = 'compile_commands.json'
  479. source = conf.path.get_bld().make_node(filename)
  480. os.symlink(source.path_from(conf.path), filename)
  481. prev_env = conf.env
  482. Logs.pprint('CYAN', 'Configuring 32 bit host environment')
  483. # Copy 'local' to serve as the basis for '32bit':
  484. env_32bit = conf.env.derive().detach()
  485. env_32bit.append_value('CFLAGS', '-m32')
  486. env_32bit.append_value('LINKFLAGS', '-m32')
  487. env_32bit.LINK_CC = 'gcc'
  488. conf.all_envs['32bit'] = env_32bit
  489. conf.set_env(prev_env)
  490. # Note: this will modify the 'local' conf when targeting emscripten:
  491. conf.recurse('applib-targets')
  492. Logs.pprint('CYAN', 'Configuring stored apps environment')
  493. conf.setenv('stored_apps', base_env)
  494. conf.recurse('stored_apps')
  495. # Confirm that requirements-*.txt and requirements-osx-brew.txt have been satisfied.
  496. import tool_check
  497. tool_check.tool_check()
  498. # Warn user not to use Cutts BB build with a Robert screen
  499. if conf.options.board == 'cutts_bb':
  500. Logs.warn('NOTE: Do not use this build with a C2/Robert display '
  501. '(6V6 rail will damage the display)')
  502. def _run_remote_suite(ctx, suite):
  503. # PEBBLESDK_TEST_ROOT must be defined in order to initiate integration tests
  504. try:
  505. pebblesdk_test_root = os.environ['PEBBLESDK_TEST_ROOT']
  506. except KeyError:
  507. waflib.Logs.pprint('RED', 'Error: environment variable $PEBBLESDK_TEST_ROOT must be defined')
  508. return
  509. # Check if firmware has been built
  510. # Assume we're looking for a "normal" PBZ, as recovery PBZs aren't supported by integration tests
  511. fw_bin_path = ctx.get_tintin_fw_node().abspath()
  512. fw_bin_exists = os.path.isfile(fw_bin_path)
  513. if not fw_bin_exists:
  514. waflib.Logs.pprint('RED', ('Error: BIN not found at expected location {}, '
  515. 'have you run `waf build` yet?'.format(fw_bin_path)))
  516. return
  517. # Check if firmware has been bundled
  518. version_string, version_ts, _ = _get_version_info(ctx)
  519. fw_type = 'qemu' if ctx.env.QEMU else 'normal'
  520. fw_pbz_path = ctx.get_pbz_node(fw_type, ctx.env.BOARD, version_string).abspath()
  521. fw_pbz_exists = os.path.isfile(fw_pbz_path)
  522. if not fw_pbz_exists:
  523. waflib.Logs.pprint('CYAN', ('Warning: PBZ not found at expected location {}, '
  524. 'running `waf bundle`...').format(fw_pbz_path))
  525. bundle(ctx)
  526. # Run power tests using remote_runner.py
  527. remote_runner_path = os.path.join(pebblesdk_test_root, 'remote_runner.py')
  528. if not os.path.isfile(remote_runner_path):
  529. waflib.Logs.pprint('RED', ('Error: remote_runner.py not found in {}. '
  530. 'Are you sure that PEBBLESDK_TEST_ROOT is defined correctly?'
  531. .format(pebblesdk_test_root)))
  532. return
  533. subprocess.call([remote_runner_path, '--pbz', fw_pbz_path, '[%s]' % suite])
  534. class power_test(BuildContext):
  535. cmd = 'power_test'
  536. def execute_build(ctx):
  537. _run_remote_suite(ctx, 'power')
  538. class integration_test(BuildContext):
  539. cmd = 'integration_test'
  540. def execute_build(ctx):
  541. _run_remote_suite(ctx, 'tintin_3x')
  542. def stop_build_timer(ctx):
  543. t = datetime.datetime.utcnow() - ctx.pbl_build_start_time
  544. node = ctx.path.get_bld().make_node('build_time')
  545. with open(node.abspath(), 'w') as fout:
  546. fout.write(str(int(round(t.total_seconds()))))
  547. def build(bld):
  548. bld.DYNAMIC_RESOURCES = []
  549. bld.LOGHASH_DICTS = []
  550. # Start this timer here to include the time to generate tasks.
  551. bld.pbl_build_start_time = datetime.datetime.utcnow()
  552. bld.add_post_fun(stop_build_timer)
  553. if bld.variant in ('test', 'test_rocky_emx', 'applib'):
  554. bld.set_env(bld.all_envs['local'])
  555. bld.load('file_name_c_define', tooldir='waftools')
  556. bld.recurse('platform')
  557. bld.recurse('src/idl')
  558. if bld.cmd == 'install':
  559. raise Exception("install isn't a supported command. Did you mean flash?")
  560. if bld.variant == 'pdc2png':
  561. bld.recurse('src/libutil')
  562. bld.recurse('tools')
  563. return
  564. if bld.variant == 'tools':
  565. bld.recurse('tools')
  566. return
  567. if bld.variant in ('', 'applib', 'prf'):
  568. # Dependency for SDK
  569. bld.recurse('src/fw/vendor/jerryscript')
  570. if bld.variant == '':
  571. # sdk generation
  572. bld.recurse('sdk')
  573. if bld.variant == 'applib':
  574. bld.recurse('resources')
  575. bld.recurse('src/libutil')
  576. bld.recurse('src/fw')
  577. bld.recurse('third_party/nanopb')
  578. bld.recurse('src/include')
  579. bld.recurse('applib-targets')
  580. return
  581. if bld.options.onlysdk:
  582. # required to build src/idl
  583. bld.recurse('third_party/nanopb')
  584. # stop here, sdk generation is done
  585. return
  586. # Do not enable stationary mode in PRF or release firmware
  587. if (bld.variant != 'prf' and not bld.env.QEMU and bld.env.NORMAL_SHELL != 'sdk'):
  588. bld.env.append_value('DEFINES', 'STATIONARY_MODE')
  589. if bld.variant == 'prf':
  590. bld.set_env(bld.all_envs['arm_prf_mode'])
  591. elif bld.variant == 'test':
  592. if bld.env.APPLIB_TARGET == 'emscripten':
  593. bld.fatal('Did you mean ./waf test_rocky_emx ?')
  594. bld.recurse('src/include')
  595. bld.recurse('src/fw/vendor/jerryscript')
  596. bld.recurse('third_party/nanopb')
  597. bld.recurse('src/libbtutil')
  598. bld.recurse('src/libos')
  599. bld.recurse('src/libutil')
  600. bld.recurse('tests')
  601. bld.recurse('tools')
  602. return
  603. elif bld.variant == 'test_rocky_emx':
  604. if bld.env.APPLIB_TARGET != 'emscripten':
  605. bld.fatal('Make sure to ./waf configure with --target=emscripten')
  606. bld.recurse('src/libutil')
  607. bld.recurse('src/libos')
  608. bld.recurse('src/fw/vendor/jerryscript')
  609. bld.recurse('third_party/nanopb')
  610. bld.recurse('applib-targets')
  611. bld.recurse('tools')
  612. bld.recurse('tests')
  613. return
  614. if bld.variant == '':
  615. bld.recurse('stored_apps')
  616. bld.recurse('third_party')
  617. bld.recurse('src/include')
  618. bld.recurse('src/libbtutil')
  619. bld.recurse('src/bluetooth-fw')
  620. bld.recurse('src/libc')
  621. bld.recurse('src/libos')
  622. bld.recurse('src/libutil')
  623. bld.recurse('src/fw')
  624. if sys.platform != 'darwin':
  625. bld.recurse('tools/qemu_spi_cooker')
  626. # Generate resources. Leave this until the end so we collect all the env['DYNAMIC_RESOURCES']
  627. # values that the other build steps added.
  628. bld.recurse('resources')
  629. # if we're not linking the firmware don't run these
  630. if not bld.env.NO_LINK:
  631. bld.add_post_fun(size_fw)
  632. bld.add_post_fun(size_resources)
  633. if 'PBL_LOGS_HASHED' in bld.env.DEFINES:
  634. bld.add_post_fun(merge_loghash_dicts)
  635. class build_prf(BuildContext):
  636. """executes the recovery firmware build"""
  637. cmd = 'build_prf'
  638. variant = 'prf'
  639. class build_applib(BuildContext):
  640. cmd = 'build_applib'
  641. variant = 'applib'
  642. def merge_loghash_dicts(bld):
  643. loghash_dict = bld.path.get_bld().make_node(LOGHASH_OUT_PATH)
  644. import log_hashing.newlogging
  645. log_hashing.newlogging.merge_loghash_dict_json_files(loghash_dict, bld.LOGHASH_DICTS)
  646. class SizeFirmware(BuildContext):
  647. cmd = 'size_fw'
  648. fun = 'size_fw'
  649. def size_fw(ctx):
  650. """prints size information of the firmware"""
  651. fw_elf = ctx.get_tintin_fw_node().change_ext('.elf')
  652. if fw_elf is None:
  653. ctx.fatal('No fw ELF found for size')
  654. fw_bin = ctx.get_tintin_fw_node()
  655. if fw_bin is None:
  656. ctx.fatal('No fw BIN found for size')
  657. import binutils
  658. text, data, bss = binutils.size(fw_elf.abspath())
  659. total = text + data
  660. output = ('{:>7} {:>7} {:>7} {:>7} {:>7} filename\n'
  661. '{:7} {:7} {:7} {:7} {:7x} tintin_fw.elf'.
  662. format('text', 'data', 'bss', 'dec', 'hex', text, data, bss, total, total))
  663. Logs.pprint('YELLOW', '\n' + output)
  664. try:
  665. space_left = _check_firmware_image_size(ctx, fw_bin.path_from(ctx.path))
  666. except FirmwareTooLargeException as e:
  667. if ctx.env.MICRO_FAMILY == 'STM32F2' and ctx.env.QEMU:
  668. # Let us off with a warning for now
  669. Logs.warn(str(e))
  670. else:
  671. ctx.fatal(str(e))
  672. else:
  673. Logs.pprint('CYAN', 'FW: ' + space_left)
  674. class SizeResources(BuildContext):
  675. cmd = 'size_resources'
  676. fun = 'size_resources'
  677. def size_resources(ctx):
  678. """prints size information of resources"""
  679. if ctx.variant == 'prf':
  680. return
  681. pbpack_path = ctx.path.get_bld().find_node('system_resources.pbpack')
  682. if pbpack_path is None:
  683. ctx.fatal('No resource pbpack found')
  684. if ctx.env.MICRO_FAMILY == 'STM32F4':
  685. max_size = 512 * 1024
  686. elif ctx.env.MICRO_FAMILY == 'STM32F7':
  687. max_size = 1024 * 1024
  688. elif ctx.env.MICRO_FAMILY == 'NRF52840':
  689. max_size = 1024 * 1024
  690. else:
  691. max_size = 256 * 1024
  692. pbpack_actual_size = os.path.getsize(pbpack_path.path_from(ctx.path))
  693. bytes_free = max_size - pbpack_actual_size
  694. from waflib import Logs
  695. Logs.pprint('CYAN', 'Resources: %d/%d (%d free)\n' % (pbpack_actual_size, max_size, bytes_free))
  696. if pbpack_actual_size > max_size:
  697. ctx.fatal('Resources are too large for target board %d > %d'
  698. % (pbpack_actual_size, max_size))
  699. def size(ctx):
  700. from waflib import Options
  701. Options.commands = ['size_fw', 'size_resources'] + Options.commands
  702. class size_prf(BuildContext):
  703. """checks the size of PRF"""
  704. cmd = 'size_prf'
  705. variant = 'prf'
  706. class test(BuildContext):
  707. """builds and runs the tests"""
  708. cmd = 'test'
  709. variant = 'test'
  710. class test_rocky_emx(BuildContext):
  711. """builds and runs the tests"""
  712. cmd = 'test_rocky_emx'
  713. variant = 'test_rocky_emx'
  714. def docs(ctx):
  715. """builds the documentation out to build/doxygen"""
  716. ctx.exec_command('doxygen Doxyfile', stdout=None, stderr=None)
  717. class DocsSdk(BuildContext):
  718. """builds the sdk documentation out to build/sdk/<platformname>/doxygen_sdk"""
  719. cmd = 'docs_sdk'
  720. fun = 'docs_sdk'
  721. def docs_sdk(ctx):
  722. pebble_sdk = ctx.path.get_bld().make_node('sdk')
  723. supported_platforms = pebble_sdk.listdir()
  724. for platform in supported_platforms:
  725. doxyfile = pebble_sdk.find_node(platform).find_node('Doxyfile-SDK.auto')
  726. if doxyfile:
  727. ctx.exec_command('doxygen {}'.format(doxyfile.path_from(ctx.path)),
  728. stdout=None, stderr=None)
  729. def docs_all(ctx):
  730. """builds the documentation with all dependency graphs out to build/doxygen"""
  731. ctx.exec_command('doxygen Doxyfile-all-graphs', stdout=None, stderr=None)
  732. # Bundle commands
  733. #################################################
  734. def _get_version_info(ctx):
  735. # FIXME: it's probably a better idea to lift board + version info from the .bin file... this can get out of sync!
  736. git_revision = waftools.gitinfo.get_git_revision(ctx)
  737. if git_revision['TAG'] != '?':
  738. version_string = git_revision['TAG']
  739. version_ts = int(git_revision['TIMESTAMP'])
  740. version_commit = git_revision['COMMIT']
  741. else:
  742. version_string = 'dev'
  743. version_ts = 0
  744. version_commit = ''
  745. return version_string, version_ts, version_commit
  746. def _make_bundle(ctx, fw_bin_path, fw_type='normal', board=None, resource_path=None, write=True):
  747. import mkbundle
  748. if board is None:
  749. board = ctx.env.BOARD
  750. b = mkbundle.PebbleBundle()
  751. version_string, version_ts, version_commit = _get_version_info(ctx)
  752. out_file = ctx.get_pbz_node(fw_type, ctx.env.BOARD, version_string).path_from(ctx.path)
  753. try:
  754. _check_firmware_image_size(ctx, fw_bin_path)
  755. b.add_firmware(fw_bin_path, fw_type, version_ts, version_commit, board, version_string)
  756. except FirmwareTooLargeException as e:
  757. ctx.fatal(str(e))
  758. except mkbundle.MissingFileException as e:
  759. ctx.fatal('Error: Missing file ' + e.filename + ', have you run ./waf build yet?')
  760. if resource_path is not None:
  761. b.add_resources(resource_path, version_ts)
  762. if 'RELEASE' not in ctx.env.DEFINES and 'PBL_LOGS_HASHED' in ctx.env.DEFINES:
  763. loghash_dict = ctx.path.get_bld().make_node(LOGHASH_OUT_PATH).abspath()
  764. b.add_loghash(loghash_dict)
  765. # Add a LICENSE.txt file
  766. b.add_license('LICENSE')
  767. # make sure ctx.capability is available
  768. ctx.recurse('platform', mandatory=False)
  769. if ctx.capability('HAS_JAVASCRIPT'):
  770. js_tooling = ctx.path.get_bld().find_node('src/fw/vendor/jerryscript/js_tooling/js_tooling.js')
  771. if js_tooling is not None:
  772. b.add_jstooling(js_tooling.path_from(ctx.path), ctx.capability('JAVASCRIPT_BYTECODE_VERSION'))
  773. if fw_type == 'normal':
  774. layouts_node = ctx.path.get_bld().find_node('resources/layouts.json.auto')
  775. if layouts_node is not None:
  776. b.add_layouts(layouts_node.path_from(ctx.path))
  777. if write:
  778. b.write(out_file)
  779. waflib.Logs.pprint('CYAN', 'Writing bundle to: %s' % out_file)
  780. return b
  781. class BundleCommand(BuildContext):
  782. cmd = 'bundle'
  783. fun = 'bundle'
  784. def bundle(ctx):
  785. """bundles a firmware"""
  786. if ctx.env.QEMU:
  787. bundle_qemu(ctx)
  788. else:
  789. _make_bundle(ctx, ctx.get_tintin_fw_node().path_from(ctx.path),
  790. resource_path=ctx.get_pbpack_node().path_from(ctx.path))
  791. class bundle_prf(BuildContext):
  792. """bundles a recovery firmware"""
  793. cmd = 'bundle_prf'
  794. variant = 'prf'
  795. def execute_build(ctx):
  796. _make_bundle(ctx, ctx.get_tintin_fw_node().path_from(ctx.path), fw_type='recovery')
  797. def _bundle_resourceless_fw(ctx, fw_path, fw_type):
  798. # We need to create a dummy pbpack and bundle it in. Some FW images don't use
  799. # resources, but the firmware will refuse to upgrade to a firmware if a resource
  800. # file isn't sent over, regardless of it's validity.
  801. import tempfile
  802. # We need to actually write some content in here or else the phone app won't think the
  803. # resources are valid, and put_bytes will refuse to update to any firmware image if it doesn't
  804. # come with a corresponding resource pack. No one will ever read these though so who cares
  805. # what the content is.
  806. with tempfile.NamedTemporaryFile(delete=False) as dummy_pbpack:
  807. dummy_pbpack.write('DUMMY')
  808. pbpack_path = dummy_pbpack.name
  809. try:
  810. _make_bundle(ctx, fw_path, fw_type=fw_type, resource_path=pbpack_path)
  811. finally:
  812. os.remove(pbpack_path)
  813. class bundle_recovery(BuildContext):
  814. """bundles a recovery firmware as normal firmware"""
  815. cmd = 'bundle_recovery'
  816. variant = 'prf'
  817. def execute_build(ctx):
  818. _bundle_resourceless_fw(ctx, ctx.get_tintin_fw_node().path_from(ctx.path),
  819. fw_type='recovery')
  820. class BundleQEMUCommand(BuildContext):
  821. cmd = 'bundle_qemu'
  822. fun = 'bundle_qemu'
  823. def bundle_qemu(ctx):
  824. """bundle QEMU images together into a "fake" PBZ"""
  825. qemu_image_micro(ctx)
  826. qemu_image_spi(ctx)
  827. b = _make_bundle(ctx, ctx.get_tintin_fw_node().path_from(ctx.path),
  828. resource_path=ctx.get_pbpack_node().path_from(ctx.path),
  829. write=False, board='qemu_{}'.format(ctx.env.BOARD))
  830. version_string, _, _ = _get_version_info(ctx)
  831. qemu_pbz = ctx.get_pbz_node('qemu', ctx.env.BOARD, version_string)
  832. out_file = qemu_pbz.path_from(ctx.path)
  833. with zipfile.ZipFile(out_file, 'w', compression=zipfile.ZIP_DEFLATED) as pbz_file:
  834. pbz_file.writestr('manifest.json', json.dumps(b.bundle_manifest))
  835. files = [ctx.get_tintin_fw_node(),
  836. ctx.get_pbpack_node(),
  837. 'qemu_micro_flash.bin',
  838. 'qemu_spi_flash.bin']
  839. if 'PBL_LOGS_HASHED' in ctx.env.DEFINES:
  840. files.append(LOGHASH_OUT_PATH)
  841. for fitem in files:
  842. if isinstance(fitem, Node.Node):
  843. fnode = fitem
  844. else:
  845. fnode = ctx.path.get_bld().make_node(fitem)
  846. img_path = fnode.path_from(ctx.path)
  847. pbz_file.write(img_path, os.path.basename(img_path))
  848. waflib.Logs.pprint('CYAN', 'Writing bundle to: %s' % out_file)
  849. class QemuImageMicroCommand(BuildContext):
  850. cmd = 'qemu_image_micro'
  851. fun = 'qemu_image_micro'
  852. class QemuImageMicroPrfCommand(BuildContext):
  853. cmd = 'qemu_image_prf_micro'
  854. fun = 'qemu_image_prf_micro'
  855. class QemuImageSpiCommand(BuildContext):
  856. cmd = 'qemu_image_spi'
  857. fun = 'qemu_image_spi'
  858. class MfgImageSpiCommand(BuildContext):
  859. cmd = 'mfg_image_spi'
  860. fun = 'mfg_image_spi'
  861. def qemu_image_micro(ctx):
  862. fw_hex = ctx.get_tintin_fw_node().change_ext('.hex')
  863. _create_qemu_image_micro(ctx, fw_hex.path_from(ctx.path))
  864. def qemu_image_prf_micro(ctx):
  865. fw_hex = ctx.get_tintin_fw_node_prf().change_ext('.hex')
  866. _create_qemu_image_micro(ctx, fw_hex.path_from(ctx.path))
  867. def _create_qemu_image_micro(ctx, path_to_firmware_hex):
  868. """creates the micro-flash image for qemu"""
  869. from intelhex import IntelHex
  870. if not ctx.env.BOOTLOADER_HEX:
  871. ctx.fatal('Board "{}" does not have a bootloader binary available'
  872. .format(ctx.env.BOARD))
  873. micro_flash_node = ctx.path.get_bld().make_node('qemu_micro_flash.bin')
  874. micro_flash_path = micro_flash_node.path_from(ctx.path)
  875. waflib.Logs.pprint('CYAN', 'Writing micro flash image to {}'.format(micro_flash_path))
  876. img = IntelHex(ctx.env.BOOTLOADER_HEX)
  877. img.merge(IntelHex(path_to_firmware_hex), overlap='replace')
  878. # Write firwmare image and pad up to next 512 byte multiple. This is because QEMU
  879. # assumes all block devices are multiples of 512 byte sectors
  880. img.padding = 0xff
  881. flash_end = ((img.maxaddr() + 511) // 512) * 512
  882. img.tobinfile(micro_flash_path, start=0x08000000, end=flash_end-1)
  883. def _create_spi_flash_image(ctx, name):
  884. spi_flash_node = ctx.path.get_bld().make_node(name)
  885. spi_flash_path = spi_flash_node.path_from(ctx.path)
  886. waflib.Logs.pprint('CYAN', 'Writing SPI flash image to {}'.format(spi_flash_path))
  887. return spi_flash_path
  888. def qemu_image_spi(ctx):
  889. """creates a SPI flash image for qemu"""
  890. if ctx.env.BOARD.startswith('silk'):
  891. resources_begin = 0x100000
  892. image_size = 0x800000
  893. elif ctx.env.BOARD.startswith('robert') or ctx.env.BOARD.startswith('cutts'):
  894. resources_begin = 0x200000
  895. image_size = 0x1000000
  896. elif ctx.env.MICRO_FAMILY == 'STM32F4':
  897. resources_begin = 0x380000
  898. image_size = 0x1000000
  899. else:
  900. resources_begin = 0x280000
  901. image_size = 0x400000
  902. spi_flash_path = _create_spi_flash_image(ctx, 'qemu_spi_flash.bin')
  903. with open(spi_flash_path, 'wb') as qemu_spi_img_file:
  904. # Pad the first section before system resources with FF's'
  905. qemu_spi_img_file.write(bytes([0xff]) * resources_begin)
  906. # Write system resources:
  907. pbpack = ctx.get_pbpack_node()
  908. res_img = open(pbpack.path_from(ctx.path), 'rb').read()
  909. qemu_spi_img_file.write(res_img)
  910. # Pad with 0xFF up to image size
  911. tail_padding_size = image_size - resources_begin - len(res_img)
  912. qemu_spi_img_file.write(bytes([0xff]) * tail_padding_size)
  913. # qemu_spi_cooker is broken on OSX but it doesn't really matter
  914. # it's only there to speed up first boot, an empty image will do
  915. if sys.platform != 'darwin':
  916. with open(os.devnull, 'w') as null:
  917. qemu_spi_cooker_node = ctx.path.get_bld().make_node('qemu_spi_cooker')
  918. qemu_spi_cooker_path = qemu_spi_cooker_node.path_from(ctx.path)
  919. subprocess.check_call([qemu_spi_cooker_path, spi_flash_path], stdout=null)
  920. def mfg_image_spi(ctx):
  921. """Creates a SPI flash image of PRF for MFG pre-burn. Includes a
  922. FirmwareDescription struct"""
  923. import insert_firmware_descr
  924. if ctx.env.BOARD.startswith('silk'):
  925. prf_begin = 0x200000
  926. image_size = 0x800000
  927. else:
  928. ctx.fatal("MFG Image not suppored for board: {}".format(ctx.env.BOARD))
  929. spi_flash_path = _create_spi_flash_image(ctx, 'mfg_prf_image.bin')
  930. mfg_spi_img_file = open(spi_flash_path, 'wb')
  931. # Pad the first section before PRF storage
  932. mfg_spi_img_file.write("\xff" * prf_begin)
  933. prf_path = ctx.get_tintin_fw_node_prf().path_from(ctx.path)
  934. prf_image = insert_firmware_descr.insert_firmware_description_struct(prf_path)
  935. mfg_spi_img_file.write(prf_image)
  936. # Pad with 0xff up to image size
  937. tail_padding_size = image_size - prf_begin - len(prf_image)
  938. mfg_spi_img_file.write("\xff" * tail_padding_size)
  939. def show_ttys(ctx):
  940. """Displays all available ftdi ports connected to computer"""
  941. os.system("python ./tools/log_hashing/miniterm_co.py ftdi:///?")
  942. class ConsoleCommand(BuildContext):
  943. cmd = 'console'
  944. fun = 'console'
  945. def console(ctx):
  946. """Starts miniterm with the serial console."""
  947. # miniterm is not made to be used as a python module, so just shell out:
  948. tty = ctx.options.tty or _get_dbgserial_tty()
  949. if _is_pulse_everywhere(ctx):
  950. os.system("python ./tools/pulse_console.py -t %s" % tty)
  951. else:
  952. baudrate = ctx.options.baudrate or 230400
  953. os.system("python ./tools/log_hashing/miniterm_co.py %s %d" % (tty, baudrate))
  954. class ConsoleCommand(BuildContext):
  955. cmd = 'console_prf'
  956. fun = 'console_prf'
  957. def console_prf(ctx):
  958. os.putenv("PBL_CONSOLE_DICT_PATH", "build/prf/src/fw/loghash_dict.json")
  959. console(ctx)
  960. class BleConsoleCommand(BuildContext):
  961. cmd = 'ble_console'
  962. fun = 'ble_console'
  963. def ble_console(ctx):
  964. def _get_ble_tty():
  965. import pebble_tty
  966. tty = pebble_tty.find_ble_tty()
  967. if tty is None:
  968. return None
  969. waflib.Logs.pprint('GREEN', 'No --tty argument specified, auto-selecting: %s' % tty)
  970. return tty
  971. """Starts miniterm with the serial console for the BLE chip."""
  972. ctx.recurse('platform', mandatory=False)
  973. # FIXME: We have the ability to progam PIDs into the new round of Big Boards. TTY
  974. # path discovery should be able to use that (PBL-31111). For now, just make a best
  975. # guess at what the path should be
  976. if ctx.is_silk() or ctx.is_robert():
  977. tty_path = _get_ble_tty()
  978. # if the bt_controller was chosen explicitly, assume we are using an eval board, which
  979. # happens to match the path for cutts
  980. elif ctx.uses_dialog_bluetooth():
  981. tty_path = "ftdi://ftdi:2232:1/1"
  982. else:
  983. waflib.Logs.pprint('CYAN', 'Note: This platform does not have a BLE UART')
  984. tty_path = _get_dbgserial_tty()
  985. tty = ctx.options.tty or tty_path
  986. baudrate = ctx.options.baudrate or 230400
  987. os.system("python ./tools/log_hashing/miniterm_co.py %s %d" % (tty, baudrate))
  988. class BleConsolePrfCommand(BuildContext):
  989. cmd = 'ble_console_prf'
  990. fun = 'ble_console_prf'
  991. def ble_console_prf(ctx):
  992. os.putenv("PBL_CONSOLE_DICT_PATH", "build/prf/src/fw/loghash_dict.json")
  993. ble_console(ctx)
  994. def accessory_console(ctx):
  995. def _get_accessory_tty():
  996. import pebble_tty
  997. tty = pebble_tty.find_accessory_tty()
  998. if tty is None:
  999. return None
  1000. waflib.Logs.pprint('GREEN', 'No --tty argument specified, auto-selecting: %s' % tty)
  1001. return tty
  1002. """Starts miniterm with the accessory connector console."""
  1003. # miniterm is not made to be used as a python module, so just shell out:
  1004. tty = ctx.options.tty or _get_accessory_tty()
  1005. baudrate = ctx.options.baudrate or 115200
  1006. os.system("python ./tools/log_hashing/miniterm_co.py %s %d" % (tty, baudrate))
  1007. def qemu(ctx):
  1008. # Make sure the micro-flash image is up to date. By default, we don't rebuild the
  1009. # SPI flash image in case you want to continue with the stored apps, etc. you had before.
  1010. from waflib import Options
  1011. Options.commands = ['qemu_image_micro', 'qemu_launch'] + Options.commands
  1012. def qemu_prf(ctx):
  1013. # Make sure the micro-flash image is up to date. By default, we don't rebuild the
  1014. # SPI flash image in case you want to continue with the stored apps, etc. you had before.
  1015. from waflib import Options
  1016. Options.commands = ['qemu_image_prf_micro', 'qemu_launch'] + Options.commands
  1017. class QemuLaunchCommand(BuildContext):
  1018. cmd = 'qemu_launch'
  1019. fun = 'qemu_launch'
  1020. def qemu_launch(ctx):
  1021. """Starts up the emulator (qemu) """
  1022. ctx.recurse('platform', mandatory=False)
  1023. qemu_machine = ctx.get_qemu_machine()
  1024. if not qemu_machine or qemu_machine == 'unknown':
  1025. raise Exception("Board type '{}' not supported by QEMU".format(ctx.env.BOARD))
  1026. qemu_micro_flash = ctx.path.get_bld().make_node('qemu_micro_flash.bin')
  1027. qemu_spi_flash = ctx.path.get_bld().make_node('qemu_spi_flash.bin')
  1028. qemu_spi_type = ctx.get_qemu_extflash_device_type()
  1029. if not qemu_spi_type:
  1030. raise Exception("External flash type for '{}' not specified".format(ctx.env.BOARD))
  1031. machine_dep_args = ['-machine', qemu_machine,
  1032. '-cpu', ctx.get_qemu_cpu(),
  1033. '-pflash', qemu_micro_flash.path_from(ctx.path),
  1034. qemu_spi_type, qemu_spi_flash.path_from(ctx.path)]
  1035. if ctx.has_touch():
  1036. machine_dep_args.append('-show-cursor')
  1037. qemu_bin = os.getenv("PEBBLE_QEMU_BIN")
  1038. if not qemu_bin or not (os.path.isfile(qemu_bin) and os.access(qemu_bin, os.X_OK)):
  1039. qemu_bin = 'qemu-system-arm'
  1040. cmd_line = (
  1041. qemu_bin + " "
  1042. "-rtc base=localtime "
  1043. "-monitor stdio "
  1044. "-s "
  1045. "-serial file:uart1.log "
  1046. "-serial tcp::12344,server,nowait " # Used for bluetooth data
  1047. "-serial tcp::12345,server,nowait " # Used for console
  1048. ) + ' '.join(machine_dep_args)
  1049. os.system(cmd_line)
  1050. class QEMUConsoleCommand(BuildContext):
  1051. cmd = 'qemu_console'
  1052. fun = 'qemu_console'
  1053. def qemu_console(ctx):
  1054. """Starts miniterm configured to talk to the emulator (qemu)"""
  1055. # miniterm is not made to be used as a python module, so just shell out:
  1056. host_port = ctx.options.qemu_host or 'localhost:12345'
  1057. # A hacky way to pass an argument
  1058. if _is_pulse_everywhere(ctx):
  1059. os.system("python ./tools/pulse_console.py -t %s" % ('socket://%s' % (host_port)))
  1060. else:
  1061. os.system("python ./tools/log_hashing/miniterm_co.py %s" % ('socket://%s' % (host_port)))
  1062. class QemuGdb(BuildContext):
  1063. """Starts up a gdb instance to talk to the emulator """
  1064. cmd = 'qemu_gdb'
  1065. fun = 'qemu_gdb'
  1066. def qemu_gdb(ctx):
  1067. # First, startup the gdb proxy
  1068. cmd_line = "python ./tools/qemu/qemu_gdb_proxy.py --port=1233 --target=localhost:1234"
  1069. proc = pexpect.spawn(cmd_line, logfile=sys.stdout, encoding='utf-8')
  1070. proc.expect(["Connected to target", pexpect.TIMEOUT], timeout=10)
  1071. fw_elf = ctx.get_tintin_fw_node().change_ext('.elf')
  1072. run_arm_gdb(ctx, fw_elf, target_server_port=1233)
  1073. class QemuGdbBoot(BuildContext):
  1074. """ Starts up a gdb instance to talk to the emulator's boot ROM """
  1075. cmd = 'qemu_gdb_boot'
  1076. fun = 'qemu_gdb_boot'
  1077. def qemu_gdb_boot(ctx):
  1078. boot_elf = ctx.get_tintin_boot_node().change_ext('.elf')
  1079. run_arm_gdb(ctx, boot_elf, target_server_port=1234)
  1080. class debug(BuildContext):
  1081. """ Alias for gdb """
  1082. cmd = 'debug'
  1083. def execute_build(ctx):
  1084. gdb(ctx)
  1085. class Gdb(BuildContext):
  1086. """ Starts GDB and openocd (if not already running) and attaches GDB to
  1087. openocd's GDB server. If openocd is already running, it will be used.
  1088. """
  1089. cmd = 'gdb'
  1090. fun = 'gdb'
  1091. def gdb(ctx, fw_elf=None, cfg_file='openocd.cfg', is_ble=False):
  1092. if fw_elf is None:
  1093. fw_elf = ctx.get_tintin_fw_node().change_ext('.elf')
  1094. with waftools.openocd.daemon(ctx, cfg_file,
  1095. use_swd=(is_ble or 'swd' in ctx.env.JTAG)):
  1096. run_arm_gdb(ctx, fw_elf, cmd_str='--init-command=".gdbinit"')
  1097. class gdb_prf(BuildContext):
  1098. """same as `gdb`, but loading the PRF elf instead"""
  1099. cmd = 'gdb_prf'
  1100. def execute_build(ctx):
  1101. gdb(ctx, ctx.get_tintin_fw_node_prf().change_ext('.elf'))
  1102. def openocd(ctx):
  1103. """ Starts openocd and leaves it running. It will reset the board to
  1104. increase the chances of attaching succesfully. """
  1105. waftools.openocd.run_command(ctx, 'init; reset', shutdown=False)
  1106. # Image commands
  1107. #################################################
  1108. def _get_dbgserial_tty():
  1109. import pebble_tty
  1110. tty = pebble_tty.find_dbgserial_tty()
  1111. if tty is None:
  1112. return None
  1113. waflib.Logs.pprint('GREEN', 'No --tty argument specified, auto-selecting: %s' % tty)
  1114. return tty
  1115. class ble_send_hci(BuildContext):
  1116. """Puts MCU in HCI bypass mode. Sends specified HCI Command and returns result. i.e:
  1117. ./waf send_hci 0x01 0x03 0x0C 0x00
  1118. """
  1119. cmd = 'ble_send_hci'
  1120. fun = 'ble_send_hci'
  1121. def ble_send_hci(ctx):
  1122. import prompt
  1123. import pebble_tty
  1124. from serial_port_wrapper import SerialPortWrapper
  1125. import struct
  1126. from time import sleep
  1127. from waflib import Options
  1128. def _dump_hex_array(prefix, hex_array):
  1129. print(prefix + " [")
  1130. for i in range(0, len(hex_array)):
  1131. print("0x%02x " % hex_array[i])
  1132. print("]")
  1133. hci_bytes = [int(i, 16) for i in Options.commands]
  1134. _dump_hex_array("Sent HCI CMD:", hci_bytes)
  1135. try:
  1136. device_tty = pebble_tty.find_dbgserial_tty()
  1137. serial = SerialPortWrapper(device_tty)
  1138. prompt.go_to_prompt(serial)
  1139. prompt.issue_command(serial, "bt test hcipass")
  1140. sleep(0.1)
  1141. serial.write_fast(struct.pack('B'*len(hci_bytes), *hci_bytes))
  1142. response = serial.read()
  1143. response = struct.unpack('%dB' % len(response), response)
  1144. serial.write(struct.pack('B', 0x04)) # issue ctrl-d
  1145. _dump_hex_array(" Got HCI EVT:", response)
  1146. finally:
  1147. # note: random bytes get dropped on subsequent usb ops if you forget to close!
  1148. serial.close()
  1149. # WAF/optparse does not have native support for adding sub-command options
  1150. # or variable length options. Reset the options list to prevent innocuous
  1151. # messaging about unrecognized commands
  1152. Options.commands = []
  1153. return None
  1154. class ImageResources(BuildContext):
  1155. """flashes resources"""
  1156. cmd = 'image_resources'
  1157. fun = 'image_resources'
  1158. def _is_pulse_everywhere(ctx):
  1159. return "PULSE_EVERYWHERE=1" in ctx.env["DEFINES"]
  1160. def _get_pulse_flash_tool(ctx):
  1161. if _is_pulse_everywhere(ctx):
  1162. return "pulse_flash_imaging"
  1163. else:
  1164. return "pulse_legacy_flash_imaging"
  1165. def image_resources(ctx):
  1166. tty = ctx.options.tty or _get_dbgserial_tty()
  1167. if tty is None:
  1168. waflib.Logs.pprint('RED', 'Error: --tty not specified')
  1169. return
  1170. tool_name = _get_pulse_flash_tool(ctx)
  1171. pbpack_path = ctx.get_pbpack_node().abspath()
  1172. waflib.Logs.pprint('CYAN', 'Writing pbpack "%s" to tty %s' % (pbpack_path, tty))
  1173. ret = os.system("python ./tools/%s.py -t %s -p resources %s" % (tool_name, tty, pbpack_path))
  1174. if ret != 0:
  1175. ctx.fatal('Imaging failed')
  1176. class ImageRecovery(BuildContext):
  1177. """flashes recovery firmware"""
  1178. cmd = 'image_recovery'
  1179. fun = 'image_recovery'
  1180. def image_recovery(ctx):
  1181. tty = ctx.options.tty or _get_dbgserial_tty()
  1182. if tty is None:
  1183. waflib.Logs.pprint('RED', 'Error: --tty not specified')
  1184. return
  1185. tool_name = _get_pulse_flash_tool(ctx)
  1186. recovery_bin_path = ctx.options.file or ctx.get_tintin_fw_node_prf().path_from(ctx.path)
  1187. waflib.Logs.pprint('CYAN', 'Writing recovery bin "%s" to tty %s' % (recovery_bin_path, tty))
  1188. ret = os.system("python ./tools/%s.py -t %s -p firmware %s" % (tool_name, tty, recovery_bin_path))
  1189. if ret != 0:
  1190. ctx.fatal('Imaging failed')
  1191. # Flash commands
  1192. #################################################
  1193. class FirmwareTooLargeException(Exception):
  1194. pass
  1195. def _check_firmware_image_size(ctx, path):
  1196. BYTES_PER_K = 1024
  1197. firmware_size = os.path.getsize(path)
  1198. # Determine flash and bootloader size so we can calculate the max firmware size
  1199. if ctx.env.MICRO_FAMILY == 'STM32F2':
  1200. # 512k of flash and 16k bootloader
  1201. max_firmware_size = (512 - 16) * BYTES_PER_K
  1202. elif ctx.env.MICRO_FAMILY == 'STM32F4':
  1203. if ctx.env.BOARD.startswith('silk') and ctx.variant == 'prf':
  1204. # silk PRF is limited to 512k to save on SPI flash space
  1205. max_firmware_size = 512 * BYTES_PER_K
  1206. elif ctx.env.BOARD in ('snowy_evt', 'snowy_evt2', 'spalding_evt'):
  1207. # 1024k of flash and 64k bootloader
  1208. max_firmware_size = (1024 - 64) * BYTES_PER_K
  1209. else:
  1210. # 1024k of flash and 16k bootloader
  1211. max_firmware_size = (1024 - 16) * BYTES_PER_K
  1212. elif ctx.env.MICRO_FAMILY == 'STM32F7':
  1213. if ctx.variant == 'prf' and not ctx.env.IS_MFG:
  1214. # Robert PRF is limited to 512k to save on SPI flash space
  1215. max_firmware_size = 512 * BYTES_PER_K
  1216. else:
  1217. # 2048k of flash and 32k bootloader
  1218. max_firmware_size = (2048 - 32) * BYTES_PER_K
  1219. elif ctx.env.MICRO_FAMILY == 'NRF52840':
  1220. if ctx.variant == 'prf' and not ctx.env.IS_MFG:
  1221. max_firmware_size = 512 * BYTES_PER_K
  1222. else:
  1223. # 1024k of flash and 32k bootloader
  1224. max_firmware_size = (1024 - 32) * BYTES_PER_K
  1225. else:
  1226. ctx.fatal('Cannot check firmware size against unknown micro family "{}"'
  1227. .format(ctx.env.MICRO_FAMILY))
  1228. if firmware_size > max_firmware_size:
  1229. raise FirmwareTooLargeException('Firmware is too large! Size is 0x%x should be less than 0x%x' \
  1230. % (firmware_size, max_firmware_size))
  1231. return ('%d / %d bytes used (%d free)' %
  1232. (firmware_size, max_firmware_size, (max_firmware_size - firmware_size)))
  1233. class FlashCommand(BuildContext):
  1234. """alias for flash_everything"""
  1235. cmd = 'flash'
  1236. fun = 'flash'
  1237. def flash(ctx):
  1238. flash_everything(ctx, ctx.get_tintin_fw_node())
  1239. class FlashPrfCommand(BuildContext):
  1240. """flashes recovery firmware as normal firmware"""
  1241. cmd = 'flash_prf'
  1242. fun = 'flash_prf'
  1243. def flash_prf(ctx):
  1244. flash_everything(ctx, ctx.get_tintin_fw_node_prf())
  1245. class FlashBootCommand(BuildContext):
  1246. cmd = 'flash_boot'
  1247. fun = 'flash_boot'
  1248. def flash_boot(ctx):
  1249. """flashes a bootloader"""
  1250. if not ctx.env.BOOTLOADER_HEX:
  1251. ctx.fatal("Target does not have a bootloader binary available")
  1252. waftools.openocd.run_command(ctx, 'init; reset halt; ' +
  1253. 'program {} reset;'.format(ctx.env.BOOTLOADER_HEX),
  1254. expect=["Programming Finished"],
  1255. enforce_expect=True)
  1256. class FlashFirmware(BuildContext):
  1257. """flashes a firmware"""
  1258. cmd = 'flash_fw'
  1259. def execute_build(ctx):
  1260. flash_fw(ctx, ctx.get_tintin_fw_node())
  1261. def flash_fw(ctx, fw_bin):
  1262. _check_firmware_image_size(ctx, fw_bin.path_from(ctx.path))
  1263. hex_path = fw_bin.change_ext('.hex').path_from(ctx.path)
  1264. waftools.openocd.run_command(ctx, 'init; reset halt; ' +
  1265. 'program {} reset;'.format(hex_path),
  1266. expect=["Programming Finished"],
  1267. enforce_expect=True)
  1268. def flash_everything(ctx, fw_bin):
  1269. """flashes a bootloader and firmware"""
  1270. if ctx.env.QEMU:
  1271. ctx.fatal("I'm sorry Dave, I can't let you do that.\n"
  1272. "QEMU firmwares do not work on physical hardware.\n"
  1273. "Configure without --qemu and rebuild before trying again.")
  1274. _check_firmware_image_size(ctx, fw_bin.path_from(ctx.path))
  1275. if not ctx.env.BOOTLOADER_HEX:
  1276. ctx.fatal("Target does not have a bootloader binary available")
  1277. hex_path = fw_bin.change_ext('.hex').path_from(ctx.path)
  1278. waftools.openocd.run_command(ctx, 'init; reset halt; '
  1279. 'program {};'.format(ctx.env.BOOTLOADER_HEX) +
  1280. 'program {} reset;'.format(hex_path),
  1281. expect=["Programming Finished", "Programming Finished", "shutdown"],
  1282. enforce_expect=True)
  1283. def force_flash(ctx):
  1284. """forces a connected device into a flashing state"""
  1285. reset_config = waftools.openocd._get_reset_conf(ctx, True)
  1286. reset_cmd = "reset_config %s; " % reset_config
  1287. waftools.openocd.run_command(ctx, reset_cmd + 'init; reset halt;', ignore_fail=True)
  1288. waftools.openocd.run_command(ctx, reset_cmd + 'init; stm32x unlock 0;', ignore_fail=True)
  1289. def reset(ctx):
  1290. """resets a connected device"""
  1291. waftools.openocd.run_command(ctx, 'init; reset;', expect=["found"])
  1292. def bork(ctx):
  1293. """resets and wipes a connected a device"""
  1294. waftools.openocd.run_command(ctx, 'init; reset halt;', ignore_fail=True)
  1295. waftools.openocd.run_command(ctx, 'init; flash erase_sector 0 0 1;', ignore_fail=True)
  1296. def make_lang(ctx):
  1297. """generate translation files and update existing ones"""
  1298. ctx.recurse('resources/normal/base/lang')
  1299. class PackLangCommand(BuildContext):
  1300. cmd = 'pack_lang'
  1301. fun = 'pack_lang'
  1302. def pack_lang(ctx):
  1303. """generates pbpack for langs"""
  1304. ctx.recurse('resources/normal/base/lang')
  1305. class PackAllLangsCommand(BuildContext):
  1306. cmd = 'pack_all_langs'
  1307. fun = 'pack_all_langs'
  1308. def pack_all_langs(ctx):
  1309. """generates pbpack for all langs"""
  1310. ctx.recurse('resources/normal/base/lang')
  1311. # Tool build commands
  1312. #################################################
  1313. class build_pdc2png(BuildContext):
  1314. """executes the pdc2png build"""
  1315. cmd = 'build_pdc2png'
  1316. variant = 'pdc2png'
  1317. class build_tools(BuildContext):
  1318. """build all tools in tools/ dir"""
  1319. cmd = 'build_tools'
  1320. variant = 'tools'
  1321. # vim:filetype=python