Skip to content
This repository has been archived by the owner on Aug 27, 2021. It is now read-only.

Add build & upload support for Arduino Teensy #163

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 139 additions & 14 deletions ino/commands/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,31 +57,31 @@ def setup_arg_parser(self, parser):
self.e.add_arduino_dist_arg(parser)

parser.add_argument('--make', metavar='MAKE',
default=self.default_make,
default='',
help='Specifies the make tool to use. If '
'a full path is not given, searches in Arduino '
'directories before PATH. Default: "%(default)s".')

parser.add_argument('--cc', metavar='COMPILER',
default=self.default_cc,
default='',
help='Specifies the compiler used for C files. If '
'a full path is not given, searches in Arduino '
'directories before PATH. Default: "%(default)s".')

parser.add_argument('--cxx', metavar='COMPILER',
default=self.default_cxx,
default='',
help='Specifies the compiler used for C++ files. '
'If a full path is not given, searches in Arduino '
'directories before PATH. Default: "%(default)s".')

parser.add_argument('--ar', metavar='AR',
default=self.default_ar,
default='',
help='Specifies the AR tool to use. If a full path '
'is not given, searches in Arduino directories '
'before PATH. Default: "%(default)s".')

parser.add_argument('--objcopy', metavar='OBJCOPY',
default=self.default_objcopy,
default='',
help='Specifies the OBJCOPY to use. If a full path '
'is not given, searches in Arduino directories '
'before PATH. Default: "%(default)s".')
Expand Down Expand Up @@ -114,25 +114,108 @@ def setup_arg_parser(self, parser):
'being invoked directly (i.e. the `-Wl,\' prefix '
'should be omitted). Default: "%(default)s".')

parser.add_argument('--menu', metavar='OPTIONS', default='',
help='"key:val,key:val" formatted string of '
'build menu items and their desired values')

parser.add_argument('-v', '--verbose', default=False, action='store_true',
help='Verbose make output')

# Merges one dictionary into another, overwriting non-dict entries and
# recursively merging dictionaries mapped to the same key.
def _mergeDicts(self,dest,src):
for key,val in src.iteritems():
if not key in dest:
dest[key] = val
elif type(val) == dict and type(dest[key]) == dict:
self._mergeDicts(dest[key],val)
else:
dest[key] = val

# Attempts to determine selections in boars['menu'] based on args.menu.
# args.menu is assumed to be formatted as "key0:val0,key1:val1,...".
# Selected options are then merged into board as though the settings
# were there all along.
def _parseMenu(self,args,board):
if not 'menu' in board:
return
choices = {}
# Menu args specified in ino.ini will already be split into a list
splitargs = args.menu if isinstance(args.menu, list) else args.menu.split(",")
for option in splitargs:
pair = option.split(":")
if len(pair) < 2:
continue
choices[pair[0]] = pair[1]

selectedOptions = {}

menu = board['menu']
failed = 0
for item,options in menu.iteritems():
if item in choices:
if not choices[item] in menu[item]:
print '\'%s\' is not a valid choice for %s (valid choices are: %s).' \
% (choices[item],item,
",".join(["'%s'" % s for s in options.keys()]))
failed += 1
else:
self._mergeDicts(selectedOptions,options[choices[item]])
else:
if len(options) == 0:
continue
print 'No option specified for %s. Defaulting to \'%s\'.' % \
(item,options.keys()[0])
self._mergeDicts(selectedOptions,options[options.keys()[0]])
if failed > 0:
raise KeyError(str(failed) + " invalid menu choices")
del selectedOptions['name']
self._mergeDicts(board,selectedOptions)


def discover(self, args):
board = self.e.board_model(args.board_model)
self._parseMenu(args,board)

core_place = os.path.join(board['_coredir'], 'cores', board['build']['core'])
core_header = 'Arduino.h' if self.e.arduino_lib_version.major else 'WProgram.h'
self.e.find_dir('arduino_core_dir', [core_header], [core_place],
human_name='Arduino core library')

if self.e.arduino_lib_version.major:
if not board['name'].lower().startswith('teensy') and self.e.arduino_lib_version.major:
variants_place = os.path.join(board['_coredir'], 'variants')
self.e.find_dir('arduino_variants_dir', ['.'], [variants_place],
human_name='Arduino variants directory')

self.e.find_arduino_dir('arduino_libraries_dir', ['libraries'],
human_name='Arduino standard libraries')

if args.make == '':
try:
args.make = board['build']['command']['make']
except KeyError as _:
args.make = self.default_make
if args.cc == '':
try:
args.cc = board['build']['command']['gcc']
except KeyError as _:
args.cc = self.default_cc
if args.cxx == '':
try:
args.cxx = board['build']['command']['g++']
except KeyError as _:
args.cxx = self.default_cxx
if args.ar == '':
try:
args.ar = board['build']['command']['ar']
except KeyError as _:
args.ar = self.default_ar
if args.objcopy == '':
try:
args.objcopy = board['build']['command']['objcopy']
except KeyError as _:
args.objcopy = self.default_objcopy

