2 # This script includes arduino specific config
12 if not os.path.isfile(f):
16 strs = file.readlines()
19 if len(str) > 0 and str[0] == '#':
24 dict.setdefault(str[0:idx], str[idx + 1:])
28 def __get_boards(dict):
32 idx = key.find('.name')
34 if key.endswith('.name'):
35 boards.append(key[0:idx])
38 def __get_cpu(dict, board):
42 idx = key.find(board + '.menu.cpu.')
43 start = len(board + '.menu.cpu.')
45 end = key.find('.', start)
58 def __get_board_info(board, key):
60 v = boards_info.get(board + '.menu.cpu.' + cpu + key)
62 v = boards_info.get(board + key)
64 v = boards_info.get(board + key)
67 def __search_files(path, pattern, ondisk=True, source=True, strings=False, recursive=True):
69 return Glob(pattern, ondisk, source, strings)
72 for root, dirnames, filenames in os.walk(path):
73 # This is a helper function to build Arduino libraries. Scripts are using this function
74 # to add all the files in a folder as compilation targets rather than specifying each
75 # file to compile from a Arduino library folder.
77 # Since the function is recursive, it adds even "/library/<library-name>/examples" to the
78 # compilation list. This is an extra overhead as stack is never going to use ".o" generated
80 if 'examples' not in root:
81 matches.extend(Glob(os.path.join(root, pattern), ondisk, source, strings))
84 # To make sure the src is built in 'BUILD_DIR' (by default it will be built at
85 # the same directory as the .c .cpp .S)
86 def __src_to_obj(env, srcs):
88 prefix = env.get('BOARD') + '_'
90 prefix += env.get('CPU') + '_'
92 build_dir = os.path.join(env.get('BUILD_DIR'), 'arduino')
94 if (os.path.isabs(src.path)):
95 obj = src.path.replace(arduino_home, build_dir)
97 obj = os.path.join(build_dir, src.path)
100 if env.get('OBJSUFFIX'):
101 obj += env.get('OBJSUFFIX')
102 objs.extend(env.Object(obj, src, OBJPREFIX=prefix))
105 def __import_lib(env, lib):
106 lib_path = os.path.join(arduino_home, 'libraries', lib)
107 if not os.path.exists(lib_path):
108 if target_arch == 'avr':
109 lib_path = os.path.join(arduino_home, 'hardware', 'arduino', 'avr', 'libraries', lib)
111 lib_path = os.path.join(arduino_home, 'hardware', 'arduino', 'sam', 'libraries', lib)
113 if os.path.exists(os.path.join(lib_path, 'src')):
114 lib_path = os.path.join(lib_path, 'src')
116 env.AppendUnique(CPPPATH = [lib_path])
118 if os.path.exists(os.path.join(lib_path, 'utility')):
119 env.AppendUnique(CPPPATH = [os.path.join(lib_path, 'utility')])
122 lib_src.extend(__search_files(lib_path, '*.S'))
123 lib_src.extend(__search_files(lib_path, '*.c'))
124 lib_src.extend(__search_files(lib_path, '*.cpp'))
126 lib_obj = __src_to_obj(env, lib_src)
127 build_dir = env.get('BUILD_DIR')
129 lib_a = env.StaticLibrary(build_dir + lib, lib_obj)
131 lib_a = env.StaticLibrary(lib, lib_obj)
133 # If we link libSPI.a, the final binary is not getting launched
134 # on the board. Which is not the case if we directly use SPI.o.
136 if env.get('TARGET_ARCH') == 'arm':
139 if obj.name.endswith('SPI.o'):
140 env.PrependUnique(LIBS = [File(obj)])
143 env.AppendUnique(LIBS = [File(lib_a[0])])
145 env.PrependUnique(LIBS = [File(lib_a[0])])
147 #env.AppendUnique(LIBS = [File(lib_a[0])])
149 def __build_core(env):
150 core_src = __search_files(core_folder, '*.S')
151 core_src.extend(__search_files(core_folder, '*.c'))
152 core_src.extend(__search_files(core_folder, '*.cpp'))
154 core_src.extend(__search_files(variant_folder, '*.S'))
155 core_src.extend(__search_files(variant_folder, '*.c'))
156 core_src.extend(__search_files(variant_folder, '*.cpp'))
158 core_obj = __src_to_obj(env, core_src)
160 prefix = env.get('BOARD') + '_'
162 prefix += env.get('CPU') + '_'
164 core = os.path.join(env.get('BUILD_DIR', '.'), 'arduino', prefix + 'core')
165 s_core = env.StaticLibrary(core, core_obj)
167 env.AppendUnique(LIBS = [File(s_core[0])])
169 # To avoid compiler issue. Otherewise there may be warnings:
170 # undefined reference to '_exit' '_close', '_getpid' ...
171 # Above functions are used in libc.a and implemented in syscalls_sam3.c
172 if env.get('TARGET_ARCH') == 'arm':
174 if obj.name.endswith('syscalls_sam3.o'):
175 env.AppendUnique(LIBS = [File(obj)])
177 def __create_bin(env, source):
179 if env.get('TARGET_ARCH') == 'avr':
180 eep = env.Command(name + '.eep', source, 'avr-objcopy -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 $SOURCE $TARGET')
181 hex = env.Command(name + '.hex', source, 'avr-objcopy -O ihex -R .eeprom $SOURCE $TARGET')
183 hex = env.Command(name + '.hex', source, 'arm-none-eabi-objcopy -O binary $SOURCE $TARGET')
185 #Currently supporting only mega (ie. Arduino ATMega2560) and arduino_due_x/arduino_due_x_dbg (i.e. Arduino Due) builds
186 def __upload(env, binary):
187 if target_arch == 'avr':
188 protocol = __get_board_info(board, '.upload.protocol')
189 speed = __get_board_info(board, '.upload.speed')
190 port = '/dev/ttyACM0'
191 upload_cmd = arduino_home + '/hardware/tools/avr/bin/avrdude -C' + arduino_home +'/hardware/tools/avr/etc/avrdude.conf -p' \
192 + mcu + ' -c' + protocol + ' -P' + port + ' -b' + speed + ' -D -Uflash:w:' + binary + ':i'
193 print "Upload command: %s" %upload_cmd
194 install_cmd = env.Command('install_cmd', None, upload_cmd)
195 env.Default('install_cmd')
196 elif target_arch == 'arm':
197 protocol = __get_board_info(board, '.upload.protocol')
198 speed = __get_board_info(board, '.upload.speed')
200 uu = __get_board_info(board, '.upload.native_usb')
201 os.system('stty -F /dev/' + port + ' speed 1200 cs8 -cstopb -parenb')
202 os.system(arduino_home + '/hardware/tools/bossac -i --port=' + port + ' -U false -e -w -b ' + binary + ' -R')
204 # Print the command line that to upload binary to the board
205 def __upload_help(env):
206 if target_arch == 'avr':
207 protocol = __get_board_info(board, '.upload.protocol')
208 speed = __get_board_info(board, '.upload.speed')
210 upload_cmd = arduino_home + '/hardware/tools/avr/bin/avrdude -C' + arduino_home +'/hardware/tools/avr/etc/avrdude.conf -v -v -v -v -p' \
211 + mcu + ' -c' + protocol + ' -P<serial_port>' + ' -b' + speed + ' -D -Uflash:w:<hex_file>:i'
213 uu = __get_board_info(board, '.upload.native_usb')
214 upload_cmd = arduino_home + '/hardware/tools/bossac -i -d --port=<serial_port> -U ' + uu + ' -e -w -v -b <bin file> -R'
217 ===============================================================================
218 You can upload the bin file with following command line:
220 Help('\n $ ' + upload_cmd)
222 \nPlease replace <xxx> according to the actual situation.
223 ===============================================================================
226 # ARDUINO_HOME build option
227 help_vars = Variables()
228 help_vars.Add(PathVariable('ARDUINO_HOME', 'ARDUINO root directory', os.environ.get('ARDUINO_HOME')))
229 help_vars.Update(env)
230 Help(help_vars.GenerateHelpText(env))
232 target_arch = env.get('TARGET_ARCH')
234 # Verify that the arduino, time, red bear, and nordic libraries are
235 # installed. If not, get them and install them.
236 SConscript(os.path.join(env.get('SRC_DIR'), 'extlibs', 'arduino', 'SConscript'))
237 arduino_home = env.get('ARDUINO_HOME')
238 print 'ARDUINO_HOME = ' + env.get('ARDUINO_HOME')
240 # Overwrite suffixes and prefixes
241 if env['HOST_OS'] == 'win32':
242 env['OBJSUFFIX'] = '.o'
243 env['SHOBJSUFFIX'] = '.os'
244 env['LIBPREFIX'] = 'lib'
245 env['LIBSUFFIX'] = '.a'
246 env['SHLIBPREFIX'] = 'lib'
247 env['SHLIBSUFFIX'] = '.so'
248 env['LIBPREFIXES'] = ['lib']
249 env['LIBSUFFIXES'] = ['.a', '.so']
250 env['PROGSUFFIX'] = ''
251 elif platform.system().lower() == 'darwin':
252 env['SHLIBSUFFIX'] = '.so'
253 env['LIBSUFFIXES'] = ['.a', '.so']
254 env['PROGSUFFIX'] = ''
256 # Debug/release relative flags
257 if env.get('RELEASE'):
258 env.AppendUnique(CCFLAGS = ['-Os'])
259 env.AppendUnique(CPPDEFINES = ['NDEBUG'])
261 env.AppendUnique(CCFLAGS = ['-g'])
266 if os.path.exists(os.path.join(arduino_home, 'lib', 'version.txt')):
267 vf = open(os.path.join(arduino_home, 'lib', 'version.txt'), 'r')
268 version = vf.readline().replace('.', '').strip()
271 ************************************* Error ***********************************
272 * Can't find version file (lib/version.txt), please check if (%s)
273 * is arduino root directory. *
274 *******************************************************************************
278 if version[0:2] == '10':
280 boards_info = __parse_config(os.path.join(arduino_home, 'hardware', 'arduino', 'boards.txt'))
281 env.PrependENVPath('PATH', os.path.join(arduino_home, 'hardware', 'tools', 'avr', 'bin'))
282 env.Replace(CC = 'avr-gcc')
283 env.Replace(CXX = 'avr-g++')
284 env.Replace(AR = 'avr-ar')
285 env.Replace(AS = 'avr-as')
286 env.Replace(LINK = 'avr-gcc')
287 env.Replace(RANLIB = 'avr-ranlib')
288 if target_arch != 'avr':
290 ************************************* Error ***********************************
291 * Arduino 1.0.x IDE only support 'avr', to support other arch at least 1.5.x *
293 *******************************************************************************
298 if target_arch == 'avr':
299 boards_info = __parse_config(os.path.join(arduino_home, 'hardware', 'arduino', 'avr', 'boards.txt'))
300 platform_info = __parse_config(os.path.join(arduino_home, 'hardware', 'arduino', 'avr', 'platform.txt'))
301 elif target_arch == 'arm':
302 boards_info = __parse_config(os.path.join(arduino_home, 'hardware', 'arduino', 'sam', 'boards.txt'))
303 platform_info = __parse_config(os.path.join(arduino_home, 'hardware', 'arduino', 'sam', 'platform.txt'))
306 ************************************* Error ***********************************
307 * CPU arch %s isn't supported currently.
308 *******************************************************************************
311 #Board option, let user to select the board
312 boards = __get_boards(boards_info)
313 help_vars = Variables()
314 help_vars.Add(EnumVariable('BOARD', 'arduino board', boards[0], boards))
315 help_vars.Update(env)
316 Help(help_vars.GenerateHelpText(env))
319 board = env.get('BOARD')
320 cpus = __get_cpu(boards_info, board)
322 help_vars = Variables()
323 help_vars.Add(EnumVariable('CPU', 'arduino board cpu', cpus[0], cpus))
324 help_vars.Update(env)
325 Help(help_vars.GenerateHelpText(env))
327 # Arduino commom flags
329 board = env.get('BOARD')
330 mcu = __get_board_info(board, '.build.mcu')
331 f_cpu = __get_board_info(board, '.build.f_cpu')
332 usb_vid = __get_board_info(board, '.build.vid')
333 usb_pid = __get_board_info(board, '.build.pid')
334 variant = __get_board_info(board, '.build.variant')
337 usb_vid = __get_board_info(board, '.vid.0')
339 usb_pid = __get_board_info(board, '.pid.0')
342 core_base = os.path.join(arduino_home, 'hardware', 'arduino')
344 if target_arch == 'avr':
345 core_base = os.path.join(arduino_home, 'hardware', 'arduino', 'avr')
347 core_base = os.path.join(arduino_home, 'hardware', 'arduino', 'sam')
349 variant_folder = os.path.join(core_base, 'variants', variant)
350 env.AppendUnique(CPPPATH = [variant_folder])
352 core = __get_board_info(board, '.build.core')
353 core_folder = os.path.join(core_base, 'cores', core)
354 env.AppendUnique(CPPPATH = [core_folder])
357 comm_flags = ['-std=c99']
359 comm_flags.extend(['-mmcu=' + mcu])
361 comm_flags.extend(['-DF_CPU=' + f_cpu])
362 comm_flags.extend(['-DARDUINO=' + version])
364 comm_flags.extend(['-DUSB_VID=' + usb_vid])
366 comm_flags.extend(['-DUSB_PID=' + usb_pid])
368 env.AppendUnique(ASFLAGS = ['-x', 'assembler-with-cpp'])
369 env.AppendUnique(ASFLAGS = comm_flags)
371 env.AppendUnique(CFLAGS = ['-Os', '-ffunction-sections', '-fdata-sections', '-MMD'])
372 env.AppendUnique(CFLAGS = comm_flags)
374 env.AppendUnique(CXXFLAGS = ['-Os', '-fno-exceptions', '-ffunction-sections', '-fdata-sections','-MMD'])
375 env.AppendUnique(CXXFLAGS = comm_flags)
377 env.AppendUnique(LINKFLAGS = ['-Os'])
378 if mcu == 'atmega2560':
379 env.AppendUnique(LINKFLAGS = ['-Wl,--gc-sections,--relax'])
381 env.AppendUnique(LINKFLAGS = ['-Wl,--gc-sections'])
382 env.AppendUnique(LINKFLAGS = ['-mmcu=' + mcu])
384 if target_arch == 'avr':
385 cpu_flag = '-mmcu=' + mcu
387 cpu_flag = '-mcpu=' + mcu
389 comm_flag = [cpu_flag, '-DF_CPU=' + f_cpu, '-DARDUINO=' + version, '-DARDUINO_' + __get_board_info(board, '.build.board')]
390 if target_arch == 'arm':
391 # As of 1.5.8 the arduino headers for arm had _asm_ bugs with ARM and
392 # require gnu99 to be used
393 comm_flag.extend(['-std=gnu99', '-DARDUINO_ARCH_SAM'])
395 comm_flag.extend(['-std=c99', '-DARDUINO_ARCH_AVR'])
397 compiler_path = platform_info.get('compiler.path')
398 compiler_path = compiler_path.replace('{runtime.ide.path}', arduino_home)
399 env.PrependENVPath('PATH', compiler_path)
400 env.Replace(CC = platform_info.get('compiler.c.cmd'))
401 env.Replace(CXX = platform_info.get('compiler.cpp.cmd'))
402 env.Replace(AR = platform_info.get('compiler.ar.cmd'))
403 if target_arch == 'arm':
404 env.AppendUnique(CPPPATH = [os.path.join(arduino_home, 'hardware', 'arduino', 'sam', 'system', 'libsam'),
405 os.path.join(arduino_home, 'hardware', 'arduino', 'sam', 'system', 'CMSIS', 'CMSIS', 'Include'),
406 os.path.join(arduino_home, 'hardware', 'arduino', 'sam', 'system', '', 'CMSIS', 'Device', 'ATMEL')])
407 env.AppendUnique(ASFLAGS = ['-x', 'assembler-with-cpp'])
408 env.AppendUnique(ASFLAGS = comm_flag)
409 env.AppendUnique(CFLAGS = Split(platform_info.get('compiler.c.flags')))
410 env.AppendUnique(CXXFLAGS = Split(platform_info.get('compiler.cpp.flags')))
411 env.AppendUnique(ARFLAGS = Split(platform_info.get('compiler.ar.flags')))
412 env.AppendUnique(CCFLAGS = comm_flag)
414 extra_flags = __get_board_info(board, '.build.extra_flags')
416 extra_flags = extra_flags.replace('{build.usb_flags}', '')
417 env.AppendUnique(CCFLAGS = Split(extra_flags))
418 usb_flags = ['-DUSB_VID=' + usb_vid, '-DUSB_PID=' + usb_pid, '-DUSBCON', '-DUSB_MANUFACTURER="Unknown"']
419 env.AppendUnique(CCFLAGS = usb_flags)
421 if target_arch == 'arm':
422 env.AppendUnique(LINKFLAGS = ['-Os', '-Wl,--gc-sections', cpu_flag,
423 '-T' + os.path.join(variant_folder, __get_board_info(board, '.build.ldscript'))])
424 env.AppendUnique(LINKFLAGS = Split('-lm -lgcc -mthumb -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group'))
426 variant_system_lib = __get_board_info(board, '.build.variant_system_lib')
427 if variant_system_lib:
428 if variant_folder.find(' ') >= 0:
429 variant_folder = '"' + variant_folder + '"'
430 env.Replace(LINKCOM = '$LINK -o $TARGET $_LIBDIRFLAGS $LINKFLAGS $SOURCES $_LIBFLAGS '
431 + os.path.join(variant_folder, variant_system_lib) + ' -Wl,--end-group')
433 env.Replace(LINKCOM = '$LINK -o $TARGET $_LIBDIRFLAGS $LINKFLAGS $SOURCES $_LIBFLAGS -Wl,--end-group')
435 env.AppendUnique(LINKFLAGS = Split(platform_info.get('compiler.c.elf.flags')))
436 env.AppendUnique(LINKFLAGS = [cpu_flag])
437 env.AppendUnique(LIBS = 'm')
438 env.Replace(ARCOM = '$AR ' + platform_info.get('compiler.ar.flags') + ' $TARGET $SOURCES')
440 # Make sure the .d files are removed when clean the build
441 if env.GetOption('clean'):
442 dfs = __search_files(env.get('BUILD_DIR'), '*.d')
447 env.AddMethod(__import_lib, "ImportLib") #import arduino library
448 env.AddMethod(__build_core, "BuildCore") #build arduino core
449 env.AddMethod(__create_bin, "CreateBin") #create binary files(.eep and .hex)
450 env.AddMethod(__upload, "Upload") #Upload binary to board
451 env.AddMethod(__upload_help, "UploadHelp") #print the command line that to upload binary to the boardf