# -*- coding: utf-8 -*- # # AWL simulator - Hardware module parameters # # Copyright 2013-2018 Michael Buesch # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # from __future__ import division, absolute_import, print_function, unicode_literals #from awlsim.common.cython_support cimport * #@cy from awlsim.common.compat import * from awlsim.common.enumeration import * from awlsim.common.util import * from awlsim.common.exceptions import * from awlsim.common.cpuconfig import * from awlsim.core.operatortypes import * #+cimport from awlsim.awlcompiler.optrans import * import re __all__ = [ "HwParamDesc", "HwParamDesc_pyobject", "HwParamDesc_str", "HwParamDesc_int", "HwParamDesc_float", "HwParamDesc_bool", "HwParamDesc_oper", ] class HwParamDesc(object): """Abstract hardware parameter descriptor.""" class ParseError(Exception): pass typeStr = "" userEditable = True defaultValue = None # Default value; represented as parsed value defaultValueStr = None # Default value; represented as parser input string def __init__(self, name, description="", mandatory=False, hidden=False, deprecated=False, compatReplacement="", replacement=""): """ name: The parameter name string. description: The parameter description string. mandatory: If True, then this parameter must be specified. hidden: If True, then this parameter will not be shown by default. deprecated: If True, then the use of this parameter is discouraged. compatReplacement: Optional name of a fully compatible parameter that replaces this one. (Also see 'deprecated'). replacement: Optional name of an incompatible parameter that replaces this one. (Also see 'deprecated'). """ self.name = name self.description = description self.mandatory = mandatory self.hidden = hidden self.deprecated = deprecated self.compatReplacement = compatReplacement self.replacement = replacement def parse(self, value): """Parse a value string. This must be overridden. """ raise NotImplementedError def match(self, matchName): """Match a name string. The default implementation just compares the string to self.name. The parameter must not be 'mandatory', if this method is overridden. """ return self.name == matchName class HwParamDesc_pyobject(HwParamDesc): """Generic object parameter descriptor.""" typeStr = "PyObject" userEditable = False def __init__(self, name, **kwargs): HwParamDesc.__init__(self, name, **kwargs) def parse(self, value): return value class HwParamDesc_str(HwParamDesc): """String hardware parameter descriptor.""" typeStr = "string" def __init__(self, name, defaultValue="", **kwargs): HwParamDesc.__init__(self, name, **kwargs) self.defaultValue = defaultValue self.defaultValueStr = defaultValue def parse(self, value): if not value.strip(): return self.defaultValue return value class HwParamDesc_int(HwParamDesc): """Integer hardware parameter descriptor.""" typeStr = "integer" def __init__(self, name, defaultValue=0, minValue=None, maxValue=None, **kwargs): HwParamDesc.__init__(self, name, **kwargs) self.defaultValue = defaultValue self.defaultValueStr = None if defaultValue is None else str(defaultValue) self.minValue = minValue self.maxValue = maxValue def parse(self, value): value = value.strip() if not value: return self.defaultValue valueUpper = value.upper() if valueUpper.startswith("B#16#") or\ valueUpper.startswith("W#16#"): value = "0x" + value[5:] elif valueUpper.startswith("DW#16#"): value = "0x" + value[6:] elif valueUpper.startswith("L#"): value = value[2:] # Strip L# prefix try: value = int(value) except ValueError: raise self.ParseError("Value '%s' is not a valid integer." %\ str(value)) if self.minValue is not None: if value < self.minValue: raise self.ParseError("Value '%d' is too small." % value) if self.maxValue is not None: if value > self.maxValue: raise self.ParseError("Value '%d' is too big." % value) return value class HwParamDesc_float(HwParamDesc): """Float hardware parameter descriptor.""" typeStr = "float" def __init__(self, name, defaultValue=0.0, minValue=None, maxValue=None, **kwargs): HwParamDesc.__init__(self, name, **kwargs) self.defaultValue = defaultValue self.defaultValueStr = None if defaultValue is None else str(defaultValue) self.minValue = minValue self.maxValue = maxValue def parse(self, value): if not value.strip(): return self.defaultValue try: value = float(value) except ValueError: raise self.ParseError("Value '%s' is not a valid floating point number." %\ str(value)) if self.minValue is not None: if value < self.minValue: raise self.ParseError("Value '%f' is too small." % value) if self.maxValue is not None: if value > self.maxValue: raise self.ParseError("Value '%f' is too big." % value) return value class HwParamDesc_bool(HwParamDesc): """Boolean hardware parameter descriptor.""" typeStr = "boolean" def __init__(self, name, defaultValue=False, **kwargs): HwParamDesc.__init__(self, name, **kwargs) self.defaultValue = None if defaultValue is None else bool(defaultValue) self.defaultValueStr = None if defaultValue is None else str(bool(defaultValue)) def parse(self, value): value = value.strip() if not value: return self.defaultValue if value.lower() in ("true", "yes", "on"): return True if value.lower() in ("false", "no", "off"): return False try: value = int(value, 10) except ValueError: raise self.ParseError("Value '%s' is not a valid boolean." %\ str(value)) return bool(value) class HwParamDesc_oper(HwParamDesc): """Hardware parameter descriptor for operators. """ typeStr = "operator" def __init__(self, name, allowedOperTypes=(), allowedOperWidths=(), **kwargs): HwParamDesc.__init__(self, name, **kwargs) self.allowedOperTypes = allowedOperTypes self.allowedOperWidths = allowedOperWidths numRe = re.compile(r'^\-?\d+$', re.DOTALL) def __tryParse(self, value, mnemonics): # Add a L# prefix, if this is a constant long integer. if self.numRe.match(value): try: v = int(value, 10) if (v > 32767 and v <= 2147483647) or\ (v < -32768 and v >= -2147483648): value = "L#" + value except ValueError as e: pass # Parse value as operator. try: trans = AwlOpTranslator(mnemonics=mnemonics) opDesc = trans.translateFromString(value) oper = opDesc.operator except AwlSimError as e: oper = None return oper def parse(self, value): if not value.strip(): return None oper = self.__tryParse(value, S7CPUConfig.MNEMONICS_EN) if not oper: oper = self.__tryParse(value, S7CPUConfig.MNEMONICS_DE) if not oper: raise self.ParseError("Operator '%s' " "is not valid." % value) if self.allowedOperTypes: if oper.operType not in self.allowedOperTypes: raise self.ParseError("Operator '%s' " "does not have a valid type." % value) if self.allowedOperWidths: if oper.width not in self.allowedOperWidths: raise self.ParseError("Operator '%s' " "does not have a valid bit width. " "Valid widths are: %s bits." % ( value, listToHumanStr(self.allowedOperWidths))) return oper