def build_config(config_name, config_file, root_dir): """ Builds the configuration object @param config_name Name of the telemac configuration @param config_file Name of the configuration file @param root_dir Path to the root folder of telemac @retuns The configuration object """ # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # path to the root hometel = '' if 'HOMETEL' in environ: hometel = environ['HOMETEL'] if root_dir == '': root_dir = hometel # user configuration name usetelcfg = '' if 'USETELCFG' in environ: usetelcfg = environ['USETELCFG'] if config_name == '': config_name = usetelcfg # user configuration file systelcfg = path.join(hometel, 'configs') if 'SYSTELCFG' in environ: systelcfg = environ['SYSTELCFG'] if config_file != '': systelcfg = config_file if path.isdir(systelcfg): systelcfg = path.join(systelcfg, 'systel.cfg') config_file = systelcfg # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Works for all configurations unless specified ~~~~~~~~~~~~~~~ if not path.isfile(config_file): print '\nNot able to get to the configuration file: '\ + config_file + '\n' dircfg = path.abspath(path.dirname(config_file)) if path.isdir(dircfg): print ' ... in directory: ' + dircfg + '\n ... use instead: ' _, _, filenames = walk(dircfg).next() for fle in filenames: _, tail = path.splitext(fle) if tail == '.cfg': print ' +> ', fle raise Exception('Error in configuration file') # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Works for all configurations unless specified ~~~~~~~~~~~~~~~ cfgs = parseConfigFile(config_file, config_name) for cfgname in cfgs: # still in lower case if 'root' not in cfgs[cfgname]: cfgs[cfgname]['root'] = root_dir return cfgs
help="specify the version number, default is taken from config file" ) options, args = parser.parse_args() if not path.isfile(options.configFile): print '\nNot able to get to the configuration file: ' + options.configFile + '\n' dircfg = path.abspath(path.dirname(options.configFile)) if path.isdir(dircfg) : print ' ... in directory: ' + dircfg + '\n ... use instead: ' for dirpath,dirnames,filenames in walk(dircfg) : break for file in filenames : head,tail = path.splitext(file) if tail == '.cfg' : print ' +> ',file sys.exit() # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Works for all configurations unless specified ~~~~~~~~~~~~~~~ cfgs = parseConfigFile(options.configFile) cfgnames = cfgs.keys() if options.configName != '': if options.configName not in cfgnames: print '\nNot able to find your configuration in the configuration file: ' + options.configFile + '\n' print ' ... use instead:' for cfgname in cfgnames : print ' +> ',cfgname sys.exit() cfgnames = [options.configName] for cfgname in cfgnames: # still in lower case if options.rootDir != '': cfgs[cfgname]['root'] = path.abspath(options.rootDir) if options.version != '': cfgs[cfgname]['version'] = options.version # parsing for proper naming cfg = parseConfig_CompileTELEMAC(cfgs[cfgname])
help="specify the last frame included (negative from the end)") options, args = parser.parse_args() if not path.isfile(options.configFile): print '\nNot able to get to the configuration file: ' + options.configFile + '\n' dircfg = path.abspath(path.dirname(options.configFile)) if path.isdir(dircfg): print ' ... in directory: ' + dircfg + '\n ... use instead: ' _, _, filenames = walk(dircfg).next() for fle in filenames: head, tail = path.splitext(fle) if tail == '.cfg': print ' +> ', fle sys.exit(1) # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Works for only one configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ cfgs = parseConfigFile(options.configFile, options.configName) cfgname = cfgs.iterkeys().next() if not cfgs[cfgname].has_key('root'): cfgs[cfgname]['root'] = PWD if options.rootDir != '': cfgs[cfgname]['root'] = options.rootDir cfg = parseConfig_CompileTELEMAC(cfgs[cfgname]) # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Reads command line arguments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if len(args) < 1: print '\nAt least one DELWAQ steering file name is required\n' parser.print_help() sys.exit(1) fileNames = args # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Loop over the DELWAQ files ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def main(): """ Main program for the execution of damocles """ # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~ Reads config file ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ print '\n\nLoading Options and Configurations\n' + '~' * 72 + '\n' parser = ArgumentParser(\ formatter_class=RawDescriptionHelpFormatter, description=('''\n By Default all the documentation are generated\n use the options --validation/reference/user/release to compile only one. ''')) parser.add_argument(\ "-c", "--configname",dest="configName",default='', help="specify configuration name, default is the "\ "first found in the configuration file" ) parser.add_argument(\ "-f", "--configfile",dest="configFile",default='', help="specify configuration file, default is systel.cfg" ) parser.add_argument(\ "-r", "--root_dir",dest="root_dir",default='', help="specify the root, default is taken from config file" ) parser.add_argument(\ "-m", "--modules",dest="modules",default='', help="specify the list modules, default is taken from config file" ) parser.add_argument(\ "--dump",action="store_true",dest="dump",default=False, help="Will dump a reformated dictionary" ) parser.add_argument(\ "--eficas",action="store_true",dest="eficas",default=False, help="Will generate the eficas Catalogue from the dictionary" ) parser.add_argument(\ "--latex",action="store_true",dest="latex",default=False, help="Will generate the LaTeX file for the reference manual" ) # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ options = parser.parse_args() # path to the root PWD = path.dirname(path.dirname(path.dirname(sys.argv[0]))) if options.root_dir != '': PWD = options.root_dir # user configuration name USETELCFG = '' if 'USETELCFG' in environ: USETELCFG = environ['USETELCFG'] if options.configName == '': options.configName = USETELCFG # user configuration file SYSTELCFG = path.join(PWD, 'configs') if 'SYSTELCFG' in environ: SYSTELCFG = environ['SYSTELCFG'] if options.configFile != '': SYSTELCFG = options.configFile if path.isdir(SYSTELCFG): SYSTELCFG = path.join(SYSTELCFG, 'systel.cfg') options.configFile = SYSTELCFG # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Works for all configurations unless specified ~~~~~~~~~~~~~~~ if not path.isfile(options.configFile): print '\nNot able to get to the configuration file: %s\n' % \ options.configFile dircfg = path.abspath(path.dirname(options.configFile)) if path.isdir(dircfg): print ' ... in directory: ' + dircfg + '\n ... use instead: ' _, _, filenames = walk(dircfg).next() for fle in filenames: _, tail = path.splitext(fle) if tail == '.cfg': print ' +> ', fle sys.exit(1) # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Works for all configurations unless specified ~~~~~~~~~~~~~~~ cfgs = parseConfigFile(options.configFile, options.configName) cfgname = cfgs.iterkeys().next() # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # Defining which modules to use if options.modules is '': moduleList = [ 'artemis', 'postel3d', 'stbtel', 'sisyphe', 'telemac2d', 'telemac3d', 'tomawac', 'waqtel' ] else: moduleList = options.modules.split(';') # Identify Root value if not cfgs[cfgname].has_key('root'): cfgs[cfgname]['root'] = PWD if options.root_dir != '': cfgs[cfgname]['root'] = path.abspath(options.root_dir) root = path.abspath(options.root_dir) else: root = cfgs[cfgname]['root'] cfg = parseConfig_ValidateTELEMAC(cfgs[cfgname]) exePath = path.join(root,'builds',cfgname,\ 'bin','damocles'+\ cfg['SYSTEM']['sfx_exe']) # Looping on all modules for module in moduleList: modulePath = path.join(root, 'sources', module) if (options.dump): inputDict = path.join(modulePath, module + ".dico") outputDict = path.join(modulePath, module + "2.dico") genDump(exePath, inputDict, outputDict) if (options.eficas): inputDict = path.join(modulePath, module + ".dico") inputDep = path.join(modulePath, module + ".dico.dep") fancyModule = module[0].upper() + module[1:] cataName = path.join(modulePath, 'eficas', fancyModule + "_cata_auto.py") enumName = path.join(modulePath, 'eficas', 'enum_' + fancyModule + "_auto.py") tsPath = path.join(modulePath, 'eficas') genCata(module.upper(), exePath, inputDict, inputDep, cataName, \ enumName, tsPath+path.sep) if (options.latex): inputDict = path.join(modulePath, module + ".dico") latexName = path.join(root,'documentation',module,'reference',\ 'latex','Corpus.tex') # English only lng = '2' genLatex(exePath, inputDict, latexName, lng) # ~~~~ Compile the valiation documentation print '\n\n' + '~' * 72 # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Jenkins' success message ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ print '\n\nMy work is done\n\n' sys.exit(0)
help="specify configuration name, default is randomly found in the configuration file" ) parser.add_option("-f", "--configfile", type="string", dest="configFile", default=SYSTELCFG, help="specify configuration file, default is systel.cfg" ) options, args = parser.parse_args() if not path.isfile(options.configFile): print '\nNot able to get to the configuration file: ' + options.configFile + '\n' sys.exit() # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Works for only one configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ cfgname = options.configName if options.configName == '': cfgname = parseConfigFile(options.configFile).keys()[0] if cfgname not in parseConfigFile(options.configFile).keys(): print '\nNot able to get to find your configuration in the configuration file: ' + options.configFile + '\n' sys.exit() cfg = parseConfig_DoxygenTELEMAC(cfgname)[cfgname] # ~~ Scans all source files to build a relation database ~~ print '\n\nScanning the source code\n\ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n' fic,mdl,sbt,fct,prg,dep,all = scanSources(cfgname,cfg,False) # ~~ Scans all source files to update Doxygen ~~~~~~~~~~~~~~~~ for mod in fic.keys(): print '\nWriting out ' + mod.upper() + ' source code following standrad template format\n\ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
if path.isdir(dircfg): print ' ... in directory: ' + dircfg + '\n ... use instead: ' _, _, filenames = walk(dircfg).next() for fle in filenames: head, tail = path.splitext(fle) if tail == '.cfg': print ' +> ', fle raise Exception('Error in configuration file') # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Reporting errors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ xcpts = MESSAGES() # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Works for all configurations unless specified ~~~~~~~~~~~~~~~ cfgs = parseConfigFile(args.configFile, args.configName) if not cfgs[args.configName].has_key('root'): cfgs[args.configName]['root'] = HOMETEL if args.rootDir != '': cfgs[args.configName]['root'] = path.abspath(args.rootDir) cfg = parseConfig_RunningTELEMAC(cfgs[args.configName]) if (args.inputFile != ""): with open(args.inputFile, 'r') as f: geoFile = f.readline().strip('\n') geoFileFmt = f.readline().strip('\n') bndFile = f.readline().strip('\n') ncsize = f.readline().strip('\n') partitionningMethod = f.readline().strip('\n') sectionFile = f.readline().strip('\n') zoneFile = f.readline().strip('\n') weirFile = f.readline().strip('\n')
help="specify the version number, default is taken from config file" ) options, args = parser.parse_args() if not path.isfile(options.configFile): print '\nNot able to get to the configuration file: ' + options.configFile + '\n' dircfg = path.dirname(options.configFile) if path.isdir(dircfg) : print ' ... in directory: ' + dircfg + '\n ... use instead: ' for dirpath,dirnames,filenames in walk(dircfg) : break for file in filenames : head,tail = path.splitext(file) if tail == '.cfg' : print ' +> ',file sys.exit() # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Works for all configurations unless specified ~~~~~~~~~~~~~~~ cfgs = parseConfigFile(options.configFile) cfgnames = cfgs.keys() if options.configName != '': if options.configName not in cfgnames: print '\nNot able to find your configuration in the configuration file: ' + options.configFile + '\n' print ' ... use instead:' for cfgname in cfgnames : print ' +> ',cfgname sys.exit() cfgnames = [options.configName] # /!\ for testing purposes ... no real use for cfgname in cfgnames: # still in lower case if options.rootDir != '': cfgs[cfgname]['root'] = options.rootDir if options.version != '': cfgs[cfgname]['version'] = options.version # parsing for proper naming
config.PlacementFile = arg elif opt in ('--no-trim-gerber',): config.TrimGerber = 0 elif opt in ('--no-trim-excellon',): config.TrimExcellon = 0 else: raise RuntimeError, "Unknown option: %s" % opt if len(args) > 2 or len(args) < 1: usage() disclaimer() # Load up the Jobs global dictionary, also filling out GAT, the # global aperture table and GAMT, the global aperture macro table. config.parseConfigFile(args[0]) # Force all X and Y coordinates positive by adding absolute value of minimum X and Y for name, job in config.Jobs.iteritems(): min_x, min_y = job.mincoordinates() shift_x = shift_y = 0 if min_x < 0: shift_x = abs(min_x) if min_y < 0: shift_y = abs(min_y) if (shift_x > 0) or (shift_y > 0): job.fixcoordinates( shift_x, shift_y ) # Display job properties for job in config.Jobs.values(): print 'Job %s:' % job.name, if job.Repeat > 1: print '(%d instances)' % job.Repeat
dircfg = path.abspath(path.dirname(options.configFile)) if path.isdir(dircfg): print ' ... in directory: ' + dircfg + '\n ... use instead: ' _, _, filenames = walk(dircfg).next() for fle in filenames: head, tail = path.splitext(fle) if tail == '.cfg': print ' +> ', fle sys.exit(1) # Checking if symlink is available if (options.use_link and not checkSymLink(options.use_link)): print '\nThe symlink option is only available on Linux systems. Remove the option and try again' sys.exit(1) # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Works for all configurations unless specified ~~~~~~~~~~~~~~~ cfgs = parseConfigFile(options.configFile, USETELCFG) # /!\ yo need to validate all configuration in the config file # If USETELCFG is not defined in the environment setting USETELCFG to the first config # /!\ please do not reset the users environemnt #if 'USETELCFG' not in environ: environ['USETELCFG'] = cfgs.iterkeys().next() # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Forces not to use any Xwindows backend for Jenkins ~~~~~~~~~~ if not options.display: import matplotlib.pyplot as plt plt.switch_backend('agg') from mayavi import mlab mlab.options.offscreen = True # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Reporting errors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def main(): """ Main program for the compilation of the documentation of the telemac-mascaret system """ # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~ Reads config file ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ print '\n\nLoading Options and Configurations\n' + '~' * 72 + '\n' parser = ArgumentParser(\ formatter_class=RawDescriptionHelpFormatter, description=('''\n By Default all the documentation are generated\n use the options --validation/reference/user/release to compile only one ''')) parser.add_argument(\ "-c", "--configname",dest="configName",default='', help="specify configuration name, default is the "\ "first found in the configuration file" ) parser.add_argument(\ "-f", "--configfile",dest="configFile",default='', help="specify configuration file, default is systel.cfg" ) parser.add_argument(\ "-r", "--root_dir",dest="root_dir",default='', help="specify the root, default is taken from config file" ) parser.add_argument(\ "-m", "--modules",dest="modules",default='', help="specify the list modules, default is taken from config file" ) parser.add_argument(\ "-M", "--misc",dest="misc",default='', help="specify the list of misc documentation to compile, "\ "default is all of them" ) parser.add_argument(\ "--validation",action="store_true",dest="validation",default=False, help="Will generate the validation documentation" ) parser.add_argument(\ "--case-list",dest="caseList",default='', help="List of cas to include in the validation documentation"\ "separated by ',' (default all of them)" ) parser.add_argument(\ "--reference",action="store_true",dest="reference",default=False, help="Will generate the reference documentation" ) parser.add_argument(\ "--user",action="store_true",dest="user",default=False, help="Will generate the user documentation" ) parser.add_argument(\ "--release",action="store_true",dest="release_note",default=False, help="Will generate the release note" ) parser.add_argument(\ "--clean",action="store_true",dest="cleanup",default=False, help="Will remove all temporary file "\ "generated by pdflatex" ) parser.add_argument(\ "--fullclean",action="store_true",dest="fullcleanup",default=False, help="Same as clean but removes the pdf as well" ) # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ options = parser.parse_args() # path to the root PWD = path.dirname(path.dirname(path.dirname(sys.argv[0]))) if options.root_dir != '': PWD = options.root_dir # user configuration name USETELCFG = '' if 'USETELCFG' in environ: USETELCFG = environ['USETELCFG'] if options.configName == '': options.configName = USETELCFG # user configuration file SYSTELCFG = path.join(PWD, 'configs') if 'SYSTELCFG' in environ: SYSTELCFG = environ['SYSTELCFG'] if options.configFile != '': SYSTELCFG = options.configFile if path.isdir(SYSTELCFG): SYSTELCFG = path.join(SYSTELCFG, 'systel.cfg') options.configFile = SYSTELCFG # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Works for all configurations unless specified ~~~~~~~~~~~~~~~ if not path.isfile(options.configFile): print '\nNot able to get to the configuration file: %s\n' % \ options.configFile dircfg = path.abspath(path.dirname(options.configFile)) if path.isdir(dircfg): print ' ... in directory: ' + dircfg + '\n ... use instead: ' _, _, filenames = walk(dircfg).next() for fle in filenames: _, tail = path.splitext(fle) if tail == '.cfg': print ' +> ', fle sys.exit(1) # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Works for all configurations unless specified ~~~~~~~~~~~~~~~ cfgs = parseConfigFile(options.configFile, options.configName) cfgname = cfgs.iterkeys().next() # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Compile the valiation documentation doall = not (options.validation or options.user or options.reference or options.release_note) for cfgname in cfgs: # still in lower case if not cfgs[cfgname].has_key('root'): cfgs[cfgname]['root'] = PWD if options.root_dir != '': cfgs[cfgname]['root'] = path.abspath(options.root_dir) root = path.abspath(options.root_dir) else: root = cfgs[cfgname]['root'] # Get what i to be compiled # By default everything if something is defined compiling only that if options.modules != '': moduleList = options.modules.split(',') else: # all modules moduleList = [ 'artemis', 'postel3d', 'stbtel', 'sisyphe', 'telemac2d', 'telemac3d', 'tomawac', 'waqtel' ] if options.misc != '': miscList = options.misc.split(',') moduleList = [] else: # all docs miscList = [ 'developer_guide', 'software_quality_plan', 'TelemacDocTemplate' ] # If a module was specified or a specific documentation for modules # not compiling Misc documentation if options.modules != '' or not doall: miscList = [] cfg = parseConfig_ValidateTELEMAC(cfgs[cfgname]) # Loop on all the modules # Get version in config if it exist use trunk otherwise version = cfgs[cfgname].get('version', 'trunk') # Initialise output message output_mess = '\n\n' # Look on all the modules for the documentation for code_name in moduleList: print '\nCompilation of the documentation for '+ code_name + \ '\n'+'~'*72 # list of what to do for the module todo = [] if (options.validation or doall): # Building Validation LaTeX file doc_dir = path.join(root,'documentation',\ code_name,'validation') chdir(doc_dir) if options.caseList != '': listOfCase = options.caseList.split(',') else: listOfCase = cfg['VALIDATION'][code_name].keys() listOfCase.remove('path') skipedCase = create_case_list_file(doc_dir, \ cfg['VALIDATION'][code_name]['path'],\ listOfCase,\ options.cleanup or options.fullcleanup) for case in skipedCase: output_mess += ' - /!\ Missing LaTeX file for ' + case + '\n' todo.append('validation') if (options.reference or doall): # Path to the dictionary dictionary = path.join(root,'sources',code_name,\ code_name+'.dico') # Path to latex File latexFile = path.join(root,'documentation',\ code_name,'reference',\ 'latex','Corpus.tex') # English only for now lng = '2' # Path to bin directory exePath = path.join(root,'builds',cfgname,\ 'bin','damocles'+\ cfg['SYSTEM']['sfx_exe']) generate_ref_from_dict(exePath,dictionary,latexFile,lng,\ options.cleanup or options.fullcleanup) todo.append('reference') if (options.user or doall): # Normal Compilation of a LaTeX file todo.append('user') if (options.release_note or doall): todo.append('release_note') for doc_type in todo: doc_dir = path.join(root,'documentation',\ code_name,doc_type) chdir(doc_dir) # Check if the file exist if path.exists(path.join(doc_dir,\ code_name + "_" + doc_type + ".tex")): compile_doc(doc_dir, code_name + '_' + doc_type, version, options.cleanup, options.fullcleanup) else: print " - Error for %s %s, %s.tex not found " % \ (path.basename(doc_dir), code_name+"_"+doc_type) sys.exit(1) if not (options.cleanup or options.fullcleanup): output_mess += ' - Created %s_%s_%s.pdf\n' % \ (code_name, doc_type, version) # List of the other documentation for doc in miscList: print '\nCompilation of the documentation for '+ doc + \ '\n'+'~'*72 doc_dir = path.join(root,'documentation',\ 'Misc',doc) chdir(doc_dir) if path.exists(path.join(doc_dir, doc + ".tex")): compile_doc(doc_dir, doc, version, options.cleanup, options.fullcleanup) else: print " - Error in %s, %s.tex not found " % \ (path.basename(doc_dir), doc) sys.exit(1) if not (options.cleanup or options.fullcleanup): output_mess += ' - Created %s_%s.pdf\n' % \ (doc, version) print output_mess print '\n\n' + '~' * 72 # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Jenkins' success message ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ print '\n\nMy work is done\n\n' sys.exit(0)
help="specify configuration name, default is randomly found in the configuration file" ) parser.add_option("-f", "--configfile", type="string", dest="configFile", default=SYSTELCFG, help="specify configuration file, default is systel.cfg" ) options, args = parser.parse_args() if not path.isfile(options.configFile): print '\nNot able to get to the configuration file: ' + options.configFile + '\n' sys.exit() # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Works for only one configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ cfgname = options.configName if options.configName == '': cfgname = parseConfigFile(options.configFile).keys()[0] if cfgname not in parseConfigFile(options.configFile).keys(): print '\nNot able to get to find your configurtaion in the configuration file: ' + options.configFile + '\n' sys.exit() cfg = parseConfig_TranslateTELEMAC(cfgname)[cfgname] MODULES = {} for mod in cfg['MODULES'].keys(): if mod in cfg['COMPILER']['MODULES']: files = getTheseFiles(path.join(cfg['MODULES'][mod]['path'],'sources'),['.f']) if files != []: MODULES.update({mod:cfg['MODULES'][mod]}) MODULES[mod].update({'sources':files}) app = QtGui.QApplication(sys.argv)
def merge(opts, gui=None): global GUI GUI = gui if opts.octagons == 'rotate': writeGerberHeader = gerber.writeHeader0degrees else: writeGerberHeader = gerber.writeHeader22degrees if opts.search == 'random': config.AutoSearchType = RANDOM_SEARCH else: config.AutoSearchType = EXHAUSTIVE_SEARCH config.RandomSearchExhaustiveJobs = opts.rs_esjobs config.SearchTimeout = opts.search_timeout if opts.no_trim_gerber: config.TrimGerber = False if opts.no_trim_excellon: config.TrimExcellon = False config.text = opts.text config.text_size = opts.text_size config.text_stroke = opts.text_stroke config.text_x = opts.text_x config.text_y = opts.text_y # Load up the Jobs global dictionary, also filling out GAT, the # global aperture table and GAMT, the global aperture macro table. updateGUI("Reading job files...") config.parseConfigFile(opts.configfile) # Force all X and Y coordinates positive by adding absolute value of minimum X and Y for name, job in config.Jobs.items(): min_x, min_y = job.mincoordinates() shift_x = shift_y = 0 if min_x < 0: shift_x = abs(min_x) if min_y < 0: shift_y = abs(min_y) if (shift_x > 0) or (shift_y > 0): job.fixcoordinates(shift_x, shift_y) # Display job properties for job in config.Jobs.values(): print("Job {:s}:".format(job.name)) if job.Repeat > 1: print("({:d} instances)".format(job.Repeat)) else: print() print(" Extents: ({:d},{:d})-({:d},{:d})".format(job.minx, job.miny, job.maxx, job.maxy)) print(" Size: {:f}\" x {:f}\"".format(job.width_in(), job.height_in())) print() # Trim drill locations and flash data to board extents if config.TrimExcellon: updateGUI("Trimming Excellon data...") print("Trimming Excellon data to board outlines ...") for job in config.Jobs.values(): job.trimExcellon() if config.TrimGerber: updateGUI("Trimming Gerber data...") print("Trimming Gerber data to board outlines ...") for job in config.Jobs.values(): job.trimGerber() # We start origin at (0.1", 0.1") just so we don't get numbers close to 0 # which could trip up Excellon leading-0 elimination. OriginX = OriginY = 0.1 # Read the layout file and construct the nested list of jobs. If there # is no layout file, do auto-layout. updateGUI("Performing layout...") print("Performing layout ...") if opts.layoutfile: # Construct a canonical placement from the manual layout (relative or absolute) Place = placement.Placement() Place.addFromFile(opts.layoutfile, OriginX + config.Config['leftmargin'], OriginY + config.Config['bottommargin']) else: # Do an automatic layout based on our tiling algorithm. tile = tile_jobs(config.Jobs.values()) Place = placement.Placement() Place.addFromTiling(tile, OriginX + config.Config['leftmargin'], OriginY + config.Config['bottommargin']) (MaxXExtent, MaxYExtent) = Place.extents() MaxXExtent += config.Config['rightmargin'] MaxYExtent += config.Config['topmargin'] # Start printing out the Gerbers. In preparation for drawing cut marks # and crop marks, make sure we have an aperture to draw with. Use a 10mil line. # If we're doing a fabrication drawing, we'll need a 1mil line. OutputFiles = [] try: fullname = config.MergeOutputFiles['placement'] except KeyError: fullname = 'merged.placement.xml' Place.write(fullname) OutputFiles.append(fullname) # For cut lines AP = aptable.Aperture(aptable.Circle, 'D??', config.Config['cutlinewidth']) drawing_code_cut = aptable.findInApertureTable(AP, config.GAT) if drawing_code_cut is None: drawing_code_cut = aptable.addToApertureTable(AP, config.GAT) # For crop marks AP = aptable.Aperture(aptable.Circle, 'D??', config.Config['cropmarkwidth']) drawing_code_crop = aptable.findInApertureTable(AP, config.GAT) if drawing_code_crop is None: drawing_code_crop = aptable.addToApertureTable(AP, config.GAT) # For fiducials drawing_code_fiducial_copper = drawing_code_fiducial_soldermask = None if config.Config['fiducialpoints']: AP = aptable.Aperture(aptable.Circle, 'D??', config.Config['fiducialcopperdiameter']) drawing_code_fiducial_copper = aptable.findInApertureTable(AP, config.GAT) if drawing_code_fiducial_copper is None: drawing_code_fiducial_copper = aptable.addToApertureTable(AP, config.GAT) AP = aptable.Aperture(aptable.Circle, 'D??', config.Config['fiducialmaskdiameter']) drawing_code_fiducial_soldermask = aptable.findInApertureTable(AP, config.GAT) if drawing_code_fiducial_soldermask is None: drawing_code_fiducial_soldermask = aptable.addToApertureTable(AP, config.GAT) if config.text: text_size_ratio = 0.5 # proportion of Y spacing to use for text (much of this is taken up by, e.g., cutlines) if not config.text_size: print("Computing text size based on Y spacing...") text_size = config.text_size if config.text_size else (config.Config['yspacing'] * 1000.0) * text_size_ratio if text_size < config.min_text_size: print("Warning: Text size ({0} mils) less than minimum ({1} mils), using minimum.".format(text_size, config.min_text_size)) text_size = max(text_size, config.min_text_size) print("Using text size: {0} mils".format(text_size)) # by default, set stroke proportional to the size based on the ratio of the minimum stroke to the minimum size if not config.text_stroke: print("Computing text stroke based on text size...") text_stroke = config.text_stroke if config.text_stroke else int((text_size / config.min_text_size) * config.min_text_stroke) if text_stroke < config.min_text_stroke: print("Warning: Text stroke ({0} mils) less than minimum ({1} mils), using minimum.".format(text_stroke, config.min_text_stroke)) text_stroke = max(text_stroke, config.min_text_stroke) print("Using text stroke: {0} mils".format(text_stroke)) AP = aptable.Aperture(aptable.Circle, 'D??', text_stroke / 1000.0) drawing_code_text = aptable.findInApertureTable(AP, config.GAT) if drawing_code_text is None: drawing_code_text = aptable.addToApertureTable(AP, config.GAT) # For fabrication drawing. AP = aptable.Aperture(aptable.Circle, 'D??', 0.001) drawing_code1 = aptable.findInApertureTable(AP, config.GAT) if drawing_code1 is None: drawing_code1 = aptable.addToApertureTable(AP, config.GAT) updateGUI("Writing merged files...") print("Writing merged output files ...") for layername in config.LayerList.keys(): lname = layername if lname[0] == '*': lname = lname[1:] try: fullname = config.MergeOutputFiles[layername] except KeyError: fullname = "merged.{:s}.ger".format(lname) OutputFiles.append(fullname) fid = open(fullname, 'wt') writeGerberHeader(fid) # Determine which apertures and macros are truly needed apUsedDict = {} apmUsedDict = {} for job in Place.jobs: apd, apmd = job.aperturesAndMacros(layername) apUsedDict.update(apd) apmUsedDict.update(apmd) # Increase aperature sizes to match minimum feature dimension if layername in config.MinimumFeatureDimension: print(" Thickening", lname, "feature dimensions ...") # Fix each aperture used in this layer for ap in list(apUsedDict.keys()): new = config.GAT[ap].getAdjusted(config.MinimumFeatureDimension[layername]) if not new: # current aperture size met minimum requirement continue else: # new aperture was created new_code = aptable.findOrAddAperture(new, config.GAT) # get name of existing aperture or create new one if needed del apUsedDict[ap] # the old aperture is no longer used in this layer apUsedDict[new_code] = None # the new aperture will be used in this layer # Replace all references to the old aperture with the new one for joblayout in Place.jobs: job = joblayout.job # access job inside job layout temp = [] if job.hasLayer(layername): for x in job.commands[layername]: if x == ap: temp.append(new_code) # replace old aperture with new one else: temp.append(x) # keep old command job.commands[layername] = temp if config.Config['cutlinelayers'] and (layername in config.Config['cutlinelayers']): apUsedDict[drawing_code_cut] = None if config.Config['cropmarklayers'] and (layername in config.Config['cropmarklayers']): apUsedDict[drawing_code_crop] = None if config.Config['fiducialpoints']: if ((layername == '*toplayer') or (layername == '*bottomlayer')): apUsedDict[drawing_code_fiducial_copper] = None elif ((layername == '*topsoldermask') or (layername == '*bottomsoldermask')): apUsedDict[drawing_code_fiducial_soldermask] = None if config.text: apUsedDict[drawing_code_text] = None # Write only necessary macro and aperture definitions to Gerber file gerber.writeApertureMacros(fid, apmUsedDict) gerber.writeApertures(fid, apUsedDict) # Finally, write actual flash data for job in Place.jobs: updateGUI("Writing merged output files...") job.writeGerber(fid, layername) if config.Config['cutlinelayers'] and (layername in config.Config['cutlinelayers']): fid.write("{:s}*\n".format(drawing_code_cut)) # Choose drawing aperture job.writeCutLines(fid, drawing_code_cut, OriginX, OriginY, MaxXExtent, MaxYExtent) if config.Config['cropmarklayers']: if layername in config.Config['cropmarklayers']: gerber.writeCropMarks(fid, drawing_code_crop, OriginX, OriginY, MaxXExtent, MaxYExtent) if config.Config['fiducialpoints']: if ((layername == '*toplayer') or (layername == '*bottomlayer')): gerber.writeFiducials(fid, drawing_code_fiducial_copper, OriginX, OriginY, MaxXExtent, MaxYExtent) elif ((layername == '*topsoldermask') or (layername == '*bottomsoldermask')): gerber.writeFiducials(fid, drawing_code_fiducial_soldermask, OriginX, OriginY, MaxXExtent, MaxYExtent) if config.Config['outlinelayers'] and (layername in config.Config['outlinelayers']): gerber.writeOutline(fid, OriginX, OriginY, MaxXExtent, MaxYExtent) if config.text: Y += row.height_in() + config.Config['yspacing'] x = config.text_x if config.text_x else util.in2mil(OriginX + config.Config['leftmargin']) + 100 # convert inches to mils 100 is extra margin y_offset = ((config.Config['yspacing'] * 1000.0) - text_size) / 2.0 y = config.text_y if config.text_y else util.in2mil(OriginY + config.Config['bottommargin'] + Place.jobs[0].height_in()) + y_offset # convert inches to mils fid.write("{:s}*\n".format(drawing_code_text)) # Choose drawing aperture makestroke.writeString(fid, config.text, int(util.mil2gerb(x)), int(util.mil2gerb(y)), 0, int(text_size)) gerber.writeFooter(fid) fid.close() # Write board outline layer if selected fullname = config.Config['outlinelayerfile'] if fullname and fullname.lower() != "none": OutputFiles.append(fullname) fid = open(fullname, 'wt') writeGerberHeader(fid) gerber.writeOutline(fid, OriginX, OriginY, MaxXExtent, MaxYExtent) gerber.writeFooter(fid) fid.close() # Write scoring layer if selected fullname = config.Config['scoringfile'] if fullname and fullname.lower() != "none": OutputFiles.append(fullname) fid = open(fullname, 'wt') writeGerberHeader(fid) # Write width-1 aperture to file AP = aptable.Aperture(aptable.Circle, 'D10', 0.001) AP.writeDef(fid) # Choose drawing aperture D10 gerber.writeCurrentAperture(fid, 10) # Draw the scoring lines scoring.writeScoring(fid, Place, OriginX, OriginY, MaxXExtent, MaxYExtent, config.Config['xspacing'], config.Config['yspacing']) gerber.writeFooter(fid) fid.close() # Get a list of all tools used by merging keys from each job's dictionary # of tools. # Grab all tool diameters and sort them. allToolDiam = [] for job in config.Jobs.values(): for tool, diam in job.xdiam.items(): if diam in config.GlobalToolRMap: continue allToolDiam.append(diam) allToolDiam.sort() # Then construct global mapping of diameters to tool numbers toolNum = 1 for d in allToolDiam: config.GlobalToolRMap[d] = "T{:02d}".format(toolNum) toolNum += 1 # Cluster similar tool sizes to reduce number of drills if config.Config['drillclustertolerance'] > 0: config.GlobalToolRMap = drillcluster.cluster(config.GlobalToolRMap, config.Config['drillclustertolerance']) drillcluster.remap(Place.jobs, list(config.GlobalToolRMap.items())) # Now construct mapping of tool numbers to diameters for diam, tool in config.GlobalToolRMap.items(): config.GlobalToolMap[tool] = diam # Tools is just a list of tool names Tools = list(config.GlobalToolMap.keys()) Tools.sort() fullname = config.Config['fabricationdrawingfile'] if fullname and fullname.lower() != 'none': if len(Tools) > strokes.MaxNumDrillTools: raise RuntimeError("Only {:d} different tool sizes supported for fabrication drawing.".format(strokes.MaxNumDrillTools)) OutputFiles.append(fullname) fid = open(fullname, 'wt') writeGerberHeader(fid) gerber.writeApertures(fid, {drawing_code1: None}) fid.write("{:s}*\n".format(drawing_code1)) # Choose drawing aperture fabdrawing.writeFabDrawing(fid, Place, Tools, OriginX, OriginY, MaxXExtent, MaxYExtent) gerber.writeFooter(fid) fid.close() # Finally, print out the Excellon try: fullname = config.MergeOutputFiles['drills'] except KeyError: fullname = "merged.drills.xln" OutputFiles.append(fullname) fid = open(fullname, 'wt') excellon.writeheader(fid, [(x, config.GlobalToolMap[x]) for x in Tools], units='in') # Ensure each one of our tools is represented in the tool list specified # by the user. for tool in Tools: try: size = config.GlobalToolMap[tool] except: raise RuntimeError("INTERNAL ERROR: Tool code {:s} not found in global tool map".format(tool)) # Write the tool name then all of the positions where it will be drilled. excellon.writetoolname(fid, tool) for job in Place.jobs: job.writeExcellon(fid, size) excellon.writefooter(fid) fid.close() updateGUI("Closing files...") # Compute stats jobarea = 0.0 for job in Place.jobs: jobarea += job.jobarea() totalarea = ((MaxXExtent - OriginX) * (MaxYExtent - OriginY)) ToolStats = {} drillhits = 0 for tool in Tools: ToolStats[tool] = 0 for job in Place.jobs: hits = job.drillhits(config.GlobalToolMap[tool]) ToolStats[tool] += hits drillhits += hits try: fullname = config.MergeOutputFiles['toollist'] except KeyError: fullname = "merged.toollist.drl" OutputFiles.append(fullname) fid = open(fullname, 'wt') print('-' * 50) print(" Job Size : {:f}\" x {:f}\"".format(MaxXExtent - OriginX, MaxYExtent - OriginY)) print(" Job Area : {:.2f} sq. in.".format(totalarea)) print(" Area Usage : {:.1f}%".format(jobarea / totalarea * 100)) print(" Drill hits : {:d}".format(drillhits)) print("Drill density : {:.1f} hits/sq.in.".format(drillhits / totalarea)) print("\nTool List:") smallestDrill = 999.9 for tool in Tools: if ToolStats[tool]: fid.write("{:s} {:.4f}in\n".format(tool, config.GlobalToolMap[tool])) print(" {:s} {:.4f}\" {:5d} hits".format(tool, config.GlobalToolMap[tool], ToolStats[tool])) smallestDrill = min(smallestDrill, config.GlobalToolMap[tool]) fid.close() print("Smallest Tool: {:.4f}in".format(smallestDrill)) print() print("Output Files :") for f in OutputFiles: print(" ", f) if (MaxXExtent - OriginX) > config.Config['panelwidth'] or (MaxYExtent - OriginY) > config.Config['panelheight']: print('*' * 75) print("*") print("* ERROR: Merged job {:.3f}\"x{:.3f}\" exceeds panel dimensions of {:.3f}\"x{:.3f}\"".format(MaxXExtent - OriginX, MaxYExtent - OriginY, config.Config['panelwidth'], config.Config['panelheight'])) print("*") print('*' * 75) sys.exit(1) # Done! return 0
parser.add_option("--stop",type="string",dest="tstop",default="-1",help="specify the last frame included (negative from the end)" ) options, args = parser.parse_args() if not path.isfile(options.configFile): print '\nNot able to get to the configuration file: ' + options.configFile + '\n' dircfg = path.abspath(path.dirname(options.configFile)) if path.isdir(dircfg) : print ' ... in directory: ' + dircfg + '\n ... use instead: ' _, _, filenames = walk(dircfg).next() for fle in filenames : head,tail = path.splitext(fle) if tail == '.cfg' : print ' +> ',fle sys.exit(1) # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Works for only one configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ cfgs = parseConfigFile(options.configFile,options.configName) cfgname = cfgs.iterkeys().next() if not cfgs[cfgname].has_key('root'): cfgs[cfgname]['root'] = PWD if options.rootDir != '': cfgs[cfgname]['root'] = options.rootDir cfg = parseConfig_CompileTELEMAC(cfgs[cfgname]) # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Reads command line arguments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if len(args) < 1: print '\nAt least one DELWAQ steering file name is required\n' parser.print_help() sys.exit(1) fileNames = args # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Loop over the DELWAQ files ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
config.PlacementFile = arg elif opt in ('--no-trim-gerber', ): config.TrimGerber = 0 elif opt in ('--no-trim-excellon', ): config.TrimExcellon = 0 else: raise RuntimeError, "Unknown option: %s" % opt if len(args) > 2 or len(args) < 1: usage() disclaimer() # Load up the Jobs global dictionary, also filling out GAT, the # global aperture table and GAMT, the global aperture macro table. config.parseConfigFile(args[0]) # Force all X and Y coordinates positive by adding absolute value of minimum X and Y for name, job in config.Jobs.iteritems(): min_x, min_y = job.mincoordinates() shift_x = shift_y = 0 if min_x < 0: shift_x = abs(min_x) if min_y < 0: shift_y = abs(min_y) if (shift_x > 0) or (shift_y > 0): job.fixcoordinates(shift_x, shift_y) # Display job properties for job in config.Jobs.values(): print 'Job %s:' % job.name, if job.Repeat > 1: print '(%d instances)' % job.Repeat
def merge(opts, args, gui=None): writeGerberHeader = writeGerberHeader22degrees global GUI GUI = gui skipDisclaimer = 0 for opt, arg in opts: if opt in ('--octagons', ): if arg == 'rotate': writeGerberHeader = writeGerberHeader0degrees elif arg == 'normal': writeGerberHeader = writeGerberHeader22degrees else: raise RuntimeError, 'Unknown octagon format' elif opt in ('--random-search', ): config.AutoSearchType = RANDOM_SEARCH elif opt in ('--full-search', ): config.AutoSearchType = EXHAUSTIVE_SEARCH elif opt in ('--rs-fsjobs', ): config.RandomSearchExhaustiveJobs = int(arg) elif opt in ('--search-timeout', ): config.SearchTimeout = int(arg) elif opt in ('--place-file', ): config.AutoSearchType = FROM_FILE config.PlacementFile = arg elif opt in ('--no-trim-gerber', ): config.TrimGerber = 0 elif opt in ('--no-trim-excellon', ): config.TrimExcellon = 0 elif opt in ('-s', '--skipdisclaimer'): skipDisclaimer = 1 else: raise RuntimeError, "Unknown option: %s" % opt if len(args) > 2 or len(args) < 1: raise RuntimeError, 'Invalid number of arguments' if (skipDisclaimer == 0): disclaimer() # Load up the Jobs global dictionary, also filling out GAT, the # global aperture table and GAMT, the global aperture macro table. updateGUI("Reading job files...") config.parseConfigFile(args[0]) # Display job properties for job in config.Jobs.values(): print 'Job %s:' % job.name, if job.Repeat > 1: print '(%d instances)' % job.Repeat else: print print ' Extents: (%d,%d)-(%d,%d)' % (job.minx, job.miny, job.maxx, job.maxy) # add metric support (1/1000 mm vs. 1/100,000 inch) if config.Config['measurementunits'] == 'inch': print ' Size: %f" x %f"' % (job.width_in(), job.height_in()) else: print ' Size: %5.3fmm x %5.3fmm' % (job.width_in(), job.height_in()) print # Trim drill locations and flash data to board extents if config.TrimExcellon: updateGUI("Trimming Excellon data...") print 'Trimming Excellon data to board outlines ...' for job in config.Jobs.values(): job.trimExcellon() if config.TrimGerber: updateGUI("Trimming Gerber data...") print 'Trimming Gerber data to board outlines ...' for job in config.Jobs.values(): job.trimGerber() # We start origin at (0.1", 0.1") just so we don't get numbers close to 0 # which could trip up Excellon leading-0 elimination. # I don't want to change the origin. If this a code bug, then it should be fixed (SDD) OriginX = OriginY = 0 #0.1 # Read the layout file and construct the nested list of jobs. If there # is no layout file, do auto-layout. updateGUI("Performing layout...") print 'Performing layout ...' if len(args) > 1: Layout = parselayout.parseLayoutFile(args[1]) # Do the layout, updating offsets for each component job. X = OriginX + config.Config['leftmargin'] Y = OriginY + config.Config['bottommargin'] for row in Layout: row.setPosition(X, Y) Y += row.height_in() + config.Config['yspacing'] # Construct a canonical placement from the layout Place = placement.Placement() Place.addFromLayout(Layout) del Layout elif config.AutoSearchType == FROM_FILE: Place = placement.Placement() Place.addFromFile(config.PlacementFile, config.Jobs) else: # Do an automatic layout based on our tiling algorithm. tile = tile_jobs(config.Jobs.values()) Place = placement.Placement() Place.addFromTiling(tile, OriginX + config.Config['leftmargin'], OriginY + config.Config['bottommargin']) (MaxXExtent, MaxYExtent) = Place.extents() MaxXExtent += config.Config['rightmargin'] MaxYExtent += config.Config['topmargin'] # Start printing out the Gerbers. In preparation for drawing cut marks # and crop marks, make sure we have an aperture to draw with. Use a 10mil line. # If we're doing a fabrication drawing, we'll need a 1mil line. OutputFiles = [] try: fullname = config.MergeOutputFiles['placement'] except KeyError: fullname = 'merged.placement.txt' Place.write(fullname) OutputFiles.append(fullname) # For cut lines AP = aptable.Aperture(aptable.Circle, 'D??', config.Config['cutlinewidth']) drawing_code_cut = aptable.findInApertureTable(AP) if drawing_code_cut is None: drawing_code_cut = aptable.addToApertureTable(AP) # For score lines AP = aptable.Aperture(aptable.Circle, 'D??', config.Config['scoringlinewidth']) drawing_code_score = aptable.findInApertureTable(AP) if drawing_code_score is None: drawing_code_score = aptable.addToApertureTable(AP) # For crop marks AP = aptable.Aperture(aptable.Circle, 'D??', config.Config['cropmarkwidth']) drawing_code_crop = aptable.findInApertureTable(AP) if drawing_code_crop is None: drawing_code_crop = aptable.addToApertureTable(AP) # For fiducials drawing_code_fiducial_copper = drawing_code_fiducial_soldermask = None if config.Config['fiducialpoints']: AP = aptable.Aperture(aptable.Circle, 'D??', config.Config['fiducialcopperdiameter']) drawing_code_fiducial_copper = aptable.findInApertureTable(AP) if drawing_code_fiducial_copper is None: drawing_code_fiducial_copper = aptable.addToApertureTable(AP) AP = aptable.Aperture(aptable.Circle, 'D??', config.Config['fiducialmaskdiameter']) drawing_code_fiducial_soldermask = aptable.findInApertureTable(AP) if drawing_code_fiducial_soldermask is None: drawing_code_fiducial_soldermask = aptable.addToApertureTable(AP) # For fabrication drawing. AP = aptable.Aperture(aptable.Circle, 'D??', 0.001) drawing_code1 = aptable.findInApertureTable(AP) if drawing_code1 is None: drawing_code1 = aptable.addToApertureTable(AP) updateGUI("Writing merged files...") print 'Writing merged output files ...' for layername in config.LayerList.keys(): lname = layername if lname[0] == '*': lname = lname[1:] try: fullname = config.MergeOutputFiles[layername] except KeyError: fullname = 'merged.%s.ger' % lname OutputFiles.append(fullname) #print 'Writing %s ...' % fullname fid = file(fullname, 'wt') writeGerberHeader(fid) # Determine which apertures and macros are truly needed apUsedDict = {} apmUsedDict = {} for job in Place.jobs: apd, apmd = job.aperturesAndMacros(layername) apUsedDict.update(apd) apmUsedDict.update(apmd) # Increase aperature sizes to match minimum feature dimension if config.MinimumFeatureDimension.has_key(layername): print ' Thickening', lname, 'feature dimensions ...' # Fix each aperture used in this layer for ap in apUsedDict.keys(): new = config.GAT[ap].getAdjusted( config.MinimumFeatureDimension[layername]) if not new: ## current aperture size met minimum requirement continue else: ## new aperture was created new_code = aptable.findOrAddAperture( new ) ## get name of existing aperture or create new one if needed del apUsedDict[ ap] ## the old aperture is no longer used in this layer apUsedDict[ new_code] = None ## the new aperture will be used in this layer # Replace all references to the old aperture with the new one for joblayout in Place.jobs: job = joblayout.job ##access job inside job layout temp = [] if job.hasLayer(layername): for x in job.commands[layername]: if x == ap: temp.append( new_code ) ## replace old aperture with new one else: temp.append(x) ## keep old command job.commands[layername] = temp if config.Config['cutlinelayers'] and ( layername in config.Config['cutlinelayers']): apUsedDict[drawing_code_cut] = None if config.Config['scoringlinelayers'] and ( layername in config.Config['scoringlinelayers']): apUsedDict[drawing_code_score] = None if config.Config['cropmarklayers'] and ( layername in config.Config['cropmarklayers']): apUsedDict[drawing_code_crop] = None if config.Config['fiducialpoints']: if ((layername == '*toplayer') or (layername == '*bottomlayer')): apUsedDict[drawing_code_fiducial_copper] = None elif ((layername == '*topsoldermask') or (layername == '*bottomsoldermask')): apUsedDict[drawing_code_fiducial_soldermask] = None # Write only necessary macro and aperture definitions to Gerber file writeApertureMacros(fid, apmUsedDict) writeApertures(fid, apUsedDict) #for row in Layout: # row.writeGerber(fid, layername) # # Do cut lines # if config.Config['cutlinelayers'] and (layername in config.Config['cutlinelayers']): # fid.write('%s*\n' % drawing_code_cut) # Choose drawing aperture # row.writeCutLines(fid, drawing_code_cut, OriginX, OriginY, MaxXExtent, MaxYExtent) # Finally, write actual flash data for job in Place.jobs: updateGUI("Writing merged output files...") job.writeGerber(fid, layername) if config.Config['cutlinelayers'] and ( layername in config.Config['cutlinelayers']): fid.write('%s*\n' % drawing_code_cut) # Choose drawing aperture #print "writing drawcode_cut: %s" % drawing_code_cut job.writeCutLines(fid, drawing_code_cut, OriginX, OriginY, MaxXExtent, MaxYExtent) # Draw the scoring lines if config.Config['scoringlinelayers'] and layername in config.Config[ 'scoringlinelayers']: fid.write('%s*\n' % drawing_code_score) # Choose scoring aperture scoring.writeScoring(fid, Place, OriginX, OriginY, MaxXExtent, MaxYExtent) if config.Config['cropmarklayers']: if layername in config.Config['cropmarklayers']: writeCropMarks(fid, drawing_code_crop, OriginX, OriginY, MaxXExtent, MaxYExtent) if config.Config['fiducialpoints']: # If we are generating fiducials along the score lines, # and we have not yet done so, we need to generate those now, pass in None as the file # to prevent it actually writing out scoring lines and just generate the fiducials if config.Config['fiducialpoints'] == 'scoring': scoring.writeScoring(None, Place, OriginX, OriginY, MaxXExtent, MaxYExtent) if ((layername == '*toplayer') or (layername == '*bottomlayer')): writeFiducials(fid, drawing_code_fiducial_copper, OriginX, OriginY, MaxXExtent, MaxYExtent) elif ((layername == '*topsoldermask') or (layername == '*bottomsoldermask')): writeFiducials(fid, drawing_code_fiducial_soldermask, OriginX, OriginY, MaxXExtent, MaxYExtent) writeGerberFooter(fid) fid.close() # Write board outline layer if selected fullname = config.Config['outlinelayerfile'] if fullname and fullname.lower() != "none": OutputFiles.append(fullname) #print 'Writing %s ...' % fullname fid = file(fullname, 'wt') writeGerberHeader(fid) # Write width-1 aperture to file # add metric support if config.Config['measurementunits'] == 'inch': AP = aptable.Aperture(aptable.Circle, 'D10', 0.001) else: AP = aptable.Aperture(aptable.Circle, 'D10', 0.25) # we'll use 0.25 mm - same as Diptrace AP.writeDef(fid) # Choose drawing aperture D10 fid.write('D10*\n') # Draw the rectangle fid.write( 'X%07dY%07dD02*\n' % (util.in2gerb(OriginX), util.in2gerb(OriginY))) # Bottom-left fid.write( 'X%07dY%07dD01*\n' % (util.in2gerb(OriginX), util.in2gerb(MaxYExtent))) # Top-left fid.write( 'X%07dY%07dD01*\n' % (util.in2gerb(MaxXExtent), util.in2gerb(MaxYExtent))) # Top-right fid.write( 'X%07dY%07dD01*\n' % (util.in2gerb(MaxXExtent), util.in2gerb(OriginY))) # Bottom-right fid.write( 'X%07dY%07dD01*\n' % (util.in2gerb(OriginX), util.in2gerb(OriginY))) # Bottom-left writeGerberFooter(fid) fid.close() # Write scoring layer if selected fullname = config.Config['scoringfile'] if fullname and fullname.lower() != "none": OutputFiles.append(fullname) #print 'Writing %s ...' % fullname fid = file(fullname, 'wt') writeGerberHeader(fid) # Write width-1 aperture to file AP = aptable.Aperture(aptable.Circle, 'D10', 0.001) AP.writeDef(fid) # Choose drawing aperture D10 fid.write('D10*\n') # Draw the scoring lines scoring.writeScoring(fid, Place, OriginX, OriginY, MaxXExtent, MaxYExtent) writeGerberFooter(fid) fid.close() # Get a list of all tools used by merging keys from each job's dictionary # of tools. if 0: Tools = {} for job in config.Jobs.values(): for key in job.xcommands.keys(): Tools[key] = 1 Tools = Tools.keys() Tools.sort() else: toolNum = 0 # First construct global mapping of diameters to tool numbers for job in config.Jobs.values(): for tool, diam in job.xdiam.items(): if config.GlobalToolRMap.has_key(diam): continue toolNum += 1 config.GlobalToolRMap[diam] = "T%02d" % toolNum # Cluster similar tool sizes to reduce number of drills if config.Config['drillclustertolerance'] > 0: config.GlobalToolRMap = drillcluster.cluster( config.GlobalToolRMap, config.Config['drillclustertolerance']) drillcluster.remap(Place.jobs, config.GlobalToolRMap.items()) # Now construct mapping of tool numbers to diameters for diam, tool in config.GlobalToolRMap.items(): config.GlobalToolMap[tool] = diam # Tools is just a list of tool names Tools = config.GlobalToolMap.keys() Tools.sort() fullname = config.Config['fabricationdrawingfile'] if fullname and fullname.lower() != 'none': if len(Tools) > strokes.MaxNumDrillTools: raise RuntimeError, "Only %d different tool sizes supported for fabrication drawing." % strokes.MaxNumDrillTools OutputFiles.append(fullname) #print 'Writing %s ...' % fullname fid = file(fullname, 'wt') writeGerberHeader(fid) writeApertures(fid, {drawing_code1: None}) fid.write('%s*\n' % drawing_code1) # Choose drawing aperture fabdrawing.writeFabDrawing(fid, Place, Tools, OriginX, OriginY, MaxXExtent, MaxYExtent) writeGerberFooter(fid) fid.close() # Finally, print out the Excellon try: fullname = config.MergeOutputFiles['drills'] except KeyError: fullname = 'merged.drills.xln' OutputFiles.append(fullname) #print 'Writing %s ...' % fullname fid = file(fullname, 'wt') writeExcellonHeader(fid) # Ensure each one of our tools is represented in the tool list specified # by the user. for tool in Tools: try: size = config.GlobalToolMap[tool] except: raise RuntimeError, "INTERNAL ERROR: Tool code %s not found in global tool map" % tool writeExcellonTool(fid, tool, size) #for row in Layout: # row.writeExcellon(fid, size) for job in Place.jobs: job.writeExcellon(fid, size) writeExcellonFooter(fid) fid.close() updateGUI("Closing files...") # Compute stats jobarea = 0.0 #for row in Layout: # jobarea += row.jobarea() for job in Place.jobs: jobarea += job.jobarea() totalarea = ((MaxXExtent - OriginX) * (MaxYExtent - OriginY)) ToolStats = {} drillhits = 0 for tool in Tools: ToolStats[tool] = 0 #for row in Layout: # hits = row.drillhits(config.GlobalToolMap[tool]) # ToolStats[tool] += hits # drillhits += hits for job in Place.jobs: hits = job.drillhits(config.GlobalToolMap[tool]) ToolStats[tool] += hits drillhits += hits try: fullname = config.MergeOutputFiles['toollist'] except KeyError: fullname = 'merged.toollist.drl' OutputFiles.append(fullname) #print 'Writing %s ...' % fullname fid = file(fullname, 'wt') print '-' * 50 # add metric support (1/1000 mm vs. 1/100,000 inch) if config.Config['measurementunits'] == 'inch': print ' Job Size : %f" x %f"' % (MaxXExtent - OriginX, MaxYExtent - OriginY) print ' Job Area : %.2f sq. in.' % totalarea else: print ' Job Size : %.2fmm x %.2fmm' % (MaxXExtent - OriginX, MaxYExtent - OriginY) print ' Job Area : %.0f mm2' % totalarea print ' Area Usage : %.1f%%' % (jobarea / totalarea * 100) print ' Drill hits : %d' % drillhits if config.Config['measurementunits'] == 'inch': print 'Drill density : %.1f hits/sq.in.' % (drillhits / totalarea) else: print 'Drill density : %.2f hits/cm2' % (100 * drillhits / totalarea) print '\nTool List:' smallestDrill = 999.9 for tool in Tools: if ToolStats[tool]: if config.Config['measurementunits'] == 'inch': fid.write('%s %.4fin\n' % (tool, config.GlobalToolMap[tool])) print ' %s %.4f" %5d hits' % ( tool, config.GlobalToolMap[tool], ToolStats[tool]) else: fid.write('%s %.4fmm\n' % (tool, config.GlobalToolMap[tool])) print ' %s %.4fmm %5d hits' % ( tool, config.GlobalToolMap[tool], ToolStats[tool]) smallestDrill = min(smallestDrill, config.GlobalToolMap[tool]) fid.close() if config.Config['measurementunits'] == 'inch': print "Smallest Tool: %.4fin" % smallestDrill else: print "Smallest Tool: %.4fmm" % smallestDrill print print 'Output Files :' for f in OutputFiles: print ' ', f if (MaxXExtent - OriginX) > config.Config['panelwidth'] or ( MaxYExtent - OriginY) > config.Config['panelheight']: print '*' * 75 print '*' # add metric support (1/1000 mm vs. 1/100,000 inch) if config.Config['measurementunits'] == 'inch': print '* ERROR: Merged job exceeds panel dimensions of %.1f"x%.1f"' % ( config.Config['panelwidth'], config.Config['panelheight']) else: print '* ERROR: Merged job exceeds panel dimensions of %.1fmmx%.1fmm' % ( config.Config['panelwidth'], config.Config['panelheight']) print '*' print '*' * 75 sys.exit(1) # Done! return 0
def main(): """ Main function that runs the mascaret executable in the current folder """ # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Reads config file ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ print '\n\nLoading Options and Configurations\n' + 72 * '~' + '\n' parser = ArgumentParser(\ formatter_class=RawDescriptionHelpFormatter, description=('''\n\ Run the mascaret executable in the current folder, given a CAS file. ''')) parser.add_argument("args", nargs='*') # ~~> Environment parser.add_argument(\ "-c", "--configname",dest="configName",default='', help="specify configuration name, default is randomly found in the configuration file" ) parser.add_argument(\ "-f", "--configfile",dest="configFile",default='', help="specify configuration file, default is systel.cfg" ) parser.add_argument(\ "-r", "--rootdir",dest="rootDir",default='', help="specify the root, default is taken from config file" ) parser.add_argument(\ "-s", "--sortiefile",action="store_true",dest="sortieFile",default=False, help="specify whether there is a sortie file, default is no" ) options = parser.parse_args() # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # path to the root PWD = path.dirname(path.dirname(path.dirname(sys.argv[0]))) if options.rootDir != '': PWD = options.rootDir # user configuration name USETELCFG = '' if 'USETELCFG' in environ: USETELCFG = environ['USETELCFG'] if options.configName == '': options.configName = USETELCFG # user configuration file SYSTELCFG = path.join(PWD, 'configs') if 'SYSTELCFG' in environ: SYSTELCFG = environ['SYSTELCFG'] if options.configFile != '': SYSTELCFG = options.configFile if path.isdir(SYSTELCFG): SYSTELCFG = path.join(SYSTELCFG, 'systel.cfg') options.configFile = SYSTELCFG options.bypass = False # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ banners ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ mes = MESSAGES() # runcode takes its version number from the CAS file svnrev = '' svnurl = '' svnban = 'unknown revision' try: key_equals = re.compile(r'(?P<key>[^:]*)(?P<after>.*)', re.I) tail, code = mes.runCmd('svn info ' + PWD, True) for line in tail.split('\n'): proc = re.match(key_equals, line) if proc: if proc.group('key').strip() == 'Revision': svnrev = proc.group('after')[1:].strip() if proc.group('key').strip() == 'URL': svnurl = proc.group('after')[1:].strip() except: pass if svnrev + svnurl == '': print '\n'.join(banner('unknown revision')) else: if svnurl != '': print '\n'.join(banner(svnurl.split('/')[-1])) if svnrev != '': print '\n'.join(banner('rev. #' + svnrev)) # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Works for one configuration only ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if not path.isfile(options.configFile): print '\nNot able to get to the configuration file: ' + options.configFile + '\n' dircfg = path.abspath(path.dirname(options.configFile)) if path.isdir(dircfg): print ' ... in directory: ' + dircfg + '\n ... use instead: ' _, _, filenames = walk(dircfg).next() for fle in filenames: head, tail = path.splitext(fle) if tail == '.cfg': print ' +> ', fle sys.exit(1) if len(options.args) < 1: print '\nThe name of the CAS file is required\n' parser.print_help() sys.exit(1) # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Reads command line arguments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ cas = options.args[0] # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Works for only one configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ cfgs = parseConfigFile(options.configFile, options.configName) cfgname = cfgs.iterkeys().next() xcpts = MESSAGES() # still in lower case if not cfgs[cfgname].has_key('root'): cfgs[cfgname]['root'] = PWD if options.rootDir != '': cfgs[cfgname]['root'] = path.abspath(options.rootDir) # parsing for proper naming cfg = parseConfig_RunningTELEMAC(cfgs[cfgname]) try: createMascaretFiles(cfg, cas) except Exception as e: xcpts.addMessages( filterMessage({'name': '_____________\nruncode::main:\n'}, e, options.bypass)) mascaretExe = cfg['root'] + sep + 'builds'+ sep + cfgname + sep + 'bin' + \ sep + 'mascaret' + cfgs[cfgname]['sfx_exe'] + ' FichierCas.txt' try: tail, code = xcpts.runCmd(mascaretExe, options.bypass) except Exception as e: xcpts.addMessages( filterMessage( { 'name': 'processExecutable', 'msg': 'something went wrong for no reason. \ Please verify your compiler installation.' }, e, options.bypass)) # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Reporting errors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if xcpts.notEmpty() or code != 0: print '\n\nHummm ... I could not complete my work.\n'+'~'*72\ + xcpts.exceptMessages() sys.exit(1) # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Jenkins' success message ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ else: print '\n\nMy work is done\n\n' sys.exit(0)
def merge(opts, args, gui = None): writeGerberHeader = writeGerberHeader22degrees global GUI GUI = gui skipDisclaimer = 0 for opt, arg in opts: if opt in ('--octagons',): if arg=='rotate': writeGerberHeader = writeGerberHeader0degrees elif arg=='normal': writeGerberHeader = writeGerberHeader22degrees else: raise RuntimeError, 'Unknown octagon format' elif opt in ('--random-search',): config.AutoSearchType = RANDOM_SEARCH elif opt in ('--full-search',): config.AutoSearchType = EXHAUSTIVE_SEARCH elif opt in ('--rs-fsjobs',): config.RandomSearchExhaustiveJobs = int(arg) elif opt in ('--search-timeout',): config.SearchTimeout = int(arg) elif opt in ('--place-file',): config.AutoSearchType = FROM_FILE config.PlacementFile = arg elif opt in ('--no-trim-gerber',): config.TrimGerber = 0 elif opt in ('--no-trim-excellon',): config.TrimExcellon = 0 elif opt in ('-s', '--skipdisclaimer'): skipDisclaimer = 1 else: raise RuntimeError, "Unknown option: %s" % opt if len(args) > 2 or len(args) < 1: raise RuntimeError, 'Invalid number of arguments' if (skipDisclaimer == 0): disclaimer() # Load up the Jobs global dictionary, also filling out GAT, the # global aperture table and GAMT, the global aperture macro table. updateGUI("Reading job files...") config.parseConfigFile(args[0]) # Force all X and Y coordinates positive by adding absolute value of minimum X and Y # KHK: name contains the names of the individual "jobs". A job represents one printed curcuit board. # KHK: Jobs is a dictionary, which is generated in config.py, the name of the individual pcb is used as key in the dictionary. # KHK: "jobs.Job is a specific instance xyz" - jobs.Job is a class with its onw methods, i.e. fixcoordinates() etc. - can be interpreted as a Gerber layer of a job. # KHK: name, job are arbitrary temporary variables used as index to store the key and value of the dictionary for name, job in config.Jobs.iteritems(): min_x, min_y = job.mincoordinates() shift_x = shift_y = 0 if min_x < 0: shift_x = abs(min_x) if min_y < 0: shift_y = abs(min_y) if (shift_x > 0) or (shift_y > 0): job.fixcoordinates( shift_x, shift_y ) # Display job properties for job in config.Jobs.values(): print 'Job %s:' % job.name, if job.Repeat > 1: print '(%d instances)' % job.Repeat else: print print ' Extents: (%d,%d)-(%d,%d)' % (job.minx,job.miny,job.maxx,job.maxy) # add metric support (1/1000 mm vs. 1/100,000 inch) if config.Config['measurementunits'] == 'inch': print ' Size: %f" x %f"' % (job.width_in(), job.height_in()) else: print ' Size: %5.3fmm x %5.3fmm' % (job.width_in(), job.height_in()) print # Trim drill locations and flash data to board extents if config.TrimExcellon: updateGUI("Trimming Excellon data...") print 'Trimming Excellon data to board outlines ...' for job in config.Jobs.values(): job.trimExcellon() if config.TrimGerber: updateGUI("Trimming Gerber data...") print 'Trimming Gerber data to board outlines ...' for job in config.Jobs.values(): job.trimGerber() # We start origin at (0.1", 0.1") just so we don't get numbers close to 0 # which could trip up Excellon leading-0 elimination. # I don't want to change the origin. If this a code bug, then it should be fixed (SDD) OriginX = OriginY = 0 #0.1 # Read the layout file and construct the nested list of jobs. If there # is no layout file, do auto-layout. updateGUI("Performing layout...") print 'Performing layout ...' if len(args) > 1: Layout = parselayout.parseLayoutFile(args[1]) # Do the layout, updating offsets for each component job. X = OriginX + config.Config['leftmargin'] Y = OriginY + config.Config['bottommargin'] for row in Layout: row.setPosition(X, Y) Y += row.height_in() + config.Config['yspacing'] # Construct a canonical placement from the layout Place = placement.Placement() Place.addFromLayout(Layout) del Layout elif config.AutoSearchType == FROM_FILE: Place = placement.Placement() Place.addFromFile(config.PlacementFile, config.Jobs) else: # Do an automatic layout based on our tiling algorithm. tile = tile_jobs(config.Jobs.values()) Place = placement.Placement() Place.addFromTiling(tile, OriginX + config.Config['leftmargin'], OriginY + config.Config['bottommargin']) (MaxXExtent,MaxYExtent) = Place.extents() MaxXExtent += config.Config['rightmargin'] MaxYExtent += config.Config['topmargin'] # Start printing out the Gerbers. In preparation for drawing cut marks # and crop marks, make sure we have an aperture to draw with. Use a 10mil line. # If we're doing a fabrication drawing, we'll need a 1mil line. OutputFiles = [] try: fullname = config.MergeOutputFiles['placement'] except KeyError: fullname = 'merged.placement.txt' Place.write(fullname) OutputFiles.append(fullname) # For cut lines AP = aptable.Aperture(aptable.Circle, 'D??', config.Config['cutlinewidth']) drawing_code_cut = aptable.findInApertureTable(AP) if drawing_code_cut is None: drawing_code_cut = aptable.addToApertureTable(AP) # For crop marks AP = aptable.Aperture(aptable.Circle, 'D??', config.Config['cropmarkwidth']) drawing_code_crop = aptable.findInApertureTable(AP) if drawing_code_crop is None: drawing_code_crop = aptable.addToApertureTable(AP) # For fiducials drawing_code_fiducial_copper = drawing_code_fiducial_soldermask = None if config.Config['fiducialpoints']: AP = aptable.Aperture(aptable.Circle, 'D??', config.Config['fiducialcopperdiameter']) drawing_code_fiducial_copper = aptable.findInApertureTable(AP) if drawing_code_fiducial_copper is None: drawing_code_fiducial_copper = aptable.addToApertureTable(AP) AP = aptable.Aperture(aptable.Circle, 'D??', config.Config['fiducialmaskdiameter']) drawing_code_fiducial_soldermask = aptable.findInApertureTable(AP) if drawing_code_fiducial_soldermask is None: drawing_code_fiducial_soldermask = aptable.addToApertureTable(AP) # For fabrication drawing. AP = aptable.Aperture(aptable.Circle, 'D??', 0.001) drawing_code1 = aptable.findInApertureTable(AP) if drawing_code1 is None: drawing_code1 = aptable.addToApertureTable(AP) updateGUI("Writing merged files...") print 'Writing merged output files ...' for layername in config.LayerList.keys(): lname = layername if lname[0]=='*': lname = lname[1:] try: fullname = config.MergeOutputFiles[layername] except KeyError: fullname = 'merged.%s.ger' % lname OutputFiles.append(fullname) #print 'Writing %s ...' % fullname fid = file(fullname, 'wt') writeGerberHeader(fid) # Determine which apertures and macros are truly needed apUsedDict = {} apmUsedDict = {} for job in Place.jobs: apd, apmd = job.aperturesAndMacros(layername) apUsedDict.update(apd) apmUsedDict.update(apmd) # Increase aperature sizes to match minimum feature dimension if config.MinimumFeatureDimension.has_key(layername): print ' Thickening', lname, 'feature dimensions ...' # Fix each aperture used in this layer for ap in apUsedDict.keys(): new = config.GAT[ap].getAdjusted( config.MinimumFeatureDimension[layername] ) if not new: ## current aperture size met minimum requirement continue else: ## new aperture was created new_code = aptable.findOrAddAperture(new) ## get name of existing aperture or create new one if needed del apUsedDict[ap] ## the old aperture is no longer used in this layer apUsedDict[new_code] = None ## the new aperture will be used in this layer # Replace all references to the old aperture with the new one for joblayout in Place.jobs: job = joblayout.job ##access job inside job layout temp = [] if job.hasLayer(layername): for x in job.commands[layername]: if x == ap: temp.append(new_code) ## replace old aperture with new one else: temp.append(x) ## keep old command job.commands[layername] = temp if config.Config['cutlinelayers'] and (layername in config.Config['cutlinelayers']): apUsedDict[drawing_code_cut]=None if config.Config['cropmarklayers'] and (layername in config.Config['cropmarklayers']): apUsedDict[drawing_code_crop]=None if config.Config['fiducialpoints']: if ((layername=='*toplayer') or (layername=='*bottomlayer')): apUsedDict[drawing_code_fiducial_copper] = None elif ((layername=='*topsoldermask') or (layername=='*bottomsoldermask')): apUsedDict[drawing_code_fiducial_soldermask] = None # Write only necessary macro and aperture definitions to Gerber file writeApertureMacros(fid, apmUsedDict) writeApertures(fid, apUsedDict) #for row in Layout: # row.writeGerber(fid, layername) # # Do cut lines # if config.Config['cutlinelayers'] and (layername in config.Config['cutlinelayers']): # fid.write('%s*\n' % drawing_code_cut) # Choose drawing aperture # row.writeCutLines(fid, drawing_code_cut, OriginX, OriginY, MaxXExtent, MaxYExtent) # Finally, write actual flash data for job in Place.jobs: updateGUI("Writing merged output files...") job.writeGerber(fid, layername) if config.Config['cutlinelayers'] and (layername in config.Config['cutlinelayers']): fid.write('%s*\n' % drawing_code_cut) # Choose drawing aperture #print "writing drawcode_cut: %s" % drawing_code_cut job.writeCutLines(fid, drawing_code_cut, OriginX, OriginY, MaxXExtent, MaxYExtent) if config.Config['cropmarklayers']: if layername in config.Config['cropmarklayers']: writeCropMarks(fid, drawing_code_crop, OriginX, OriginY, MaxXExtent, MaxYExtent) if config.Config['fiducialpoints']: if ((layername=='*toplayer') or (layername=='*bottomlayer')): writeFiducials(fid, drawing_code_fiducial_copper, OriginX, OriginY, MaxXExtent, MaxYExtent) elif ((layername=='*topsoldermask') or (layername=='*bottomsoldermask')): writeFiducials(fid, drawing_code_fiducial_soldermask, OriginX, OriginY, MaxXExtent, MaxYExtent) # KHK Patch Begin: added for Seeed Studio to generate an outline for all panelized gerber files if config.Config['outlinelayers'] and (layername in config.Config['outlinelayers']): writeOutline(fid, OriginX, OriginY, MaxXExtent, MaxYExtent) # KHK Patch End: added for Seeed Studio to generate an outline for all panelized gerber files writeGerberFooter(fid) fid.close() # Write board outline layer if selected fullname = config.Config['outlinelayerfile'] if fullname and fullname.lower() != "none": OutputFiles.append(fullname) #print 'Writing %s ...' % fullname fid = file(fullname, 'wt') writeGerberHeader(fid) # Write width-1 aperture to file # add metric support if config.Config['measurementunits'] == 'inch': AP = aptable.Aperture(aptable.Circle, 'D10', 0.001) else: AP = aptable.Aperture(aptable.Circle, 'D10', 0.25) # we'll use 0.25 mm - same as Diptrace AP.writeDef(fid) # Choose drawing aperture D10 fid.write('D10*\n') # Draw the rectangle fid.write('X%07dY%07dD02*\n' % (util.in2gerb(OriginX), util.in2gerb(OriginY))) # Bottom-left fid.write('X%07dY%07dD01*\n' % (util.in2gerb(OriginX), util.in2gerb(MaxYExtent))) # Top-left fid.write('X%07dY%07dD01*\n' % (util.in2gerb(MaxXExtent), util.in2gerb(MaxYExtent))) # Top-right fid.write('X%07dY%07dD01*\n' % (util.in2gerb(MaxXExtent), util.in2gerb(OriginY))) # Bottom-right fid.write('X%07dY%07dD01*\n' % (util.in2gerb(OriginX), util.in2gerb(OriginY))) # Bottom-left writeGerberFooter(fid) fid.close() # Write scoring layer if selected fullname = config.Config['scoringfile'] if fullname and fullname.lower() != "none": OutputFiles.append(fullname) #print 'Writing %s ...' % fullname fid = file(fullname, 'wt') writeGerberHeader(fid) # Write width-1 aperture to file AP = aptable.Aperture(aptable.Circle, 'D10', 0.001) AP.writeDef(fid) # Choose drawing aperture D10 fid.write('D10*\n') # Draw the scoring lines scoring.writeScoring(fid, Place, OriginX, OriginY, MaxXExtent, MaxYExtent) writeGerberFooter(fid) fid.close() # Get a list of all tools used by merging keys from each job's dictionary # of tools. if 0: Tools = {} for job in config.Jobs.values(): for key in job.xcommands.keys(): Tools[key] = 1 Tools = Tools.keys() Tools.sort() else: toolNum = 0 # First construct global mapping of diameters to tool numbers for job in config.Jobs.values(): for tool,diam in job.xdiam.items(): if config.GlobalToolRMap.has_key(diam): continue toolNum += 1 config.GlobalToolRMap[diam] = "T%02d" % toolNum # Cluster similar tool sizes to reduce number of drills if config.Config['drillclustertolerance'] > 0: config.GlobalToolRMap = drillcluster.cluster( config.GlobalToolRMap, config.Config['drillclustertolerance'] ) drillcluster.remap( Place.jobs, config.GlobalToolRMap.items() ) # Now construct mapping of tool numbers to diameters for diam,tool in config.GlobalToolRMap.items(): config.GlobalToolMap[tool] = diam # Tools is just a list of tool names Tools = config.GlobalToolMap.keys() Tools.sort() fullname = config.Config['fabricationdrawingfile'] if fullname and fullname.lower() != 'none': if len(Tools) > strokes.MaxNumDrillTools: raise RuntimeError, "Only %d different tool sizes supported for fabrication drawing." % strokes.MaxNumDrillTools OutputFiles.append(fullname) #print 'Writing %s ...' % fullname fid = file(fullname, 'wt') writeGerberHeader(fid) writeApertures(fid, {drawing_code1: None}) fid.write('%s*\n' % drawing_code1) # Choose drawing aperture fabdrawing.writeFabDrawing(fid, Place, Tools, OriginX, OriginY, MaxXExtent, MaxYExtent) writeGerberFooter(fid) fid.close() # Finally, print out the Excellon try: fullname = config.MergeOutputFiles['drills'] except KeyError: fullname = 'merged.drills.xln' OutputFiles.append(fullname) #print 'Writing %s ...' % fullname fid = file(fullname, 'wt') writeExcellonHeader(fid) # Ensure each one of our tools is represented in the tool list specified # by the user. for tool in Tools: try: size = config.GlobalToolMap[tool] except: raise RuntimeError, "INTERNAL ERROR: Tool code %s not found in global tool map" % tool writeExcellonTool(fid, tool, size) #for row in Layout: # row.writeExcellon(fid, size) for job in Place.jobs: job.writeExcellon(fid, size) writeExcellonFooter(fid) fid.close() updateGUI("Closing files...") # Compute stats jobarea = 0.0 #for row in Layout: # jobarea += row.jobarea() for job in Place.jobs: jobarea += job.jobarea() totalarea = ((MaxXExtent-OriginX)*(MaxYExtent-OriginY)) ToolStats = {} drillhits = 0 for tool in Tools: ToolStats[tool]=0 #for row in Layout: # hits = row.drillhits(config.GlobalToolMap[tool]) # ToolStats[tool] += hits # drillhits += hits for job in Place.jobs: hits = job.drillhits(config.GlobalToolMap[tool]) ToolStats[tool] += hits drillhits += hits try: fullname = config.MergeOutputFiles['toollist'] except KeyError: fullname = 'merged.toollist.drl' OutputFiles.append(fullname) #print 'Writing %s ...' % fullname fid = file(fullname, 'wt') print '-'*50 # add metric support (1/1000 mm vs. 1/100,000 inch) if config.Config['measurementunits'] == 'inch': print ' Job Size : %f" x %f"' % (MaxXExtent-OriginX, MaxYExtent-OriginY) print ' Job Area : %.2f sq. in.' % totalarea else: print ' Job Size : %.2fmm x %.2fmm' % (MaxXExtent-OriginX, MaxYExtent-OriginY) print ' Job Area : %.0f mm2' % totalarea print ' Area Usage : %.1f%%' % (jobarea/totalarea*100) print ' Drill hits : %d' % drillhits if config.Config['measurementunits'] == 'inch': print 'Drill density : %.1f hits/sq.in.' % (drillhits/totalarea) else: print 'Drill density : %.2f hits/cm2' % (100*drillhits/totalarea) print '\nTool List:' smallestDrill = 999.9 for tool in Tools: if ToolStats[tool]: if config.Config['measurementunits'] == 'inch': fid.write('%s %.4fin\n' % (tool, config.GlobalToolMap[tool])) print ' %s %.4f" %5d hits' % (tool, config.GlobalToolMap[tool], ToolStats[tool]) else: fid.write('%s %.4fmm\n' % (tool, config.GlobalToolMap[tool])) print ' %s %.4fmm %5d hits' % (tool, config.GlobalToolMap[tool], ToolStats[tool]) smallestDrill = min(smallestDrill, config.GlobalToolMap[tool]) fid.close() if config.Config['measurementunits'] == 'inch': print "Smallest Tool: %.4fin" % smallestDrill else: print "Smallest Tool: %.4fmm" % smallestDrill print print 'Output Files :' for f in OutputFiles: print ' ', f if (MaxXExtent-OriginX)>config.Config['panelwidth'] or (MaxYExtent-OriginY)>config.Config['panelheight']: print '*'*75 print '*' # add metric support (1/1000 mm vs. 1/100,000 inch) if config.Config['measurementunits'] == 'inch': print '* ERROR: Merged job exceeds panel dimensions of %.1f"x%.1f"' % (config.Config['panelwidth'],config.Config['panelheight']) else: print '* ERROR: Merged job exceeds panel dimensions of %.1fmmx%.1fmm' % (config.Config['panelwidth'],config.Config['panelheight']) print '*' print '*'*75 sys.exit(1) # Done! return 0
def main(config_name, config_file, root_dir, validation_directory, example, clean): """ Main function :param: config_name Name of the telemac configuration :param: config_file Name of the configuration file :param: root_dir Path to the root folder of telemac :param: validation_directory name of the example repository to validate :param: example case to compute :param: clean keyword to know if or not the tmp directory are remove after validation """ # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # path to the root hometel = '' if 'HOMETEL' in environ: hometel = environ['HOMETEL'] if root_dir == '': root_dir = hometel # user configuration name usetelcfg = '' if 'USETELCFG' in environ: usetelcfg = environ['USETELCFG'] if config_name == '': config_name = usetelcfg # user configuration file systelcfg = path.join(hometel, 'configs') if 'SYSTELCFG' in environ: systelcfg = environ['SYSTELCFG'] if config_file != '': systelcfg = config_file if path.isdir(systelcfg): systelcfg = path.join(systelcfg, 'systel.cfg') config_file = systelcfg # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Works for all configurations unless specified ~~~~~~~~~~~~~~~ if not path.isfile(config_file): print '\nNot able to get to the configuration file: '\ + config_file + '\n' dircfg = path.abspath(path.dirname(config_file)) if path.isdir(dircfg): print ' ... in directory: ' + dircfg + '\n ... use instead: ' _, _, filenames = walk(dircfg).next() for fle in filenames: _, tail = path.splitext(fle) if tail == '.cfg': print ' +> ', fle raise Exception('Error in configuration file') # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Reporting errors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ xcptss = MESSAGES() # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ~~~~ Works for all configurations unless specified ~~~~~~~~~~~~~~~ cfgs = parseConfigFile(config_file, config_name) for cfgname in cfgs: # still in lower case if not cfgs[cfgname].has_key('root'): cfgs[cfgname]['root'] = root_dir # parsing for proper naming #cfg = parseConfig_CompileTELEMAC(cfgs[cfgname]) print '\n\n' + '\n'.join(banner(cfgname)) return xcptss