toolset = [
('make', args.make),
('cc', args.cc),
Expand All @@ -143,40 +226,82 @@ def discover(self, args):

for tool_key, tool_binary in toolset:
self.e.find_arduino_tool(
tool_key, ['hardware', 'tools', 'avr', 'bin'],
tool_key, ['hardware', 'tools', '*', 'bin'],
items=[tool_binary], human_name=tool_binary)

# Used to parse board options. Finds a sequence of entries in table with the
# keys prefix0, prefix1, prefix2 (or beginning with prefix1 if start = 1),
# and appends them to the list-like structure out which has a constructor wrap.
# For example:
# >>> o = []
# >>> table = {'squirrel':3,'a1':1,'a2':1,'a3':2,'a4':3,'a5':5,'a7':13}
# >>> _appendNumberedEntries(o,table,'a',start=1,wrap=lambda x:[x])
# >>> o
# >>> [1,1,2,3,5]
def _appendNumberedEntries(self, out, table, prefix, start=0, wrap=SpaceList):
i = start
while (prefix + str(i)) in table:
out += wrap([table[prefix+str(i)]])
i += 1

def setup_flags(self, args):
board = self.e.board_model(args.board_model)
mcu = '-mmcu=' + board['build']['mcu']
cpu,mcu = '',''
if 'cpu' in board['build']:
cpu = '-mcpu=' + board['build']['cpu']
elif 'mcu' in board['build']:
mcu = '-mmcu=' + board['build']['mcu']
if 'f_cpu' in board['build']:
f_cpu = board['build']['f_cpu']
else:
raise KeyError('No valid source of f_cpu option')

# Hard-code the flags that are essential to building the sketch
self.e['cppflags'] = SpaceList([
cpu,
mcu,
'-DF_CPU=' + board['build']['f_cpu'],
'-DF_CPU=' + f_cpu,
'-DARDUINO=' + str(self.e.arduino_lib_version.as_int()),
'-I' + self.e['arduino_core_dir'],
])
])
# Add additional flags as specified
self.e['cppflags'] += SpaceList(shlex.split(args.cppflags))
self._appendNumberedEntries(self.e['cppflags'],board['build'],'option',start=1)
self._appendNumberedEntries(self.e['cppflags'],board['build'],'define')

if 'vid' in board['build']:
self.e['cppflags'].append('-DUSB_VID=%s' % board['build']['vid'])
if 'pid' in board['build']:
self.e['cppflags'].append('-DUSB_PID=%s' % board['build']['pid'])

if self.e.arduino_lib_version.major:
variant_dir = os.path.join(self.e.arduino_variants_dir,

if board['name'].lower().startswith('teensy'):
pass
elif self.e.arduino_lib_version.major:
variant_dir = os.path.join(self.e.arduino_variants_dir,
board['build']['variant'])
self.e.cppflags.append('-I' + variant_dir)

self.e['cflags'] = SpaceList(shlex.split(args.cflags))
self.e['cxxflags'] = SpaceList(shlex.split(args.cxxflags))
self._appendNumberedEntries(self.e['cxxflags'],board['build'],
'cppoption',start=1)

# Again, hard-code the flags that are essential to building the sketch
self.e['ldflags'] = SpaceList([mcu])
self.e['ldflags'] = SpaceList([cpu,mcu])
self.e['ldflags'] += SpaceList([
'-Wl,' + flag for flag in shlex.split(args.ldflags)
])
self._appendNumberedEntries(self.e['ldflags'],board['build'],
'linkoption',start=1)
self._appendNumberedEntries(self.e['ldflags'],board['build'],
'additionalobject',start=1)

if 'linkscript' in board['build']:
script = self.e.find_arduino_tool(board['build']['linkscript'],
['hardware','*','cores','*'],
human_name='Link script')
self.e['ldflags'] = SpaceList(['-T' + script]) + \
self.e['ldflags']

self.e['names'] = {
'obj': '%s.o',
Expand Down
35 changes: 31 additions & 4 deletions ino/commands/upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,13 @@ def setup_arg_parser(self, parser):
self.e.add_board_model_arg(parser)
self.e.add_arduino_dist_arg(parser)

def discover(self):
def discover(self,model):
board = self.e.board_model(model)
self.e.find_tool('stty', ['stty'])
if platform.system() == 'Linux':
if model.startswith('teensy'):
self.e.find_arduino_tool(board['build']['post_compile_script'], ['hardware', 'tools'])
self.e.find_arduino_tool(board['upload']['avrdude_wrapper'], ['hardware','tools'])
elif platform.system() == 'Linux':
self.e.find_arduino_tool('avrdude', ['hardware', 'tools'])

conf_places = self.e.arduino_dist_places(['hardware', 'tools'])
Expand All @@ -48,10 +52,33 @@ def discover(self):
self.e.find_arduino_file('avrdude.conf', ['hardware', 'tools', 'avr', 'etc'])

def run(self, args):
self.discover()
port = args.serial_port or self.e.guess_serial_port()
self.discover(args.board_model)
board = self.e.board_model(args.board_model)

if args.board_model.startswith('teensy'):
post_compile = self.e[board['build']['post_compile_script']]
reboot = self.e[board['upload']['avrdude_wrapper']]
# post_compile script requires:
# .hex filename w/o the extension
filename = os.path.splitext(self.e.hex_filename)[0]
# full path to directory with the compiled .hex file
fullpath = os.path.realpath(self.e.build_dir)
# full path to the tools directory
tooldir = self.e.find_arduino_dir('', ['hardware', 'tools'])
subprocess.call([
post_compile,
'-file=' + filename,
'-path=' + fullpath,
'-tools=' + tooldir
])
# reboot to complete the upload
# NOTE: this will warn the user if they need to press the reset button
subprocess.call([
reboot
])
exit(0)

port = args.serial_port or self.e.guess_serial_port()
protocol = board['upload']['protocol']
if protocol == 'stk500':
# if v1 is not specifid explicitly avrdude will
Expand Down