Lee Kai Xuan / mbed-os

Fork of mbed-os by erkin yucel

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 from distutils.spawn import find_executable
00007 import subprocess
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, FailedBuildException
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 = 'cmsis'
00121     TOOLCHAIN = 'ARM'
00122     TARGETS = [target for target, obj in TARGET_MAP.iteritems()
00123                if "ARM" in obj.supported_toolchains]
00124     #File associations within .uvprojx file
00125     file_types = {'.cpp': 8, '.c': 1, '.s': 2,
00126                   '.obj': 3, '.o': 3, '.lib': 4,
00127                   '.ar': 4, '.h': 5, '.sct': 4}
00128 
00129     def uv_file (self, loc):
00130         """Return a namedtuple of information about project file
00131         Positional Arguments:
00132         loc - the file's location
00133 
00134         .uvprojx XML for project file:
00135         <File>
00136             <FileType>{{file.type}}</FileType>
00137             <FileName>{{file.name}}</FileName>
00138             <FilePath>{{file.loc}}</FilePath>
00139         </File>
00140         """
00141         UVFile = namedtuple('UVFile', ['type','loc','name'])
00142         _, ext = os.path.splitext(loc)
00143         type = self.file_types [ext.lower()]
00144         name = ntpath.basename(normpath(loc))
00145         return UVFile(type, loc, name)
00146 
00147     def format_flags (self):
00148         """Format toolchain flags for Uvision"""
00149         flags = copy.deepcopy(self.flags)
00150         asm_flag_string = '--cpreproc --cpreproc_opts=-D__ASSERT_MSG,' + \
00151                           ",".join(flags['asm_flags'])
00152         # asm flags only, common are not valid within uvision project,
00153         # they are armcc specific
00154         flags['asm_flags'] = asm_flag_string
00155         # cxx flags included, as uvision have them all in one tab
00156         flags['c_flags'] = list(set(['-D__ASSERT_MSG']
00157                                         + flags['common_flags']
00158                                         + flags['c_flags']
00159                                         + flags['cxx_flags']))
00160         # not compatible with c99 flag set in the template
00161         try: flags['c_flags'].remove("--c99")
00162         except ValueError: pass
00163         # cpp is not required as it's implicit for cpp files
00164         try: flags['c_flags'].remove("--cpp")
00165         except ValueError: pass
00166         # we want no-vla for only cxx, but it's also applied for C in IDE,
00167         #  thus we remove it
00168         try: flags['c_flags'].remove("--no_vla")
00169         except ValueError: pass
00170         flags['c_flags'] =" ".join(flags['c_flags'])
00171         return flags
00172 
00173     def format_src (self, srcs):
00174         """Make sources into the named tuple for use in the template"""
00175         grouped = self.group_project_files(srcs)
00176         for group, files in grouped.items():
00177             grouped[group] = [self.uv_file (src) for src in files]
00178         return grouped
00179 
00180     def generate (self):
00181         """Generate the .uvproj file"""
00182         cache = Cache(True, False)
00183         if cache_d:
00184             cache.cache_descriptors()
00185 
00186         srcs = self.resources.headers + self.resources.s_sources + \
00187                self.resources.c_sources + self.resources.cpp_sources + \
00188                self.resources.objects + self.resources.libraries
00189         ctx = {
00190             'name': self.project_name,
00191             'project_files': self.format_src (srcs),
00192             'linker_script':self.resources.linker_script,
00193             'include_paths': '; '.join(self.resources.inc_dirs).encode('utf-8'),
00194             'device': DeviceUvision(self.target),
00195         }
00196         # Turn on FPU optimizations if the core has an FPU
00197         ctx['fpu_setting'] = 1 if 'f' not in ctx['device'].core.lower() \
00198                                   or 'd' in ctx['device'].core.lower() else 2
00199         ctx.update(self.format_flags ())
00200         self.gen_file('uvision/uvision.tmpl', ctx, self.project_name+".uvprojx")
00201         self.gen_file('uvision/uvision_debug.tmpl', ctx, self.project_name + ".uvoptx")
00202 
00203     def build(self):
00204         ERRORLEVEL = {
00205             0: 'success (0 warnings, 0 errors)',
00206             1: 'warnings',
00207             2: 'errors',
00208             3: 'fatal errors',
00209             11: 'cant write to project file',
00210             12: 'device error',
00211             13: 'error writing',
00212             15: 'error reading xml file',
00213         }
00214         success = 0
00215         warn  = 1
00216         if find_executable("UV4"):
00217             uv_exe = "UV4.exe"
00218         else:
00219             uv_exe = join('C:', sep,
00220             'Keil_v5', 'UV4', 'UV4.exe')
00221             if not exists(uv_exe):
00222                 raise Exception("UV4.exe not found. Add to path.")
00223         cmd = [uv_exe, '-r', '-j0', '-o', join(self.export_dir,'build_log.txt'), join(self.export_dir,self.project_name+".uvprojx")]
00224         ret_code = subprocess.call(cmd)
00225         with open(join(self.export_dir, 'build_log.txt'), 'r') as build_log:
00226             print build_log.read()
00227 
00228         if ret_code != success and ret_code != warn:
00229             # Seems like something went wrong.
00230             raise FailedBuildException("Project: %s build failed with the status: %s" % (
00231                 self.project_name, ERRORLEVEL.get(ret_code, "Unknown")))
00232         else:
00233             return "Project: %s build succeeded with the status: %s" % (
00234             self.project_name, ERRORLEVEL.get(ret_code, "Unknown"))