Knight KE / Mbed OS Game_Master
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers __init__.py Source File

__init__.py

00001 from __future__ import print_function, absolute_import
00002 from builtins import str
00003 
00004 import os
00005 from os.path import sep, normpath, join, exists
00006 import ntpath
00007 import copy
00008 from collections import namedtuple
00009 import shutil
00010 from subprocess import Popen, PIPE
00011 import re
00012 
00013 from tools.arm_pack_manager import Cache
00014 from tools.targets import TARGET_MAP
00015 from tools.export.exporters import Exporter, apply_supported_whitelist
00016 from tools.export.cmsis import DeviceCMSIS
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 
00123     POST_BINARY_WHITELIST = set([
00124         "MCU_NRF51Code.binary_hook",
00125         "TEENSY3_1Code.binary_hook",
00126         "LPCTargetCode.lpc_patch",
00127         "LPC4088Code.binary_hook",
00128         "MTSCode.combine_bins_mts_dot",
00129         "MTSCode.combine_bins_mts_dragonfly",
00130         "NCS36510TargetCode.ncs36510_addfib"
00131     ])
00132 
00133     @classmethod
00134     def is_target_supported (cls, target_name):
00135         target = TARGET_MAP[target_name]
00136         if not (set(target.supported_toolchains) and set(["ARM", "uARM"])):
00137             return False
00138         if not DeviceCMSIS.check_supported(target_name):
00139             return False
00140         if not hasattr(target, "post_binary_hook"):
00141             return True
00142         if target.post_binary_hook['function'] in cls.POST_BINARY_WHITELIST:
00143             return True
00144         else:
00145             return False
00146 
00147     #File associations within .uvprojx file
00148     file_types = {'.cpp': 8, '.c': 1, '.s': 2,
00149                   '.obj': 3, '.o': 3, '.lib': 4,
00150                   '.ar': 4, '.h': 5, '.hpp': 5, '.sct': 4}
00151 
00152     def uv_files (self, files):
00153         """An generator containing Uvision specific information about project files
00154         Positional Arguments:
00155         files - the location of source files
00156 
00157         .uvprojx XML for project file:
00158         <File>
00159             <FileType>{{file.type}}</FileType>
00160             <FileName>{{file.name}}</FileName>
00161             <FilePath>{{file.loc}}</FilePath>
00162         </File>
00163         """
00164         for loc in files:
00165             #Encapsulates the information necessary for template entry above
00166             UVFile = namedtuple('UVFile', ['type','loc','name'])
00167             _, ext = os.path.splitext(loc)
00168             if ext.lower() in self.file_types :
00169                 type = self.file_types [ext.lower()]
00170                 name = ntpath.basename(normpath(loc))
00171                 yield UVFile(type, loc, name)
00172 
00173     def format_flags (self):
00174         """Format toolchain flags for Uvision"""
00175         flags = copy.deepcopy(self.flags)
00176         # to be preprocessed with armcc
00177         asm_flag_string = (
00178             '--cpreproc --cpreproc_opts=-D__ASSERT_MSG,' +
00179             ",".join(filter(lambda f: f.startswith("-D"), flags['asm_flags'])))
00180         flags['asm_flags'] = asm_flag_string
00181         # All non-asm flags are in one template field
00182         c_flags = list(set(flags['c_flags'] + flags['cxx_flags'] +flags['common_flags']))
00183         ld_flags = list(set(flags['ld_flags'] ))
00184         # These flags are in template to be set by user i n IDE
00185         template = ["--no_vla", "--cpp", "--c99"]
00186         # Flag is invalid if set in template
00187         # Optimizations are also set in the template
00188         invalid_flag = lambda x: x in template or re.match("-O(\d|time)", x)
00189         flags['c_flags'] = [flag.replace('"','\\"') for flag in c_flags if not invalid_flag(flag)]
00190         flags['c_flags'] = " ".join(flags['c_flags'])
00191         flags['ld_flags'] = " ".join(flags['ld_flags'])
00192         return flags
00193 
00194     def format_src (self, srcs):
00195         """Make sources into the named tuple for use in the template"""
00196         grouped = self.group_project_files(srcs)
00197         for group, files in grouped.items():
00198             grouped[group] = sorted(list(self.uv_files (files)),
00199                                     key=lambda tuple: tuple[2].lower())
00200         return grouped
00201 
00202     @staticmethod
00203     def format_fpu (core):
00204         """Generate a core's FPU string"""
00205         if core.endswith("FD"):
00206             return "FPU3(DFPU)"
00207         elif core.endswith("F"):
00208             return "FPU2"
00209         else:
00210             return ""
00211 
00212     def generate (self):
00213         """Generate the .uvproj file"""
00214         cache = Cache(True, False)
00215 
00216         srcs = self.resources.headers + self.resources.s_sources + \
00217                self.resources.c_sources + self.resources.cpp_sources + \
00218                self.resources.objects + self.resources.libraries
00219         ctx = {
00220             'name': self.project_name,
00221             # project_files => dict of generators - file group to generator of
00222             # UVFile tuples defined above
00223             'project_files': sorted(list(self.format_src (srcs).items()),
00224                                     key=lambda tuple: tuple[0].lower()),
00225             'include_paths': ';'.join(self.filter_dot(d) for d in
00226                                       self.resources.inc_dirs).encode('utf-8'),
00227             'device': DeviceUvision(self.target),
00228         }
00229         sct_file = self.resources.linker_script
00230         ctx['linker_script'] = self.toolchain.correct_scatter_shebang(
00231             sct_file, self.resources.file_basepath[sct_file])
00232         if ctx['linker_script'] != sct_file:
00233             self.generated_files.append(ctx['linker_script'])
00234         core = ctx['device'].core
00235         ctx['cputype'] = core.rstrip("FD")
00236         if core.endswith("FD"):
00237             ctx['fpu_setting'] = 3
00238         elif core.endswith("F"):
00239             ctx['fpu_setting'] = 2
00240         else:
00241             ctx['fpu_setting'] = 1
00242         ctx['fputype'] = self.format_fpu (core)
00243         ctx.update(self.format_flags ())
00244         self.gen_file('uvision/uvision.tmpl', ctx, self.project_name+".uvprojx")
00245         self.gen_file('uvision/uvision_debug.tmpl', ctx, self.project_name + ".uvoptx")
00246 
00247     @staticmethod
00248     def clean (project_name):
00249         os.remove(project_name + ".uvprojx")
00250         os.remove(project_name + ".uvoptx")
00251         # legacy .build directory cleaned if exists
00252         if exists('.build'):
00253             shutil.rmtree('.build')
00254         if exists('BUILD'):
00255             shutil.rmtree('BUILD')
00256 
00257     @staticmethod
00258     def build (project_name, log_name='build_log.txt', cleanup=True):
00259         """ Build Uvision project """
00260         # > UV4 -r -j0 -o [log_name] [project_name].uvprojx
00261         proj_file = project_name + ".uvprojx"
00262         cmd = ['UV4', '-r', '-j0', '-o', log_name, proj_file]
00263 
00264         # Build the project
00265         p = Popen(cmd, stdout=PIPE, stderr=PIPE)
00266         out, err = p.communicate()
00267         ret_code = p.returncode
00268 
00269         # Print the log file to stdout
00270         with open(log_name, 'r') as f:
00271             print(f.read())
00272 
00273         # Cleanup the exported and built files
00274         if cleanup:
00275             os.remove(log_name)
00276             Uvision.clean(project_name)
00277 
00278         # Returns 0 upon success, 1 upon a warning, and neither upon an error
00279         if ret_code != 0 and ret_code != 1:
00280             # Seems like something went wrong.
00281             return -1
00282         else:
00283             return 0