| # takes: fei (either xml or text) and smv, |
| # and produces smv and fault modes files |
| |
| import sys |
| import os.path |
| import logging |
| import subprocess |
| |
| import _paths |
| import _utils |
| |
| |
| # WARNING! ordering is important here! |
| FMEA_ENGINES = "bdd bmc msat".split() |
| FMEA_ENGINE_BDD, FMEA_ENGINE_BMC, FMEA_ENGINE_MSAT = FMEA_ENGINES |
| |
| |
| def handle_options(): |
| """returns (options, input_file): |
| values (as a map) and the name of the input file""" |
| |
| import argparse |
| parser = argparse.ArgumentParser(description="Produces an extend smv file" |
| " out of given nominal smv file and fei") |
| |
| parser.add_argument("--smv-file", |
| metavar="SMV-FILE", |
| help="The input extended smv file name") |
| |
| parser.add_argument("--fms-file", |
| metavar="FMS-FILE", |
| help="The input fault mode xml file name") |
| |
| parser.add_argument("--prop-indices", "-n", |
| type=int, |
| metavar="INDICES", |
| help="Property indices to be used as TLE " |
| "(separated by ':' or spaces, ranges like " |
| "'0-10' are allowed)") |
| |
| parser.add_argument("--props-text", "-p", |
| metavar="PROPERTIES", |
| help="Textual properties to be used as TLE, " |
| "separated by ':' or by spaces") |
| |
| parser.add_argument('--verbose', '-v', |
| action='store_true', |
| default=False, |
| help='Sets verbosity to high level') |
| |
| parser.add_argument('--engine', '-E', |
| choices=FMEA_ENGINES, |
| default=FMEA_ENGINE_BDD, |
| help='Use given engine (default: %(default)s)') |
| |
| parser.add_argument('--dynamic', |
| action='store_true', |
| default=False, |
| help='Generates dynamic fmea table') |
| |
| parser.add_argument('--compact', '-c', |
| action='store_true', |
| default=False, |
| help='Generates compact fmea table') |
| |
| parser.add_argument('--card', "-N", |
| type=int, |
| default=1, |
| help='Cut-Set cardinality (default: %(default)d)') |
| |
| parser.add_argument('--bmc-length', "-k", |
| type=int, |
| default=10, |
| help='Specify BMC length (integer)') |
| |
| parser.add_argument('--show', '-s', |
| action='store_true', |
| default=False, |
| help='Show the generated fmea table') |
| |
| parser.add_argument( |
| "-d", "--outdir", |
| default="out", |
| metavar="PATH", |
| help="Output directory, where all generated file should be " |
| "put into (default:%(default)s)") |
| |
| args = parser.parse_args() |
| |
| for fn in (args.smv_file, args.fms_file): |
| if fn and not os.path.isfile(fn): |
| parser.error("File not found: " + fn) |
| |
| if os.path.exists(args.outdir) and not os.path.isdir(args.outdir): |
| parser.error("Not a directory: " + args.outdir) |
| |
| prop = [p for p in (args.prop_indices, args.props_text) |
| if p is not None] |
| if len(prop) > 1: |
| parser.error("Properties can be specified only " |
| "in one way (multiple used)") |
| |
| if args.engine in (FMEA_ENGINE_MSAT, FMEA_ENGINE_BMC) and args.dynamic: |
| parser.error("Dynamic fmea not available with engine %s" % args.engine) |
| |
| return args |
| |
| |
| def show_fmea_table(fmea_fname, card, show): |
| count = 0 |
| |
| import csv |
| with open(fmea_fname, 'rb') as csvfile: |
| reader = csv.reader(csvfile, delimiter='\t', quotechar="'") |
| reader.next() |
| for row in reader: |
| if show: |
| print "-" * 70 |
| print "ID: ", row[0] |
| print "TLE:", row[3] |
| print "FMS:", row[2] |
| count += 1 |
| |
| if show: |
| print "=" * 70 |
| print "Total cut sets with cardinality %d: %d" % (card, count) |
| |
| elif count == 0: |
| logging.warn("The FMEA table is empty with cardinality %d" % card) |
| |
| return |
| |
| |
| if "__main__" == __name__: |
| _paths.setup_path() |
| |
| import xsap.utils.misc.log |
| from xsap.utils.processes.xsap_process import XsapProcess |
| xsap.utils.misc.log.init() |
| |
| args = handle_options() |
| |
| if not os.path.exists(args.outdir): |
| os.makedirs(args.outdir) |
| |
| if args.verbose: |
| logging.getLogger().setLevel(logging.INFO) |
| |
| prop = [('-n %d' % args.prop_indices) if args.prop_indices is not None |
| else |
| ('%s' % args.props_text) if args.props_text is not None |
| else ""] |
| |
| # automatically searches for inputs when not explicitly provided |
| smv_fname = _utils.get_suitable_smv_file(args.smv_file, args.outdir) |
| if smv_fname is None: |
| sys.exit(1) |
| |
| fms_fname = _utils.get_suitable_fms_file(args.fms_file, |
| smv_fname, |
| args.outdir) |
| if fms_fname is None: |
| sys.exit(1) |
| |
| stdouterr_fname = os.path.join(args.outdir, "xsap_compute_fmea.out") |
| if os.path.exists(stdouterr_fname): |
| os.remove(stdouterr_fname) |
| stdouterr_file = open(stdouterr_fname, "w") |
| |
| logging.info("Invoking xsap to compute fmea table") |
| |
| need_msat = XsapProcess.has_infinite_domain_vars(smv_fname) or args.engine == FMEA_ENGINE_MSAT |
| with XsapProcess(smv_fname, fms_fname, |
| need_msat=need_msat, |
| stdout=subprocess.PIPE, |
| stderr=subprocess.STDOUT, |
| dumpers=[stdouterr_file]) as xsap_proc: |
| |
| # set the prefix of generated files |
| full_base, _ext = os.path.splitext(smv_fname) |
| base = os.path.basename(full_base) |
| xsap_proc.set_tmp_filename_prefix(args.outdir + "/" + base) |
| |
| stdouterr_file.write("\n" + "-" * 70) |
| stdouterr_file.write("\nInvoking: %s %s\n" % (xsap_proc.get_path(), |
| " ".join(xsap_proc.get_args()))) |
| stdouterr_file.write("\n" + "-" * 70) |
| stdouterr_file.write("\n") |
| |
| res = xsap_proc.compute_fmea_table( |
| prop, args.card, dynamic=args.dynamic, bmc_length=args.bmc_length, |
| compact=args.compact, engine=args.engine) |
| |
| logging.info("xsap produced fmea table in: '%s'" % res) |
| stdouterr_file.close() |
| |
| show_fmea_table(res, args.card, args.show) |