the other jimmy / mbed-sdk-tools

Fork of mbed-sdk-tools by mbed official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers __init__.py Source File

__init__.py

00001 import os
00002 from os.path import sep, normpath, join, exists
00003 import ntpath
00004 import copy
00005 from collections import namedtuple
00006 import shutil
00007 from subprocess import Popen, PIPE
00008 import re
00009 
00010 from tools.arm_pack_manager import Cache
00011 from tools.targets import TARGET_MAP
00012 from tools.export.exporters import Exporter
00013 from tools.export.cmsis import DeviceCMSIS
00014 
00015 cache_d = False
00016 
00017 
00018 class DeviceUvision (DeviceCMSIS):
00019     """Uvision Device class, inherits CMSIS Device class
00020 
00021     Encapsulates information necessary for uvision project targets"""
00022     def __init__(self, target):
00023         DeviceCMSIS.__init__(self, target)
00024         dev_format = "$$Device:{0}${1}"
00025         self.svd  = ''
00026         if self.debug_svd:
00027             self.svd  = dev_format.format(self.dname, self.debug_svd)
00028         self.reg_file  = dev_format.format(self.dname, self.compile_header)
00029         self.debug_interface  = self.uv_debug ()
00030         self.flash_dll  = self.generate_flash_dll ()
00031 
00032     def uv_debug (self):
00033         """Return a namedtuple of information about uvision debug settings"""
00034         UVDebug = namedtuple('UVDebug',['bin_loc','core_flag', 'key'])
00035 
00036         # CortexMXn => pCMX
00037         cpu = self.core.replace("Cortex-", "C")
00038         cpu = cpu.replace("+", "")
00039         cpu = cpu.replace("F", "")
00040         cpu_flag = "p"+cpu
00041 
00042         # Locations found in Keil_v5/TOOLS.INI
00043         debuggers = {"st-link": ('STLink\\ST-LINKIII-KEIL_SWO.dll', 'ST-LINKIII-KEIL_SWO'),
00044                      "j-link":('Segger\\JL2CM3.dll', 'JL2CM3'),
00045                      "cmsis-dap":('BIN\\CMSIS_AGDI.dll', 'CMSIS_AGDI'),
00046                      "nulink":('NULink\\Nu_Link.dll','Nu_Link')}
00047         res = debuggers[self.debug.lower()]
00048         binary = res[0]
00049         key = res[1]
00050 
00051         return UVDebug(binary, cpu_flag, key)
00052 
00053     def generate_flash_dll (self):
00054         '''Flash DLL string from uvision
00055         S = SW/JTAG Clock ID
00056         C = CPU index in JTAG chain
00057         P = Access Port
00058         For the Options for Target -> Debug tab -> settings -> "Flash" tab in the dialog:
00059         FD = RAM Start for Flash Functions
00060         FC = RAM Size for Flash Functions
00061         FN = Number of Flash types
00062         FF = Flash File Name (without an extension)
00063         FS = Start Address of the Flash Device
00064         FL = Size of the Flash Device
00065         FP = Full path to the Device algorithm (RTE)
00066 
00067         Necessary to flash some targets. Info gathered from algorithms field of pdsc file.
00068         '''
00069         fl_count = 0
00070         def get_mem_no_x(mem_str):
00071             mem_reg = "\dx(\w+)"
00072             m = re.search(mem_reg, mem_str)
00073             return m.group(1) if m else None
00074 
00075         RAMS = [(get_mem_no_x(info["start"]), get_mem_no_x(info["size"]))
00076                 for mem, info in self.target_info["memory"].items() if "RAM" in mem]
00077         format_str = "UL2CM3(-S0 -C0 -P0 -FD{ramstart}"+" -FC{ramsize} "+"-FN{num_algos} {extra_flags})"
00078         ramstart = ''
00079         #Default according to Keil developer
00080         ramsize = '1000'
00081         if len(RAMS)>=1:
00082             ramstart = RAMS[0][0]
00083         extra_flags = []
00084         for name, info in self.target_info["algorithm"].items():
00085             if not name or not info:
00086                 continue
00087             if int(info["default"])==0:
00088                 continue
00089             name_reg = "\w*/([\w_]+)\.flm"
00090             m = re.search(name_reg, name.lower())
00091             fl_name = m.group(1) if m else None
00092             name_flag = "-FF" + str(fl_count) + fl_name
00093 
00094             start, size = get_mem_no_x(info["start"]), get_mem_no_x(info["size"])
00095             rom_start_flag = "-FS"+str(fl_count)+str(start)
00096             rom_size_flag = "-FL" + str(fl_count) + str(size)
00097 
00098             if info["ramstart"] is not None and info["ramsize"] is not None:
00099                 ramstart = get_mem_no_x(info["ramstart"])
00100                 ramsize = get_mem_no_x(info["ramsize"])
00101 
00102             path_flag = "-FP" + str(fl_count) + "($$Device:"+self.dname+"$"+name+")"
00103 
00104             extra_flags.extend([name_flag, rom_start_flag, rom_size_flag, path_flag])
00105             fl_count += 1
00106 
00107         extra = " ".join(extra_flags)
00108         return format_str.format(ramstart=ramstart,
00109                                  ramsize=ramsize,
00110                                  extra_flags=extra, num_algos=fl_count)
00111 
00112 
00113 class Uvision (Exporter):
00114     """Keil Uvision class
00115 
00116     This class encapsulates information to be contained in a Uvision
00117     project file (.uvprojx).
00118     The needed information can be viewed in uvision.tmpl
00119     """
00120     NAME = 'uvision5'
00121     TOOLCHAIN = 'ARM'
00122     TARGETS = []
00123     for target, obj in TARGET_MAP.iteritems():
00124         if not ("ARM" in obj.supported_toolchains and hasattr(obj, "device_name")):
00125             continue
00126         if not DeviceCMSIS.check_supported(target):
00127             continue
00128         TARGETS.append(target)
00129     #File associations within .uvprojx file
00130     file_types = {'.cpp': 8, '.c': 1, '.s': 2,
00131                   '.obj': 3, '.o': 3, '.lib': 4,
00132                   '.ar': 4, '.h': 5, '.hpp': 5, '.sct': 4}
00133 
00134     def uv_files (self, files):
00135         """An generator containing Uvision specific information about project files
00136         Positional Arguments:
00137         files - the location of source files
00138 
00139         .uvprojx XML for project file:
00140         <File>
00141             <FileType>{{file.type}}</FileType>
00142             <FileName>{{file.name}}</FileName>
00143             <FilePath>{{file.loc}}</FilePath>
00144         </File>
00145         """
00146         for loc in files:
00147             #Encapsulates the information necessary for template entry above
00148             UVFile = namedtuple('UVFile', ['type','loc','name'])
00149             _, ext = os.path.splitext(loc)
00150             if ext.lower() in self.file_types :
00151                 type = self.file_types [ext.lower()]
00152                 name = ntpath.basename(normpath(loc))
00153                 yield UVFile(type, loc, name)
00154 
00155     def format_flags (self):
00156         """Format toolchain flags for Uvision"""
00157         flags = copy.deepcopy(self.flags)
00158         asm_flag_string = '--cpreproc --cpreproc_opts=-D__ASSERT_MSG,' + \
00159                           ",".join(flags['asm_flags'])
00160         # asm flags only, common are not valid within uvision project,
00161         # they are armcc specific
00162         flags['asm_flags'] = asm_flag_string
00163         # cxx flags included, as uvision have them all in one tab
00164         flags['c_flags'] = list(set(['-D__ASSERT_MSG']
00165                                         + flags['common_flags']
00166                                         + flags['c_flags']
00167                                         + flags['cxx_flags']))
00168         # not compatible with c99 flag set in the template
00169         try: flags['c_flags'].remove("--c99")
00170         except ValueError: pass
00171         # cpp is not required as it's implicit for cpp files
00172         try: flags['c_flags'].remove("--cpp")
00173         except ValueError: pass
00174         # we want no-vla for only cxx, but it's also applied for C in IDE,
00175         #  thus we remove it
00176         try: flags['c_flags'].remove("--no_vla")
00177         except ValueError: pass
00178         flags['c_flags'] =" ".join(flags['c_flags'])
00179         return flags
00180 
00181     def format_src (self, srcs):
00182         """Make sources into the named tuple for use in the template"""
00183         grouped = self.group_project_files(srcs)
00184         for group, files in grouped.items():
00185             grouped[group] = self.uv_files (files)
00186         return grouped
00187 
00188     def generate (self):
00189         """Generate the .uvproj file"""
00190         cache = Cache(True, False)
00191         if cache_d:
00192             cache.cache_descriptors()
00193 
00194         srcs = self.resources.headers + self.resources.s_sources + \
00195                self.resources.c_sources + self.resources.cpp_sources + \
00196                self.resources.objects + self.resources.libraries
00197         ctx = {
00198             'name': self.project_name,
00199             # project_files => dict of generators - file group to generator of
00200             # UVFile tuples defined above
00201             'project_files': self.format_src (srcs),
00202             'linker_script':self.resources.linker_script,
00203             'include_paths': '; '.join(self.resources.inc_dirs).encode('utf-8'),
00204             'device': DeviceUvision(self.target),
00205         }
00206         # Turn on FPU optimizations if the core has an FPU
00207         ctx['fpu_setting'] = 1 if 'f' not in ctx['device'].core.lower() \
00208                                   or 'd' in ctx['device'].core.lower() else 2
00209         ctx.update(self.format_flags ())
00210         self.gen_file('uvision/uvision.tmpl', ctx, self.project_name+".uvprojx")
00211         self.gen_file('uvision/uvision_debug.tmpl', ctx, self.project_name + ".uvoptx")
00212 
00213     @staticmethod
00214     def build (project_name, log_name='build_log.txt', cleanup=True):
00215         """ Build Uvision project """
00216         # > UV4 -r -j0 -o [log_name] [project_name].uvprojx
00217         proj_file = project_name + ".uvprojx"
00218         cmd = ['UV4', '-r', '-j0', '-o', log_name, proj_file]
00219 
00220         # Build the project
00221         p = Popen(cmd, stdout=PIPE, stderr=PIPE)
00222         out, err = p.communicate()
00223         ret_code = p.returncode
00224 
00225         # Print the log file to stdout
00226         with open(log_name, 'r') as f:
00227             print f.read()
00228 
00229         # Cleanup the exported and built files
00230         if cleanup:
00231             os.remove(log_name)
00232             os.remove(project_name+".uvprojx")
00233             os.remove(project_name+".uvoptx")
00234             # legacy .build directory cleaned if exists
00235             if exists('.build'):
00236                 shutil.rmtree('.build')
00237             if exists('BUILD'):
00238                 shutil.rmtree('BUILD')
00239 
00240         # Returns 0 upon success, 1 upon a warning, and neither upon an error
00241         if ret_code != 0 and ret_code != 1:
00242             # Seems like something went wrong.
00243             return -1
00244         else:
00245             return 0