# HG changeset patch # User laurent # Date 1301671171 -7200 # Node ID 722714c04dcd85a7f4849364bf979e5e4e6b039f # Parent 343fa6867322eb7158d90ef1dda65f2fba795135 Adding support for displaying and forcing TIME variables according to IEC 61131 literal format diff -r 343fa6867322 -r 722714c04dcd dialogs/ForceVariableDialog.py --- a/dialogs/ForceVariableDialog.py Fri Apr 01 15:33:36 2011 +0200 +++ b/dialogs/ForceVariableDialog.py Fri Apr 01 17:19:31 2011 +0200 @@ -22,6 +22,7 @@ #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA import wx +import re import datetime #------------------------------------------------------------------------------- @@ -46,10 +47,33 @@ getfloat = gen_get_function(float) getstring = gen_get_function(str) -def gettime(v): - try: - return datetime.timedelta(0, float(v)) - except: +SECOND = 1000000 +MINUTE = 60 * SECOND +HOUR = 60 * MINUTE +DAY = 24 * HOUR +IEC_TIME_MODEL = re.compile("(?:T|TIME)#(-)?(?:(%(float)s)D_?)?(?:(%(float)s)H_?)?(?:(%(float)s)M_?)?(?:(%(float)s)S_?)?(?:(%(float)s)MS)?" % {"float": "[0-9]+(?:\.[0-9]+)?"}) + +def gettime(v): + result = IEC_TIME_MODEL.match(v.upper()) + if result is not None: + negative, days, hours, minutes, seconds, milliseconds = result.groups() + microseconds = 0 + not_null = False + for value, factor in [(days, DAY), + (hours, HOUR), + (minutes, MINUTE), + (seconds, SECOND), + (milliseconds, 1000)]: + if value is not None: + microseconds += float(value) * factor + not_null = True + if not not_null: + return None + if negative is not None: + microseconds = -microseconds + return datetime.timedelta(microseconds=microseconds) + + else: return None diff -r 343fa6867322 -r 722714c04dcd graphics/GraphicCommons.py --- a/graphics/GraphicCommons.py Fri Apr 01 15:33:36 2011 +0200 +++ b/graphics/GraphicCommons.py Fri Apr 01 17:19:31 2011 +0200 @@ -175,6 +175,30 @@ return dir_target return v_base +SECOND = 1000000 +MINUTE = 60 * SECOND +HOUR = 60 * MINUTE +DAY = 24 * HOUR + +def generate_time(value): + microseconds = float(value.days * DAY + value.seconds * SECOND + value.microseconds) + negative = microseconds < 0 + microseconds = abs(microseconds) + data = "T#" + not_null = False + if negative: + data += "-" + for val, format in [(int(microseconds) / DAY, "%dd"), + ((int(microseconds) % DAY) / HOUR, "%dh"), + ((int(microseconds) % HOUR) / MINUTE, "%dm"), + ((int(microseconds) % MINUTE) / SECOND, "%ds")]: + if val > 0 or not_null: + data += format % val + not_null = True + data += "%gms" % (microseconds % SECOND / 1000.) + return data + +TYPE_TRANSLATOR = {"TIME": generate_time} #------------------------------------------------------------------------------- # Debug Data Consumer Class @@ -185,6 +209,7 @@ def __init__(self): self.LastValue = None self.Value = None + self.DataType = None self.LastForced = False self.Forced = False self.Inhibited = False @@ -195,15 +220,19 @@ self.SetForced(self.LastForced) self.SetValue(self.LastValue) self.LastValue = None - + + def SetDataType(self, data_type): + self.DataType = data_type + def NewValue(self, tick, value, forced=False): + value = TYPE_TRANSLATOR.get(self.DataType, lambda x:x)(value) if self.Inhibited: self.LastValue = value self.LastForced = forced else: self.SetForced(forced) self.SetValue(value) - + def SetValue(self, value): self.Value = value @@ -266,6 +295,7 @@ result = self.DataProducer.SubscribeDebugIECVariable(iec_path, consumer) is not None if result is not None and consumer != self: self.DataConsumers[consumer] = iec_path + consumer.SetDataType(self.GetDataType(iec_path)) return result def RemoveDataConsumer(self, consumer): @@ -1619,7 +1649,7 @@ def CreateToolTip(self, pos): if self.Value is not None and self.Value != "undefined" and not isinstance(self.Value, BooleanType): - if isinstance(self.Value, StringType): + if isinstance(self.Value, StringType) and self.Value.find("#") == -1: computed_value = "\"%s\""%self.Value else: computed_value = str(self.Value) @@ -1789,7 +1819,7 @@ if self.Value != value: self.Value = value if value is not None and not isinstance(value, BooleanType): - if isinstance(value, StringType): + if isinstance(value, StringType) and value.find('#') == -1: self.ComputedValue = "\"%s\""%value else: self.ComputedValue = str(value) @@ -2687,19 +2717,20 @@ if self.Value is not None and not isinstance(self.Value, BooleanType) and self.Value != "undefined": dc.SetFont(self.Parent.GetMiniFont()) dc.SetTextForeground(wx.NamedColour("purple")) - width, height = self.ValueSize - if self.BoundingBox[2] > width * 4 or self.BoundingBox[3] > height * 4: - x = self.Points[0].x + width * (self.StartPoint[1][0] - 1) / 2 - y = self.Points[0].y + height * (self.StartPoint[1][1] - 1) / 2 - dc.DrawText(self.ComputedValue, x, y) - x = self.Points[-1].x + width * (self.EndPoint[1][0] - 1) / 2 - y = self.Points[-1].y + height * (self.EndPoint[1][1] - 1) / 2 - dc.DrawText(self.ComputedValue, x, y) - else: - middle = len(self.Segments) / 2 + len(self.Segments) % 2 - 1 - x = (self.Points[middle].x + self.Points[middle + 1].x - width) / 2 - y = (self.Points[middle].y + self.Points[middle + 1].y - height) / 2 - dc.DrawText(self.ComputedValue, x, y) + if self.ValueSize is not None: + width, height = self.ValueSize + if self.BoundingBox[2] > width * 4 or self.BoundingBox[3] > height * 4: + x = self.Points[0].x + width * (self.StartPoint[1][0] - 1) / 2 + y = self.Points[0].y + height * (self.StartPoint[1][1] - 1) / 2 + dc.DrawText(self.ComputedValue, x, y) + x = self.Points[-1].x + width * (self.EndPoint[1][0] - 1) / 2 + y = self.Points[-1].y + height * (self.EndPoint[1][1] - 1) / 2 + dc.DrawText(self.ComputedValue, x, y) + else: + middle = len(self.Segments) / 2 + len(self.Segments) % 2 - 1 + x = (self.Points[middle].x + self.Points[middle + 1].x - width) / 2 + y = (self.Points[middle].y + self.Points[middle + 1].y - height) / 2 + dc.DrawText(self.ComputedValue, x, y) dc.SetFont(self.Parent.GetFont()) dc.SetTextForeground(wx.BLACK)