Laurent@814: # -*- coding: utf-8 -*- Laurent@814: Laurent@814: #This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor Laurent@814: #based on the plcopen standard. Laurent@814: # Laurent@814: #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD Laurent@814: # Laurent@814: #See COPYING file for copyrights details. Laurent@814: # Laurent@814: #This library is free software; you can redistribute it and/or Laurent@814: #modify it under the terms of the GNU General Public Laurent@814: #License as published by the Free Software Foundation; either Laurent@814: #version 2.1 of the License, or (at your option) any later version. Laurent@814: # Laurent@814: #This library is distributed in the hope that it will be useful, Laurent@814: #but WITHOUT ANY WARRANTY; without even the implied warranty of Laurent@814: #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Laurent@814: #General Public License for more details. Laurent@814: # Laurent@814: #You should have received a copy of the GNU General Public Laurent@814: #License along with this library; if not, write to the Free Software Laurent@814: #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Laurent@814: Laurent@814: import re Laurent@814: import datetime Laurent@814: Laurent@814: import wx Laurent@814: Laurent@814: #------------------------------------------------------------------------------- Laurent@814: # Helpers Laurent@814: #------------------------------------------------------------------------------- Laurent@814: Laurent@814: LOCATIONDATATYPES = {"X" : ["BOOL"], Laurent@814: "B" : ["SINT", "USINT", "BYTE", "STRING"], Laurent@814: "W" : ["INT", "UINT", "WORD", "WSTRING"], Laurent@814: "D" : ["DINT", "UDINT", "REAL", "DWORD"], Laurent@814: "L" : ["LINT", "ULINT", "LREAL", "LWORD"]} Laurent@814: Laurent@814: def gen_get_function(f): Laurent@814: def get_function(v): Laurent@814: try: Laurent@814: return f(v) Laurent@814: except: Laurent@814: return None Laurent@814: return get_function Laurent@814: Laurent@878: def gen_get_string(delimiter): Laurent@878: STRING_MODEL = re.compile("%(delimiter)s([^%(delimiter)s]*)%(delimiter)s$" % {"delimiter": delimiter}) Laurent@878: def get_string(v): Laurent@878: result = STRING_MODEL.match(v) Laurent@878: if result is not None: Laurent@878: return result.group(1) Laurent@878: return None Laurent@878: return get_string Laurent@878: Laurent@814: getinteger = gen_get_function(int) Laurent@814: getfloat = gen_get_function(float) Laurent@878: getstring = gen_get_string("'") Laurent@878: getwstring = gen_get_string('"') Laurent@814: Laurent@814: SECOND = 1000000 Laurent@814: MINUTE = 60 * SECOND Laurent@814: HOUR = 60 * MINUTE Laurent@814: DAY = 24 * HOUR Laurent@814: Laurent@878: IEC_TIME_MODEL = re.compile("(?:(?:T|TIME)#)?(-)?(?:(%(float)s)D_?)?(?:(%(float)s)H_?)?(?:(%(float)s)M(?!S)_?)?(?:(%(float)s)S_?)?(?:(%(float)s)MS)?$" % {"float": "[0-9]+(?:\.[0-9]+)?"}) Laurent@878: IEC_DATE_MODEL = re.compile("(?:(?:D|DATE)#)?([0-9]{4})-([0-9]{2})-([0-9]{2})$") Laurent@878: IEC_DATETIME_MODEL = re.compile("(?:(?:DT|DATE_AND_TIME)#)?([0-9]{4})-([0-9]{2})-([0-9]{2})-([0-9]{2}):([0-9]{2}):([0-9]{2}(?:\.[0-9]+)?)$") Laurent@878: IEC_TIMEOFDAY_MODEL = re.compile("(?:(?:TOD|TIME_OF_DAY)#)?([0-9]{2}):([0-9]{2}):([0-9]{2}(?:\.[0-9]+)?)$") Laurent@814: Laurent@814: def gettime(v): Laurent@814: result = IEC_TIME_MODEL.match(v.upper()) Laurent@814: if result is not None: Laurent@814: negative, days, hours, minutes, seconds, milliseconds = result.groups() Laurent@814: microseconds = 0 Laurent@814: not_null = False Laurent@814: for value, factor in [(days, DAY), Laurent@814: (hours, HOUR), Laurent@814: (minutes, MINUTE), Laurent@814: (seconds, SECOND), Laurent@814: (milliseconds, 1000)]: Laurent@814: if value is not None: Laurent@814: microseconds += float(value) * factor Laurent@814: not_null = True Laurent@814: if not not_null: Laurent@814: return None Laurent@814: if negative is not None: Laurent@814: microseconds = -microseconds Laurent@814: return datetime.timedelta(microseconds=microseconds) Laurent@814: Laurent@814: else: Laurent@814: return None Laurent@814: Laurent@814: def getdate(v): Laurent@814: result = IEC_DATE_MODEL.match(v.upper()) Laurent@814: if result is not None: Laurent@814: year, month, day = result.groups() Laurent@814: try: Laurent@814: date = datetime.datetime(int(year), int(month), int(day)) Laurent@814: except ValueError, e: Laurent@814: return None Laurent@814: base_date = datetime.datetime(1970, 1, 1) Laurent@814: return date - base_date Laurent@814: else: Laurent@814: return None Laurent@814: Laurent@814: def getdatetime(v): Laurent@814: result = IEC_DATETIME_MODEL.match(v.upper()) Laurent@814: if result is not None: Laurent@814: year, month, day, hours, minutes, seconds = result.groups() Laurent@814: try: Laurent@814: date = datetime.datetime(int(year), int(month), int(day), int(hours), int(minutes), int(float(seconds)), int((float(second) * SECOND) % SECOND)) Laurent@814: except ValueError, e: Laurent@814: return None Laurent@814: base_date = datetime.datetime(1970, 1, 1) Laurent@814: return date - base_date Laurent@814: else: Laurent@814: return None Laurent@814: Laurent@814: def gettimeofday(v): Laurent@814: result = IEC_TIMEOFDAY_MODEL.match(v.upper()) Laurent@814: if result is not None: Laurent@814: hours, minutes, seconds = result.groups() Laurent@814: microseconds = 0 Laurent@814: for value, factor in [(hours, HOUR), Laurent@814: (minutes, MINUTE), Laurent@814: (seconds, SECOND)]: Laurent@814: microseconds += float(value) * factor Laurent@814: return datetime.timedelta(microseconds=microseconds) Laurent@814: else: Laurent@814: return None Laurent@814: Laurent@814: GetTypeValue = {"BOOL": lambda x: {"TRUE": True, "FALSE": False, "0": False, "1": True}.get(x.upper(), None), Laurent@814: "SINT": getinteger, Laurent@814: "INT": getinteger, Laurent@814: "DINT": getinteger, Laurent@814: "LINT": getinteger, Laurent@814: "USINT": getinteger, Laurent@814: "UINT": getinteger, Laurent@814: "UDINT": getinteger, Laurent@814: "ULINT": getinteger, Laurent@814: "BYTE": getinteger, Laurent@814: "WORD": getinteger, Laurent@814: "DWORD": getinteger, Laurent@814: "LWORD": getinteger, Laurent@814: "REAL": getfloat, Laurent@814: "LREAL": getfloat, Laurent@814: "STRING": getstring, Laurent@878: "WSTRING": getwstring, Laurent@814: "TIME": gettime, Laurent@814: "DATE": getdate, Laurent@814: "DT": getdatetime, Laurent@814: "TOD": gettimeofday} Laurent@814: Laurent@814: #------------------------------------------------------------------------------- Laurent@814: # Force Variable Dialog Laurent@814: #------------------------------------------------------------------------------- Laurent@814: Laurent@814: class ForceVariableDialog(wx.TextEntryDialog): Laurent@814: Laurent@814: def __init__(self, parent, iec_type, defaultValue=""): Laurent@814: wx.TextEntryDialog.__init__(self, parent, message = _("Forcing Variable Value"), Laurent@814: caption = _("Please enter value for a \"%s\" variable:") % iec_type, defaultValue = defaultValue, Laurent@814: style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition) Laurent@814: Laurent@814: self.IEC_Type = iec_type Laurent@814: Laurent@814: self.Bind(wx.EVT_BUTTON, self.OnOK, Laurent@814: self.GetSizer().GetItem(2).GetSizer().GetItem(1).GetSizer().GetAffirmativeButton()) Laurent@814: Laurent@814: def OnOK(self, event): Laurent@814: message = None Laurent@814: value = self.GetSizer().GetItem(1).GetWindow().GetValue() Laurent@814: if value == "": Laurent@814: message = _("You must type a value!") Laurent@814: elif GetTypeValue[self.IEC_Type](value) is None: Laurent@814: message = _("Invalid value \"%s\" for \"%s\" variable!") % (value, self.IEC_Type) Laurent@814: if message is not None: Laurent@814: dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR) Laurent@814: dialog.ShowModal() Laurent@814: dialog.Destroy() Laurent@814: else: Laurent@814: self.EndModal(wx.ID_OK) Laurent@814: event.Skip() Laurent@814: Laurent@814: def GetValue(self): Laurent@814: return GetTypeValue[self.IEC_Type](wx.TextEntryDialog.GetValue(self))