graphics/DebugDataConsumer.py
changeset 1784 64beb9e9c749
parent 1782 5b6ad7a7fd9d
child 1831 56b48961cc68
equal deleted inserted replaced
1729:31e63e25b4cc 1784:64beb9e9c749
    22 # along with this program; if not, write to the Free Software
    22 # along with this program; if not, write to the Free Software
    23 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    23 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    24 
    24 
    25 import datetime
    25 import datetime
    26 
    26 
    27 #-------------------------------------------------------------------------------
    27 
       
    28 # -------------------------------------------------------------------------------
    28 #                        Date and Time conversion function
    29 #                        Date and Time conversion function
    29 #-------------------------------------------------------------------------------
    30 # -------------------------------------------------------------------------------
    30 
    31 
    31 SECOND = 1000000      # Number of microseconds in one second
    32 SECOND = 1000000      # Number of microseconds in one second
    32 MINUTE = 60 * SECOND  # Number of microseconds in one minute
    33 MINUTE = 60 * SECOND  # Number of microseconds in one minute
    33 HOUR = 60 * MINUTE    # Number of microseconds in one hour
    34 HOUR = 60 * MINUTE    # Number of microseconds in one hour
    34 DAY = 24 * HOUR       # Number of microseconds in one day
    35 DAY = 24 * HOUR       # Number of microseconds in one day
    35 
    36 
    36 # Date corresponding to Epoch (1970 January the first)
    37 # Date corresponding to Epoch (1970 January the first)
    37 DATE_ORIGIN = datetime.datetime(1970, 1, 1)
    38 DATE_ORIGIN = datetime.datetime(1970, 1, 1)
    38 
    39 
       
    40 
    39 def get_microseconds(value):
    41 def get_microseconds(value):
    40     """
    42     """
    41     Function converting time duration expressed in day, second and microseconds
    43     Function converting time duration expressed in day, second and microseconds
    42     into one expressed in microseconds
    44     into one expressed in microseconds
    43     @param value: Time duration to convert
    45     @param value: Time duration to convert
    44     @return: Time duration expressed in microsecond
    46     @return: Time duration expressed in microsecond
    45     """
    47     """
    46     return float(value.days * DAY + \
    48     return float(value.days * DAY +
    47                  value.seconds * SECOND + \
    49                  value.seconds * SECOND +
    48                  value.microseconds)
    50                  value.microseconds)
    49     return 
    51     return
       
    52 
    50 
    53 
    51 def generate_time(value):
    54 def generate_time(value):
    52     """
    55     """
    53     Function converting time duration expressed in day, second and microseconds
    56     Function converting time duration expressed in day, second and microseconds
    54     into a IEC 61131 TIME literal
    57     into a IEC 61131 TIME literal
    55     @param value: Time duration to convert
    58     @param value: Time duration to convert
    56     @return: IEC 61131 TIME literal
    59     @return: IEC 61131 TIME literal
    57     """
    60     """
    58     microseconds = get_microseconds(value)
    61     microseconds = get_microseconds(value)
    59     
    62 
    60     # Get absolute microseconds value and save if it was negative
    63     # Get absolute microseconds value and save if it was negative
    61     negative = microseconds < 0
    64     negative = microseconds < 0
    62     microseconds = abs(microseconds)
    65     microseconds = abs(microseconds)
    63     
    66 
    64     # TIME literal prefix
    67     # TIME literal prefix
    65     data = "T#"
    68     data = "T#"
    66     if negative:
    69     if negative:
    67         data += "-"
    70         data += "-"
    68     
    71 
    69     # In TIME literal format, it isn't mandatory to indicate null values
    72     # In TIME literal format, it isn't mandatory to indicate null values
    70     # if no greater non-null values are available. This variable is used to
    73     # if no greater non-null values are available. This variable is used to
    71     # inhibit formatting until a non-null value is found
    74     # inhibit formatting until a non-null value is found
    72     not_null = False
    75     not_null = False
    73     
    76 
    74     for val, format in [
    77     for val, format in [
    75             (int(microseconds) / DAY, "%dd"),                # Days
    78             (int(microseconds) / DAY, "%dd"),                 # Days
    76             ((int(microseconds) % DAY) / HOUR, "%dh"),       # Hours
    79             ((int(microseconds) % DAY) / HOUR, "%dh"),        # Hours
    77             ((int(microseconds) % HOUR) / MINUTE, "%dm"),    # Minutes
    80             ((int(microseconds) % HOUR) / MINUTE, "%dm"),     # Minutes
    78             ((int(microseconds) % MINUTE) / SECOND, "%ds")]: # Seconds
    81             ((int(microseconds) % MINUTE) / SECOND, "%ds")]:  # Seconds
    79         
    82 
    80         # Add value to TIME literal if value is non-null or another non-null 
    83         # Add value to TIME literal if value is non-null or another non-null
    81         # value have already be found
    84         # value have already be found
    82         if val > 0 or not_null:
    85         if val > 0 or not_null:
    83             data += format % val
    86             data += format % val
    84             
    87 
    85             # Update non-null variable
    88             # Update non-null variable
    86             not_null = True
    89             not_null = True
    87     
    90 
    88     # In any case microseconds have to be added to TIME literal 
    91     # In any case microseconds have to be added to TIME literal
    89     data += "%gms" % (microseconds % SECOND / 1000.)
    92     data += "%gms" % (microseconds % SECOND / 1000.)
    90     
    93 
    91     return data
    94     return data
    92 
    95 
       
    96 
    93 def generate_date(value):
    97 def generate_date(value):
    94     """
    98     """
    95     Function converting time duration expressed in day, second and microseconds
    99     Function converting time duration expressed in day, second and microseconds
    96     into a IEC 61131 DATE literal
   100     into a IEC 61131 DATE literal
    97     @param value: Time duration to convert
   101     @param value: Time duration to convert
    98     @return: IEC 61131 DATE literal
   102     @return: IEC 61131 DATE literal
    99     """
   103     """
   100     return (DATE_ORIGIN + value).strftime("DATE#%Y-%m-%d")
   104     return (DATE_ORIGIN + value).strftime("DATE#%Y-%m-%d")
   101 
   105 
       
   106 
   102 def generate_datetime(value):
   107 def generate_datetime(value):
   103     """
   108     """
   104     Function converting time duration expressed in day, second and microseconds
   109     Function converting time duration expressed in day, second and microseconds
   105     into a IEC 61131 DATE_AND_TIME literal
   110     into a IEC 61131 DATE_AND_TIME literal
   106     @param value: Time duration to convert
   111     @param value: Time duration to convert
   107     @return: IEC 61131 DATE_AND_TIME literal
   112     @return: IEC 61131 DATE_AND_TIME literal
   108     """
   113     """
   109     return (DATE_ORIGIN + value).strftime("DT#%Y-%m-%d-%H:%M:%S.%f")
   114     return (DATE_ORIGIN + value).strftime("DT#%Y-%m-%d-%H:%M:%S.%f")
   110 
   115 
       
   116 
   111 def generate_timeofday(value):
   117 def generate_timeofday(value):
   112     """
   118     """
   113     Function converting time duration expressed in day, second and microseconds
   119     Function converting time duration expressed in day, second and microseconds
   114     into a IEC 61131 TIME_OF_DAY literal
   120     into a IEC 61131 TIME_OF_DAY literal
   115     @param value: Time duration to convert
   121     @param value: Time duration to convert
   116     @return: IEC 61131 TIME_OF_DAY literal
   122     @return: IEC 61131 TIME_OF_DAY literal
   117     """
   123     """
   118     microseconds = get_microseconds(value)
   124     microseconds = get_microseconds(value)
   119     
   125 
   120     # TIME_OF_DAY literal prefix
   126     # TIME_OF_DAY literal prefix
   121     data = "TOD#"
   127     data = "TOD#"
   122     
   128 
   123     for val, format in [
   129     for val, format in [
   124             (int(microseconds) / HOUR, "%2.2d:"),               # Hours
   130             (int(microseconds) / HOUR, "%2.2d:"),               # Hours
   125             ((int(microseconds) % HOUR) / MINUTE, "%2.2d:"),    # Minutes
   131             ((int(microseconds) % HOUR) / MINUTE, "%2.2d:"),    # Minutes
   126             ((int(microseconds) % MINUTE) / SECOND, "%2.2d."),  # Seconds
   132             ((int(microseconds) % MINUTE) / SECOND, "%2.2d."),  # Seconds
   127             (microseconds % SECOND, "%6.6d")]:                  # Microseconds
   133             (microseconds % SECOND, "%6.6d")]:                  # Microseconds
   128         
   134 
   129         # Add value to TIME_OF_DAY literal
   135         # Add value to TIME_OF_DAY literal
   130         data += format % val
   136         data += format % val
   131     
   137 
   132     return data
   138     return data
   133 
   139 
   134 # Dictionary of translation functions from value send by debugger to IEC 
   140 
       
   141 # Dictionary of translation functions from value send by debugger to IEC
   135 # literal stored by type
   142 # literal stored by type
   136 TYPE_TRANSLATOR = {
   143 TYPE_TRANSLATOR = {
   137     "TIME": generate_time,
   144     "TIME": generate_time,
   138     "DATE": generate_date,
   145     "DATE": generate_date,
   139     "DT": generate_datetime,
   146     "DT": generate_datetime,
   141     "STRING": lambda v: "'%s'" % v,
   148     "STRING": lambda v: "'%s'" % v,
   142     "WSTRING": lambda v: '"%s"' % v,
   149     "WSTRING": lambda v: '"%s"' % v,
   143     "REAL": lambda v: "%.6g" % v,
   150     "REAL": lambda v: "%.6g" % v,
   144     "LREAL": lambda v: "%.6g" % v}
   151     "LREAL": lambda v: "%.6g" % v}
   145 
   152 
   146 #-------------------------------------------------------------------------------
   153 
       
   154 # -------------------------------------------------------------------------------
   147 #                            Debug Data Consumer Class
   155 #                            Debug Data Consumer Class
   148 #-------------------------------------------------------------------------------
   156 # -------------------------------------------------------------------------------
   149 
   157 
   150 """
       
   151 Class that implements an element that consumes debug values
       
   152 Value update can be inhibited during the time the associated Debug Viewer is
       
   153 refreshing
       
   154 """
       
   155 
   158 
   156 class DebugDataConsumer:
   159 class DebugDataConsumer:
   157     
   160     """
       
   161     Class that implements an element that consumes debug values
       
   162     Value update can be inhibited during the time the associated Debug Viewer is
       
   163     refreshing
       
   164     """
       
   165 
   158     def __init__(self):
   166     def __init__(self):
   159         """
   167         """
   160         Constructor
   168         Constructor
   161         """
   169         """
   162         # Debug value and forced flag
   170         # Debug value and forced flag
   163         self.Value = None
   171         self.Value = None
   164         self.Forced = False
   172         self.Forced = False
   165         
   173 
   166         # Store debug value and forced flag when value update is inhibited
   174         # Store debug value and forced flag when value update is inhibited
   167         self.LastValue = None
   175         self.LastValue = None
   168         self.LastForced = False
   176         self.LastForced = False
   169         
   177 
   170         # Value IEC data type
   178         # Value IEC data type
   171         self.DataType = None
   179         self.DataType = None
   172         
   180 
   173         # Flag that value update is inhibited
   181         # Flag that value update is inhibited
   174         self.Inhibited = False
   182         self.Inhibited = False
   175     
   183 
   176     def Inhibit(self, inhibit):
   184     def Inhibit(self, inhibit):
   177         """
   185         """
   178         Set flag to inhibit or activate value update
   186         Set flag to inhibit or activate value update
   179         @param inhibit: Inhibit flag
   187         @param inhibit: Inhibit flag
   180         """
   188         """
   181         # Save inhibit flag
   189         # Save inhibit flag
   182         self.Inhibited = inhibit
   190         self.Inhibited = inhibit
   183         
   191 
   184         # When reactivated update value and forced flag with stored values
   192         # When reactivated update value and forced flag with stored values
   185         if not inhibit and self.LastValue is not None:
   193         if not inhibit and self.LastValue is not None:
   186             self.SetForced(self.LastForced)
   194             self.SetForced(self.LastForced)
   187             self.SetValue(self.LastValue)
   195             self.SetValue(self.LastValue)
   188             
   196 
   189             # Reset stored values
   197             # Reset stored values
   190             self.LastValue = None
   198             self.LastValue = None
   191             self.LastForced = False
   199             self.LastForced = False
   192     
   200 
   193     def SetDataType(self, data_type):
   201     def SetDataType(self, data_type):
   194         """
   202         """
   195         Set value IEC data type
   203         Set value IEC data type
   196         @param data_type: Value IEC data type
   204         @param data_type: Value IEC data type
   197         """
   205         """
   198         self.DataType = data_type
   206         self.DataType = data_type
   199     
   207 
   200     def NewValues(self, tick, values, raw="BOOL"):
   208     def NewValues(self, tick, values, raw="BOOL"):
   201         """
   209         """
   202         Function called by debug thread when a new debug value is available
   210         Function called by debug thread when a new debug value is available
   203         @param tick: PLC tick when value was captured
   211         @param tick: PLC tick when value was captured
   204         @param value: Value captured
   212         @param value: Value captured
   205         @param forced: Forced flag, True if value is forced (default: False)
   213         @param forced: Forced flag, True if value is forced (default: False)
   206         @param raw: Data type of values not translated (default: 'BOOL')
   214         @param raw: Data type of values not translated (default: 'BOOL')
   207         """
   215         """
   208         value, forced = values
   216         value, forced = values
   209         
   217 
   210         # Translate value to IEC literal
   218         # Translate value to IEC literal
   211         if self.DataType != raw:
   219         if self.DataType != raw:
   212             value = TYPE_TRANSLATOR.get(self.DataType, str)(value)
   220             value = TYPE_TRANSLATOR.get(self.DataType, str)(value)
   213         
   221 
   214         # Store value and forced flag when value update is inhibited
   222         # Store value and forced flag when value update is inhibited
   215         if self.Inhibited:
   223         if self.Inhibited:
   216             self.LastValue = value
   224             self.LastValue = value
   217             self.LastForced = forced
   225             self.LastForced = forced
   218         
   226 
   219         # Update value and forced flag in any other case
   227         # Update value and forced flag in any other case
   220         else:
   228         else:
   221             self.SetForced(forced)
   229             self.SetForced(forced)
   222             self.SetValue(value)
   230             self.SetValue(value)
   223     
   231 
   224     def SetValue(self, value):
   232     def SetValue(self, value):
   225         """
   233         """
   226         Update value.
   234         Update value.
   227         May be overridden by inherited classes
   235         May be overridden by inherited classes
   228         @param value: New value
   236         @param value: New value
   229         """
   237         """
   230         self.Value = value
   238         self.Value = value
   231     
   239 
   232     def GetValue(self):
   240     def GetValue(self):
   233         """
   241         """
   234         Return current value
   242         Return current value
   235         @return: Current value
   243         @return: Current value
   236         """
   244         """
   237         return self.Value
   245         return self.Value
   238     
   246 
   239     def SetForced(self, forced):
   247     def SetForced(self, forced):
   240         """
   248         """
   241         Update Forced flag.
   249         Update Forced flag.
   242         May be overridden by inherited classes
   250         May be overridden by inherited classes
   243         @param forced: New forced flag
   251         @param forced: New forced flag
   244         """
   252         """
   245         self.Forced = forced
   253         self.Forced = forced
   246     
   254 
   247     def IsForced(self):
   255     def IsForced(self):
   248         """
   256         """
   249         Indicate if current value is forced
   257         Indicate if current value is forced
   250         @return: Current forced flag
   258         @return: Current forced flag
   251         """
   259         """