--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/DataTypeEditor.py Thu Dec 06 18:05:29 2007 +0100
@@ -0,0 +1,488 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor
+#based on the plcopen standard.
+#
+#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
+#
+#See COPYING file for copyrights details.
+#
+#This library 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.1 of the License, or (at your option) any later version.
+#
+#This library 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 library; if not, write to the Free Software
+#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import wx
+import wx.grid
+import wx.gizmos
+from plcopen.structures import GetDataTypeRange, IEC_KEYWORDS
+
+if wx.VERSION >= (2, 8, 0):
+ import wx.aui
+
+ class MDIDataTypeEditor(wx.aui.AuiMDIChildFrame):
+ def __init__(self, parent, tagname, window, controler):
+ wx.aui.AuiMDIChildFrame.__init__(self, parent, -1, title = "")
+
+ sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ self.Viewer = DataTypeEditor(self, tagname, window, controler)
+
+ sizer.AddWindow(self.Viewer, 1, border=0, flag=wx.GROW)
+
+ self.SetSizer(sizer)
+
+ def GetViewer(self):
+ return self.Viewer
+
+#-------------------------------------------------------------------------------
+# Configuration Editor class
+#-------------------------------------------------------------------------------
+
+[ID_DATATYPEEDITOR, ID_DATATYPEEDITORSTATICBOX,
+ ID_DATATYPEEDITORDERIVATIONTYPE, ID_DATATYPEEDITORDIRECTLYPANEL,
+ ID_DATATYPEEDITORSUBRANGEPANEL, ID_DATATYPEEDITORDIRECTLYBASETYPE,
+ ID_DATATYPEEDITORSUBRANGEBASETYPE, ID_DATATYPEEDITORSUBRANGEMINIMUM,
+ ID_DATATYPEEDITORSUBRANGEMAXIMUM, ID_DATATYPEEDITORDIRECTLYINITIALVALUE,
+ ID_DATATYPEEDITORSUBRANGEINITIALVALUE, ID_DATATYPEEDITORENUMERATEDPANEL,
+ ID_DATATYPEEDITORENUMERATEDVALUES, ID_DATATYPEEDITORENUMERATEDINITIALVALUE,
+ ID_DATATYPEEDITORARRAYPANEL, ID_DATATYPEEDITORARRAYBASETYPE,
+ ID_DATATYPEEDITORARRAYDIMENSIONS, ID_DATATYPEEDITORARRAYINITIALVALUE,
+ ID_DATATYPEEDITORSTATICTEXT1, ID_DATATYPEEDITORSTATICTEXT2,
+ ID_DATATYPEEDITORSTATICTEXT3, ID_DATATYPEEDITORSTATICTEXT4,
+ ID_DATATYPEEDITORSTATICTEXT5, ID_DATATYPEEDITORSTATICTEXT6,
+ ID_DATATYPEEDITORSTATICTEXT7, ID_DATATYPEEDITORSTATICTEXT8,
+ ID_DATATYPEEDITORSTATICTEXT9, ID_DATATYPEEDITORSTATICTEXT10,
+] = [wx.NewId() for _init_ctrls in range(28)]
+
+class DataTypeEditor(wx.Panel):
+
+ def _init_coll_MainSizer_Items(self, parent):
+ parent.AddSizer(self.TopSizer, 0, border=5, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
+ parent.AddSizer(self.TypeInfosSizer, 0, border=5, flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT)
+
+ def _init_coll_MainSizer_Growables(self, parent):
+ parent.AddGrowableCol(0)
+ parent.AddGrowableRow(1)
+
+ def _init_coll_TopSizer_Items(self, parent):
+ parent.AddWindow(self.staticText1, 0, border=5, flag=wx.GROW|wx.LEFT)
+ parent.AddWindow(self.DerivationType, 0, border=0, flag=wx.GROW)
+
+ def _init_coll_TypeInfosSizer_Items(self, parent):
+ parent.AddWindow(self.DirectlyPanel, 1, border=0, flag=wx.ALL)
+ parent.AddWindow(self.SubrangePanel, 1, border=0, flag=wx.ALL)
+ parent.AddWindow(self.EnumeratedPanel, 1, border=0, flag=wx.GROW|wx.ALL)
+ parent.AddWindow(self.ArrayPanel, 1, border=0, flag=wx.ALL)
+
+ def _init_coll_DirectlyPanelSizer_Items(self, parent):
+ parent.AddWindow(self.staticText2, 1, border=5, flag=wx.GROW|wx.ALL)
+ parent.AddWindow(self.DirectlyBaseType, 1, border=5, flag=wx.GROW|wx.ALL)
+ parent.AddWindow(self.staticText3, 1, border=5, flag=wx.GROW|wx.ALL)
+ parent.AddWindow(self.DirectlyInitialValue, 1, border=5, flag=wx.GROW|wx.ALL)
+
+ def _init_coll_SubrangePanelSizer_Items(self, parent):
+ parent.AddWindow(self.staticText4, 1, border=5, flag=wx.GROW|wx.ALL)
+ parent.AddWindow(self.SubrangeBaseType, 1, border=5, flag=wx.GROW|wx.ALL)
+ parent.AddWindow(self.staticText5, 1, border=5, flag=wx.GROW|wx.ALL)
+ parent.AddWindow(self.SubrangeInitialValue, 1, border=5, flag=wx.GROW|wx.ALL)
+ parent.AddWindow(self.staticText6, 1, border=5, flag=wx.GROW|wx.ALL)
+ parent.AddWindow(self.SubrangeMinimum, 1, border=5, flag=wx.GROW|wx.ALL)
+ parent.AddWindow(wx.Size(0, 0), 1, border=5, flag=wx.GROW|wx.ALL)
+ parent.AddWindow(wx.Size(0, 0), 1, border=5, flag=wx.GROW|wx.ALL)
+ parent.AddWindow(self.staticText7, 1, border=5, flag=wx.GROW|wx.ALL)
+ parent.AddWindow(self.SubrangeMaximum, 1, border=5, flag=wx.GROW|wx.ALL)
+
+ def _init_coll_EnumeratedPanelSizer_Items(self, parent):
+ parent.AddWindow(self.EnumeratedValues, 2, border=5, flag=wx.GROW|wx.ALL)
+ parent.AddWindow(self.staticText8, 1, border=5, flag=wx.GROW|wx.ALL)
+ parent.AddWindow(self.EnumeratedInitialValue, 1, border=5, flag=wx.ALL)
+
+ def _init_coll_ArrayPanelSizer_Items(self, parent):
+ parent.AddSizer(self.ArrayPanelLeftSizer, 0, border=0, flag=wx.GROW)
+ parent.AddSizer(self.ArrayPanelRightSizer, 0, border=0, flag=wx.GROW)
+ parent.AddWindow(self.ArrayDimensions, 0, border=5, flag=wx.GROW|wx.ALL)
+
+ def _init_coll_ArrayPanelSizer_Growables(self, parent):
+ parent.AddGrowableCol(0)
+ parent.AddGrowableCol(1)
+ parent.AddGrowableRow(1)
+
+ def _init_coll_ArrayPanelLeftSizer_Items(self, parent):
+ parent.AddWindow(self.staticText9, 1, border=5, flag=wx.GROW|wx.ALL)
+ parent.AddWindow(self.ArrayBaseType, 1, border=5, flag=wx.GROW|wx.ALL)
+
+ def _init_coll_ArrayPanelRightSizer_Items(self, parent):
+ parent.AddWindow(self.staticText10, 1, border=5, flag=wx.GROW|wx.ALL)
+ parent.AddWindow(self.ArrayInitialValue, 1, border=5, flag=wx.GROW|wx.ALL)
+
+ def _init_sizers(self):
+ self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10)
+ self.TopSizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.TypeInfosSizer = wx.StaticBoxSizer(self.staticbox, wx.HORIZONTAL)
+ self.DirectlyPanelSizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.SubrangePanelSizer = wx.GridSizer(cols=4, hgap=0, rows=3, vgap=0)
+ self.EnumeratedPanelSizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.ArrayPanelSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=2, vgap=0)
+ self.ArrayPanelLeftSizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.ArrayPanelRightSizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ self._init_coll_MainSizer_Items(self.MainSizer)
+ self._init_coll_MainSizer_Growables(self.MainSizer)
+ self._init_coll_TopSizer_Items(self.TopSizer)
+ self._init_coll_TypeInfosSizer_Items(self.TypeInfosSizer)
+ self._init_coll_DirectlyPanelSizer_Items(self.DirectlyPanelSizer)
+ self._init_coll_SubrangePanelSizer_Items(self.SubrangePanelSizer)
+ self._init_coll_EnumeratedPanelSizer_Items(self.EnumeratedPanelSizer)
+ self._init_coll_ArrayPanelSizer_Items(self.ArrayPanelSizer)
+ self._init_coll_ArrayPanelSizer_Growables(self.ArrayPanelSizer)
+ self._init_coll_ArrayPanelLeftSizer_Items(self.ArrayPanelLeftSizer)
+ self._init_coll_ArrayPanelRightSizer_Items(self.ArrayPanelRightSizer)
+
+ self.SetSizer(self.MainSizer)
+ self.DirectlyPanel.SetSizer(self.DirectlyPanelSizer)
+ self.SubrangePanel.SetSizer(self.SubrangePanelSizer)
+ self.EnumeratedPanel.SetSizer(self.EnumeratedPanelSizer)
+ self.ArrayPanel.SetSizer(self.ArrayPanelSizer)
+
+ def _init_ctrls(self, prnt):
+ wx.Panel.__init__(self, id=ID_DATATYPEEDITOR, name='', parent=prnt,
+ size=wx.Size(0, 0), style=wx.SUNKEN_BORDER)
+
+ self.staticbox = wx.StaticBox(id=ID_DATATYPEEDITORSTATICBOX,
+ label='Type infos:', name='staticBox1', parent=self,
+ pos=wx.Point(0, 0), size=wx.Size(0, 0), style=0)
+
+ self.staticText1 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT1,
+ label='Derivation Type:', name='staticText1', parent=self,
+ pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0)
+
+ self.DerivationType = wx.Choice(id=ID_DATATYPEEDITORDERIVATIONTYPE,
+ name='DerivationType', parent=self, pos=wx.Point(0, 0),
+ size=wx.Size(200, 24), style=0)
+ self.Bind(wx.EVT_CHOICE, self.OnDerivationTypeChanged, id=ID_DATATYPEEDITORDERIVATIONTYPE)
+
+ # Panel for Directly derived data types
+
+ self.DirectlyPanel = wx.Panel(id=ID_DATATYPEEDITORDIRECTLYPANEL,
+ name='DirectlyPanel', parent=self, pos=wx.Point(0, 0),
+ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
+
+ self.staticText2 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT2,
+ label='Base Type:', name='staticText2', parent=self.DirectlyPanel,
+ pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0)
+
+ self.DirectlyBaseType = wx.Choice(id=ID_DATATYPEEDITORDIRECTLYBASETYPE,
+ name='DirectlyBaseType', parent=self.DirectlyPanel, pos=wx.Point(0, 0),
+ size=wx.Size(0, 24), style=wx.TAB_TRAVERSAL)
+ self.Bind(wx.EVT_CHOICE, self.OnInfosChanged, id=ID_DATATYPEEDITORDIRECTLYBASETYPE)
+
+ self.staticText3 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT3,
+ label='Initial Value:', name='staticText3', parent=self.DirectlyPanel,
+ pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0)
+
+ self.DirectlyInitialValue = wx.TextCtrl(id=ID_DATATYPEEDITORDIRECTLYINITIALVALUE,
+ name='DirectlyInitialValue', parent=self.DirectlyPanel, pos=wx.Point(0, 0),
+ size=wx.Size(0, 24), style=wx.TAB_TRAVERSAL|wx.TE_PROCESS_ENTER)
+ self.Bind(wx.EVT_TEXT_ENTER, self.OnInfosChanged, id=ID_DATATYPEEDITORDIRECTLYINITIALVALUE)
+
+ # Panel for Subrange data types
+
+ self.SubrangePanel = wx.Panel(id=ID_DATATYPEEDITORSUBRANGEPANEL,
+ name='SubrangePanel', parent=self, pos=wx.Point(0, 0),
+ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
+
+ self.staticText4 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT4,
+ label='Base Type:', name='staticText4', parent=self.SubrangePanel,
+ pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0)
+
+ self.SubrangeBaseType = wx.Choice(id=ID_DATATYPEEDITORSUBRANGEBASETYPE,
+ name='SubrangeBaseType', parent=self.SubrangePanel, pos=wx.Point(0, 0),
+ size=wx.Size(0, 24), style=wx.TAB_TRAVERSAL)
+ self.Bind(wx.EVT_CHOICE, self.OnSubrangeBaseTypeChanged, id=ID_DATATYPEEDITORSUBRANGEBASETYPE)
+
+ self.staticText5 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT5,
+ label='Initial Value:', name='staticText5', parent=self.SubrangePanel,
+ pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0)
+
+ self.SubrangeInitialValue = wx.SpinCtrl(id=ID_DATATYPEEDITORSUBRANGEINITIALVALUE,
+ name='SubrangeInitialValue', parent=self.SubrangePanel, pos=wx.Point(0, 0),
+ size=wx.Size(0, 24), style=wx.TAB_TRAVERSAL)
+ self.Bind(wx.EVT_SPINCTRL, self.OnInfosChanged, id=ID_DATATYPEEDITORSUBRANGEINITIALVALUE)
+
+ self.staticText6 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT6,
+ label='Minimum:', name='staticText6', parent=self.SubrangePanel,
+ pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0)
+
+ self.SubrangeMinimum = wx.SpinCtrl(id=ID_DATATYPEEDITORSUBRANGEMINIMUM,
+ name='SubrangeMinimum', parent=self.SubrangePanel, pos=wx.Point(0, 0),
+ size=wx.Size(0, 24), style=wx.TAB_TRAVERSAL)
+ self.Bind(wx.EVT_SPINCTRL, self.OnSubrangeMinimumChanged, id=ID_DATATYPEEDITORSUBRANGEMINIMUM)
+
+ self.staticText7 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT7,
+ label='Maximum:', name='staticText7', parent=self.SubrangePanel,
+ pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0)
+
+ self.SubrangeMaximum = wx.SpinCtrl(id=ID_DATATYPEEDITORSUBRANGEMAXIMUM,
+ name='SubrangeMaximum', parent=self.SubrangePanel, pos=wx.Point(0, 0),
+ size=wx.Size(0, 24), style=wx.TAB_TRAVERSAL)
+ self.Bind(wx.EVT_SPINCTRL, self.OnSubrangeMaximumChanged, id=ID_DATATYPEEDITORSUBRANGEMAXIMUM)
+
+ # Panel for Enumerated data types
+
+ self.EnumeratedPanel = wx.Panel(id=ID_DATATYPEEDITORENUMERATEDPANEL,
+ name='EnumeratedPanel', parent=self, pos=wx.Point(0, 0),
+ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
+
+ self.EnumeratedValues = wx.gizmos.EditableListBox(id=ID_DATATYPEEDITORENUMERATEDVALUES,
+ name='EnumeratedValues', parent=self.EnumeratedPanel, label="Values:", pos=wx.Point(0, 0),
+ size=wx.Size(0, 0), style=wx.gizmos.EL_ALLOW_NEW | wx.gizmos.EL_ALLOW_EDIT | wx.gizmos.EL_ALLOW_DELETE)
+ self.EnumeratedValues.GetListCtrl().Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnEnumeratedValueEndEdit)
+ self.EnumeratedValues.GetNewButton().Bind(wx.EVT_BUTTON, self.OnEnumeratedValuesChanged)
+ self.EnumeratedValues.GetDelButton().Bind(wx.EVT_BUTTON, self.OnEnumeratedValuesChanged)
+ self.EnumeratedValues.GetUpButton().Bind(wx.EVT_BUTTON, self.OnEnumeratedValuesChanged)
+ self.EnumeratedValues.GetDownButton().Bind(wx.EVT_BUTTON, self.OnEnumeratedValuesChanged)
+
+ self.staticText8 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT8,
+ label='Initial Value:', name='staticText8', parent=self.EnumeratedPanel,
+ pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0)
+
+ self.EnumeratedInitialValue = wx.Choice(id=ID_DATATYPEEDITORENUMERATEDINITIALVALUE,
+ name='EnumeratedInitialValue', parent=self.EnumeratedPanel, pos=wx.Point(0, 0),
+ size=wx.Size(0, 24), style=wx.TAB_TRAVERSAL|wx.TE_PROCESS_ENTER)
+ self.Bind(wx.EVT_CHOICE, self.OnInfosChanged, id=ID_DATATYPEEDITORENUMERATEDINITIALVALUE)
+
+ # Panel for Array data types
+
+ self.ArrayPanel = wx.Panel(id=ID_DATATYPEEDITORARRAYPANEL,
+ name='ArrayPanel', parent=self, pos=wx.Point(0, 0),
+ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
+
+ self.staticText9 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT9,
+ label='Base Type:', name='staticText9', parent=self.ArrayPanel,
+ pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0)
+
+ self.ArrayBaseType = wx.Choice(id=ID_DATATYPEEDITORARRAYBASETYPE,
+ name='SubrangeBaseType', parent=self.ArrayPanel, pos=wx.Point(0, 0),
+ size=wx.Size(0, 24), style=wx.TAB_TRAVERSAL)
+ self.Bind(wx.EVT_CHOICE, self.OnInfosChanged, id=ID_DATATYPEEDITORARRAYBASETYPE)
+
+ self.ArrayDimensions = wx.gizmos.EditableListBox(id=ID_DATATYPEEDITORARRAYDIMENSIONS,
+ name='ArrayDimensions', parent=self.ArrayPanel, label="Dimensions:", pos=wx.Point(0, 0),
+ size=wx.Size(0, 24), style=wx.gizmos.EL_ALLOW_NEW | wx.gizmos.EL_ALLOW_EDIT | wx.gizmos.EL_ALLOW_DELETE)
+ self.ArrayDimensions.GetListCtrl().Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnDimensionsChanged)
+ self.ArrayDimensions.GetNewButton().Bind(wx.EVT_BUTTON, self.OnDimensionsChanged)
+ self.ArrayDimensions.GetDelButton().Bind(wx.EVT_BUTTON, self.OnDimensionsChanged)
+ self.ArrayDimensions.GetUpButton().Bind(wx.EVT_BUTTON, self.OnDimensionsChanged)
+ self.ArrayDimensions.GetDownButton().Bind(wx.EVT_BUTTON, self.OnDimensionsChanged)
+
+ self.staticText10 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT10,
+ label='Initial Value:', name='staticText10', parent=self.ArrayPanel,
+ pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0)
+
+ self.ArrayInitialValue = wx.TextCtrl(id=ID_DATATYPEEDITORARRAYINITIALVALUE,
+ name='ArrayInitialValue', parent=self.ArrayPanel, pos=wx.Point(0, 0),
+ size=wx.Size(0, 24), style=wx.TAB_TRAVERSAL|wx.TE_PROCESS_ENTER)
+ self.Bind(wx.EVT_TEXT_ENTER, self.OnInfosChanged, id=ID_DATATYPEEDITORARRAYINITIALVALUE)
+
+ self._init_sizers()
+
+ def __init__(self, parent, tagname, window, controler):
+ self._init_ctrls(parent)
+
+ self.DerivationType.Append("Directly")
+ self.DerivationType.Append("Subrange")
+ self.DerivationType.Append("Enumerated")
+ self.DerivationType.Append("Array")
+ self.SubrangePanel.Hide()
+ self.EnumeratedPanel.Hide()
+ self.ArrayPanel.Hide()
+ self.CurrentPanel = "Directly"
+
+ self.ParentWindow = window
+ self.Controler = controler
+ self.TagName = tagname
+
+ def OnEnumeratedValueEndEdit(self, event):
+ text = event.GetText()
+ if text.upper() in [string.upper() for string in self.EnumeratedValues.GetStrings()]:
+ message = wx.MessageDialog(self, "\"%s\" value already defined!"%text, "Error", wx.OK|wx.ICON_ERROR)
+ message.ShowModal()
+ message.Destroy()
+ event.Veto()
+ elif text.upper() in IEC_KEYWORDS:
+ message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%text, "Error", wx.OK|wx.ICON_ERROR)
+ message.ShowModal()
+ message.Destroy()
+ else:
+ wx.CallAfter(self.RefreshEnumeratedValues)
+ wx.CallAfter(self.RefreshTypeInfos)
+ event.Skip()
+
+ def OnEnumeratedValuesChanged(self, event):
+ wx.CallAfter(self.RefreshEnumeratedValues)
+ wx.CallAfter(self.RefreshTypeInfos)
+ event.Skip()
+
+ def SetTagName(self, tagname):
+ self.TagName = tagname
+
+ def GetTagName(self):
+ return self.TagName
+
+ def IsViewing(self, tagname):
+ return self.TagName == tagname
+
+ def SetMode(self, mode):
+ pass
+
+ def ResetBuffer(self):
+ pass
+
+ def RefreshView(self):
+ self.DirectlyBaseType.Clear()
+ self.ArrayBaseType.Clear()
+ for datatype in self.Controler.GetDataTypes(self.TagName):
+ self.DirectlyBaseType.Append(datatype)
+ self.ArrayBaseType.Append(datatype)
+ self.DirectlyBaseType.SetSelection(0)
+ self.SubrangeBaseType.Clear()
+ words = self.TagName.split("::")
+ for base_type in self.Controler.GetSubrangeTypes():
+ self.SubrangeBaseType.Append(base_type)
+ self.SubrangeBaseType.SetSelection(0)
+ self.RefreshBoundsRange()
+ type_infos = self.Controler.GetDataTypeInfos(self.TagName)
+ if type_infos is not None:
+ self.DerivationType.SetStringSelection(type_infos["type"])
+ if type_infos["type"] == "Directly":
+ self.DirectlyBaseType.SetStringSelection(type_infos["base_type"])
+ self.DirectlyInitialValue.SetValue(type_infos["initial"])
+ elif type_infos["type"] == "Subrange":
+ self.SubrangeBaseType.SetStringSelection(type_infos["base_type"])
+ self.RefreshBoundsRange()
+ self.SubrangeMinimum.SetValue(type_infos["min"])
+ self.SubrangeMaximum.SetValue(type_infos["max"])
+ self.RefreshSubrangeInitialValueRange()
+ if type_infos["initial"] != "":
+ self.SubrangeInitialValue.SetValue(int(type_infos["initial"]))
+ else:
+ self.SubrangeInitialValue.SetValue(type_infos["min"])
+ elif type_infos["type"] == "Enumerated":
+ self.EnumeratedValues.SetStrings(type_infos["values"])
+ self.RefreshEnumeratedValues()
+ self.EnumeratedInitialValue.SetStringSelection(type_infos["initial"])
+ elif type_infos["type"] == "Array":
+ self.ArrayBaseType.SetStringSelection(type_infos["base_type"])
+ self.ArrayDimensions.SetStrings(type_infos["dimensions"])
+ self.ArrayInitialValue.SetValue(type_infos["initial"])
+ self.RefreshDisplayedInfos()
+
+ def OnDerivationTypeChanged(self, event):
+ self.RefreshDisplayedInfos()
+ self.RefreshTypeInfos()
+ event.Skip()
+
+ def OnInfosChanged(self, event):
+ self.RefreshTypeInfos()
+ event.Skip()
+
+ def OnSubrangeBaseTypeChanged(self, event):
+ self.RefreshBoundsRange()
+ self.RefreshTypeInfos()
+ event.Skip()
+
+ def OnSubrangeMinimumChanged(self, event):
+ wx.CallAfter(self.SubrangeMinimum.SetValue, min(self.SubrangeMaximum.GetValue(), self.SubrangeMinimum.GetValue()))
+ wx.CallAfter(self.RefreshSubrangeInitialValueRange)
+ wx.CallAfter(self.RefreshTypeInfos)
+ event.Skip()
+
+ def OnSubrangeMaximumChanged(self, event):
+ wx.CallAfter(self.SubrangeMaximum.SetValue, max(self.SubrangeMinimum.GetValue(), self.SubrangeMaximum.GetValue()))
+ wx.CallAfter(self.RefreshSubrangeInitialValueRange)
+ wx.CallAfter(self.RefreshTypeInfos)
+ event.Skip()
+
+ def OnDimensionsChanged(self, event):
+ wx.CallAfter(self.RefreshTypeInfos)
+ event.Skip()
+
+ def RefreshDisplayedInfos(self):
+ selected = self.DerivationType.GetStringSelection()
+ if selected != self.CurrentPanel:
+ if self.CurrentPanel == "Directly":
+ self.DirectlyPanel.Hide()
+ elif self.CurrentPanel == "Subrange":
+ self.SubrangePanel.Hide()
+ elif self.CurrentPanel == "Enumerated":
+ self.EnumeratedPanel.Hide()
+ elif self.CurrentPanel == "Array":
+ self.ArrayPanel.Hide()
+ self.CurrentPanel = selected
+ if selected == "Directly":
+ self.DirectlyPanel.Show()
+ elif selected == "Subrange":
+ self.SubrangePanel.Show()
+ elif selected == "Enumerated":
+ self.EnumeratedPanel.Show()
+ elif selected == "Array":
+ self.ArrayPanel.Show()
+ self.MainSizer.Layout()
+
+ def RefreshEnumeratedValues(self):
+ selected = self.EnumeratedInitialValue.GetStringSelection()
+ self.EnumeratedInitialValue.Clear()
+ self.EnumeratedInitialValue.Append("")
+ for value in self.EnumeratedValues.GetStrings():
+ self.EnumeratedInitialValue.Append(value)
+ self.EnumeratedInitialValue.SetStringSelection(selected)
+
+ def RefreshBoundsRange(self):
+ range = GetDataTypeRange(self.SubrangeBaseType.GetStringSelection())
+ if range is not None:
+ min_value, max_value = range
+ self.SubrangeMinimum.SetRange(min_value, max_value)
+ self.SubrangeMinimum.SetValue(min(max(min_value, self.SubrangeMinimum.GetValue()), max_value))
+ self.SubrangeMaximum.SetRange(min_value, max_value)
+ self.SubrangeMaximum.SetValue(min(max(min_value, self.SubrangeMaximum.GetValue()), max_value))
+
+ def RefreshSubrangeInitialValueRange(self):
+ self.SubrangeInitialValue.SetRange(self.SubrangeMinimum.GetValue(), self.SubrangeMaximum.GetValue())
+
+ def RefreshTypeInfos(self):
+ selected = self.DerivationType.GetStringSelection()
+ infos = {"type" : selected}
+ if selected == "Directly":
+ infos["base_type"] = self.DirectlyBaseType.GetStringSelection()
+ infos["initial"] = self.DirectlyInitialValue.GetValue()
+ elif selected == "Subrange":
+ infos["base_type"] = self.SubrangeBaseType.GetStringSelection()
+ infos["min"] = self.SubrangeMinimum.GetValue()
+ infos["max"] = self.SubrangeMaximum.GetValue()
+ initial_value = self.SubrangeInitialValue.GetValue()
+ if initial_value == infos["min"]:
+ infos["initial"] = ""
+ else:
+ infos["initial"] = str(initial_value)
+ elif selected == "Enumerated":
+ infos["values"] = self.EnumeratedValues.GetStrings()
+ infos["initial"] = self.EnumeratedInitialValue.GetStringSelection()
+ elif selected == "Array":
+ infos["base_type"] = self.ArrayBaseType.GetStringSelection()
+ infos["dimensions"] = self.ArrayDimensions.GetStrings()
+ infos["initial"] = self.ArrayInitialValue.GetValue()
+ self.Controler.SetDataTypeInfos(self.TagName, infos)
+ self.ParentWindow.RefreshTitle()
+ self.ParentWindow.RefreshEditMenu()
+
--- a/PLCControler.py Tue Nov 27 12:58:34 2007 +0100
+++ b/PLCControler.py Thu Dec 06 18:05:29 2007 +0100
@@ -37,7 +37,10 @@
duration_model = re.compile("(?:([0-9]{1,2})h)?(?:([0-9]{1,2})m(?!s))?(?:([0-9]{1,2})s)?(?:([0-9]{1,3}(?:.[0-9]*)?)ms)?")
[ITEM_UNEDITABLE, ITEM_PROJECT, ITEM_POU, ITEM_CLASS, ITEM_VARIABLE,
- ITEM_TRANSITION, ITEM_ACTION, ITEM_CONFIGURATION, ITEM_RESOURCE] = range(9)
+ ITEM_TRANSITION, ITEM_ACTION, ITEM_CONFIGURATION, ITEM_RESOURCE,
+ ITEM_DATATYPE] = range(10)
+
+ScriptDirectory = os.path.split(os.path.realpath(__file__))[0]
"""
pyxsval is not complete and the parts that are not supported print some error
@@ -167,6 +170,8 @@
self.FilePath = ""
self.FileName = ""
self.ProgramFilePath = ""
+ self.RefreshDataTypeUsingTree()
+ self.RefreshDataTypes()
self.RefreshPouUsingTree()
self.RefreshBlockTypes()
@@ -192,6 +197,12 @@
self.ProjectBuffer = UndoBuffer(self.Copy(self.Project), False)
self.Buffering = False
+ # Return project data type names
+ def GetProjectDataTypeNames(self):
+ if self.Project:
+ return [datatype.getName() for datatype in self.Project.getDataTypes()]
+ return []
+
# Return project pou names
def GetProjectPouNames(self):
if self.Project:
@@ -263,6 +274,9 @@
def GetProjectInfos(self):
if self.Project:
infos = {"name": self.Project.getName(), "type": ITEM_PROJECT}
+ datatypes = {"name": "Data Types", "type": ITEM_UNEDITABLE, "values":[]}
+ for datatype in self.Project.getDataTypes():
+ datatypes["values"].append({"name": datatype.getName(), "type": ITEM_DATATYPE, "values": []})
pou_types = {"function": {"name": "Functions", "type": ITEM_UNEDITABLE, "values":[]},
"functionBlock": {"name": "Function Blocks", "type": ITEM_UNEDITABLE, "values":[]},
"program": {"name": "Programs", "type": ITEM_UNEDITABLE, "values":[]}}
@@ -294,11 +308,38 @@
config_infos["values"] = [resources]
configurations["values"].append(config_infos)
infos["values"] = [{"name": "Properties", "type": ITEM_UNEDITABLE, "values": []},
- pou_types["function"], pou_types["functionBlock"],
+ datatypes, pou_types["function"], pou_types["functionBlock"],
pou_types["program"], configurations]
return infos
return None
+ # Refresh the tree of user-defined data type cross-use
+ def RefreshDataTypeUsingTree(self):
+ # Reset the tree of user-defined pou cross-use
+ self.DataTypeUsingTree = {}
+ if self.Project:
+ datatypes = self.Project.getDataTypes()
+ # Reference all the user-defined data type names and initialize the tree of
+ # user-defined data type cross-use
+ datatypenames = [datatype.getName() for datatype in datatypes]
+ for name in datatypenames:
+ self.DataTypeUsingTree[name] = []
+ # Analyze each data type
+ for datatype in datatypes:
+ name = datatype.getName()
+ basetype_content = datatype.getBaseType().getContent()
+ if basetype_content["value"] is not None:
+ if basetype_content["name"] == "derived":
+ basetype_name = basetype_content["value"].getName()
+ if basetype_name in datatypenames and name not in self.DataTypeUsingTree[basetype_name]:
+ self.DataTypeUsingTree[basetype_name].append(name)
+ elif basetype_content["name"] in ["subrangeSigned", "subrangeUnsigned", "array"]:
+ base_type = basetype_content["value"].baseType.getContent()
+ if base_type["value"] is not None:
+ basetype_name = base_type["value"].getName()
+ if basetype_name in datatypenames and name not in self.DataTypeUsingTree[basetype_name]:
+ self.DataTypeUsingTree[basetype_name].append(name)
+
# Refresh the tree of user-defined pou cross-use
def RefreshPouUsingTree(self):
# Reset the tree of user-defined pou cross-use
@@ -317,9 +358,9 @@
# Extract variables from every varLists
for type, varlist in pou.getVars():
for var in varlist.getVariable():
- var_type = var.getType().getValue()
- if not isinstance(var_type, (StringType, UnicodeType)):
- typename = var_type.getName()
+ vartype_content = var.getType().getContent()
+ if vartype_content["value"] is not None:
+ typename = vartype_content["value"].getName()
if typename in pounames and name not in self.PouUsingTree[typename]:
self.PouUsingTree[typename].append(name)
bodytype = pou.getBodyType()
@@ -342,12 +383,34 @@
if typename != name and typename_model.search(text):
self.PouUsingTree[typename].append(name)
+ # Return if data type given by name is used by another data type or pou
+ def DataTypeIsUsed(self, name):
+ if name in self.DataTypeUsingTree:
+ return len(self.DataTypeUsingTree[name]) > 0
+ return False
+
# Return if pou given by name is used by another pou
def PouIsUsed(self, name):
if name in self.PouUsingTree:
return len(self.PouUsingTree[name]) > 0
return False
+ # Return if data type given by name is directly or undirectly used by the reference data type
+ def DataTypeIsUsedBy(self, name, reference):
+ if name in self.DataTypeUsingTree:
+ list = self.DataTypeUsingTree[name]
+ # Test if data type is directly used by reference
+ if reference in list:
+ return True
+ else:
+ # Test if data type is undirectly used by reference, by testing if data types
+ # that directly use data type is directly or undirectly used by reference
+ used = False
+ for element in list:
+ used |= self.DataTypeIsUsedBy(element, reference)
+ return used
+ return False
+
# Return if pou given by name is directly or undirectly used by the reference pou
def PouIsUsedBy(self, name, reference):
if name in self.PouUsingTree:
@@ -380,7 +443,22 @@
#-------------------------------------------------------------------------------
# Project Pous management functions
#-------------------------------------------------------------------------------
-
+
+ # Add a Data Type to Project
+ def ProjectAddDataType(self, datatype_name):
+ # Add the pou to project
+ self.Project.appendDataType(datatype_name)
+ self.RefreshDataTypeUsingTree()
+ self.RefreshDataTypes()
+ self.BufferProject()
+
+ # Remove a Data Type from project
+ def ProjectRemoveDataType(self, datatype_name):
+ self.Project.removeDataType(datatype_name)
+ self.RefreshDataTypeUsingTree()
+ self.RefreshDataTypes()
+ self.BufferProject()
+
# Add a Pou to Project
def ProjectAddPou(self, pou_name, pou_type, body_type):
# Add the pou to project
@@ -391,7 +469,7 @@
self.RefreshBlockTypes()
self.BufferProject()
- # Remove a pou from project
+ # Remove a Pou from project
def ProjectRemovePou(self, pou_name):
self.Project.removePou(pou_name)
self.RefreshPouUsingTree()
@@ -401,8 +479,6 @@
# Add a configuration to Project
def ProjectAddConfiguration(self, config_name):
self.Project.addConfiguration(config_name)
- self.RefreshPouUsingTree()
- self.RefreshBlockTypes()
self.BufferProject()
# Remove a configuration from project
@@ -413,8 +489,6 @@
# Add a resource to a configuration of the Project
def ProjectAddConfigurationResource(self, config_name, resource_name):
self.Project.addConfigurationResource(config_name, resource_name)
- self.RefreshPouUsingTree()
- self.RefreshBlockTypes()
self.BufferProject()
# Remove a resource from a configuration of the project
@@ -450,7 +524,15 @@
pou = self.Project.getPou(pou_name)
pou.removeAction(action_name)
self.BufferProject()
-
+
+ # Change the name of a pou
+ def ChangeDataTypeName(self, old_name, new_name):
+ # Found the pou corresponding to old name and change its name to new name
+ datatype = self.Project.getDataType(old_name)
+ datatype.setName(new_name)
+ self.Project.updateElementName(old_name, new_name)
+ self.BufferProject()
+
# Change the name of a pou
def ChangePouName(self, old_name, new_name):
# Found the pou corresponding to old name and change its name to new name
@@ -575,12 +657,12 @@
tempvar = plcopen.varListPlain_variable()
tempvar.setName(var["Name"])
var_type = plcopen.dataType()
- if GetBlockType(var["Type"]) != None:
+ if var["Type"] not in var_type.getChoices():
derived_type = plcopen.derived()
derived_type.setName(var["Type"])
- var_type.setValue(derived_type)
+ var_type.setContent("derived", derived_type)
else:
- var_type.setValue(var["Type"])
+ var_type.setContent(var["Type"], None)
tempvar.setType(var_type)
if var["Initial Value"] != "":
value = plcopen.value()
@@ -615,11 +697,11 @@
for varlist in configuration.getGlobalVars():
for var in varlist.getVariable():
tempvar = {"Name":var.getName(),"Class":"Global"}
- var_type = var.getType().getValue()
- if isinstance(var_type, (StringType, UnicodeType)):
- tempvar["Type"] = var_type
+ vartype_content = var.getType().getContent()
+ if vartype_content["value"] is None:
+ tempvar["Type"] = vartype_content["name"]
else:
- tempvar["Type"] = var_type.getName()
+ tempvar["Type"] = vartype_content["value"].getName()
tempvar["Edit"] = True
initial = var.getInitialValue()
if initial:
@@ -663,11 +745,11 @@
for varlist in resource.getGlobalVars():
for var in varlist.getVariable():
tempvar = {"Name":var.getName(),"Class":"Global"}
- var_type = var.getType().getValue()
- if isinstance(var_type, (StringType, UnicodeType)):
- tempvar["Type"] = var_type
+ vartype_content = var.getType().getContent()
+ if vartype_content["value"] is None:
+ tempvar["Type"] = vartype_content["name"]
else:
- tempvar["Type"] = var_type.getName()
+ tempvar["Type"] = vartype_content["value"].getName()
tempvar["Edit"] = True
initial = var.getInitialValue()
if initial:
@@ -704,12 +786,12 @@
for type, varlist in pou.getVars():
for var in varlist.getVariable():
tempvar = {"Name":var.getName(),"Class":type}
- var_type = var.getType().getValue()
- if isinstance(var_type, (StringType, UnicodeType)):
- tempvar["Type"] = var_type
+ vartype_content = var.getType().getContent()
+ if vartype_content["value"] is None:
+ tempvar["Type"] = vartype_content["name"]
tempvar["Edit"] = True
else:
- tempvar["Type"] = var_type.getName()
+ tempvar["Type"] = vartype_content["value"].getName()
tempvar["Edit"] = not pou.hasBlock(tempvar["Name"])
initial = var.getInitialValue()
if initial:
@@ -754,7 +836,12 @@
return_type = plcopen.dataType()
pou.interface.setReturnType(return_type)
# Change return type
- return_type.setValue(type)
+ if type in self.GetBaseTypes():
+ return_type.setContent(type, None)
+ else:
+ derived_type = plcopen.derived()
+ derived_type.setName(type)
+ return_type.setContent("derived", derived_type)
self.RefreshBlockTypes()
def UpdateProjectUsedPous(self, old_name, new_name):
@@ -778,9 +865,39 @@
# Return the return type if there is one
return_type = pou.interface.getReturnType()
if return_type:
- return return_type.getValue()
+ returntype_content = return_type.getContent()
+ if returntype_content["value"] is None:
+ return returntype_content["name"]
+ else:
+ return returntype_content["value"].getName()
return None
-
+
+ # Update data types with user-defined data types added
+ def RefreshDataTypes(self):
+ ResetTypeHierarchy()
+ ResetEnumeratedDataValues()
+ if self.Project:
+ for datatype in self.Project.getDataTypes():
+ name = datatype.getName()
+ basetype_content = datatype.getBaseType().getContent()
+ if basetype_content["value"] is None:
+ AddDataTypeHierarchy(name, basetype_content["name"])
+ elif basetype_content["name"] == "derived":
+ AddDataTypeHierarchy(name, basetype_content["value"].getName())
+ elif basetype_content["name"] in ["subrangeSigned", "subrangeUnsigned"]:
+ base_type = basetype_content["value"].baseType.getContent()
+ if base_type["value"] is None:
+ AddDataTypeHierarchy(name, base_type["name"])
+ else:
+ AddDataTypeHierarchy(name, base_type["value"].getName())
+ else:
+ if basetype_content["name"] == "enum":
+ values = []
+ for value in basetype_content["value"].values.getValue():
+ values.append(value.getName())
+ AddEnumeratedDataValues(values)
+ AddDataTypeHierarchy(name, "ANY_DERIVED")
+
# Update Block types with user-defined pou added
def RefreshBlockTypes(self):
if BlockTypes[-1]["name"] == "User-defined POUs":
@@ -799,17 +916,34 @@
for type, varlist in pou.getVars():
if type == "InOut":
for var in varlist.getVariable():
- block_infos["inputs"].append((var.getName(),var.getType().getValue(),"none"))
- block_infos["outputs"].append((var.getName(),var.getType().getValue(),"none"))
+ var_type = var.type.getContent()
+ if var_type["value"] is None:
+ block_infos["inputs"].append((var.getName(),var_type["name"],"none"))
+ block_infos["outputs"].append((var.getName(),var_type["name"],"none"))
+ else:
+ block_infos["inputs"].append((var.getName(),var_type["value"].getName(),"none"))
+ block_infos["outputs"].append((var.getName(),var_type["value"].getName(),"none"))
elif type == "Input":
for var in varlist.getVariable():
- block_infos["inputs"].append((var.getName(),var.getType().getValue(),"none"))
+ var_type = var.type.getContent()
+ if var_type["value"] is None:
+ block_infos["inputs"].append((var.getName(),var_type["name"],"none"))
+ else:
+ block_infos["inputs"].append((var.getName(),var_type["value"].getName(),"none"))
elif type == "Output":
for var in varlist.getVariable():
- block_infos["outputs"].append((var.getName(),var.getType().getValue(),"none"))
+ var_type = var.type.getContent()
+ if var_type["value"] is None:
+ block_infos["outputs"].append((var.getName(),var_type["name"],"none"))
+ else:
+ block_infos["outputs"].append((var.getName(),var_type["value"].getName(),"none"))
return_type = pou.interface.getReturnType()
if return_type:
- block_infos["outputs"].append(("",return_type.getValue(),"none"))
+ var_type = return_type.getContent()
+ if var_type["value"] is None:
+ block_infos["outputs"].append(("",var_type["name"],"none"))
+ else:
+ block_infos["outputs"].append(("",var_type["value"].getName(),"none"))
if pou.getBodyType() in ["FBD","LD","SFC"]:
for instance in pou.getInstances():
if isinstance(instance, plcopen.comment):
@@ -818,16 +952,13 @@
# Return Block types checking for recursion
def GetBlockTypes(self, tagname = ""):
+ name = ""
+ type = None
if self.Project:
words = tagname.split("::")
- if len(words) == 1:
- name = current_name
- else:
+ if words[0] in ["P","T","A"]:
name = words[1]
- type = self.GetPouType(name)
- else:
- name = ""
- type = None
+ type = self.GetPouType(name)
if type == "function":
blocktypes = []
for category in BlockTypes[:-1] + PluginTypes:
@@ -853,10 +984,7 @@
if self.Project:
words = tagname.split("::")
if words[0] in ["P","T","A"]:
- if len(words) == 1:
- name = current_name
- else:
- name = words[1]
+ name = words[1]
type = self.GetPouType(name)
blocktypes = []
for category in BlockTypes[:-1]:
@@ -882,11 +1010,45 @@
blocktypes.append(pou.getName())
return blocktypes
+ # Return Data Types checking for recursion
+ def GetDataTypes(self, tagname = "", basetypes = True):
+ if basetypes:
+ datatypes = self.GetBaseTypes()
+ else:
+ datatypes = []
+ if self.Project:
+ words = tagname.split("::")
+ if words[0] in ["D"]:
+ name = words[1]
+ else:
+ name = ""
+ for datatype in self.Project.getDataTypes():
+ datatype_name = datatype.getName()
+ if datatype_name != name and not self.DataTypeIsUsedBy(name, datatype_name):
+ datatypes.append(datatype_name)
+ return datatypes
+
+ # Return Base Types
+ def GetBaseTypes(self):
+ return [value for value, parent in TypeHierarchy_list if not value.startswith("ANY")]
+
+ # Return Subrange types
+ def GetSubrangeTypes(self):
+ return [value for value, range in DataTypeRange_list]
+
+ # Return Enumerated Values
+ def GetEnumeratedDataValues(self):
+ return EnumeratedDataValues
+
#-------------------------------------------------------------------------------
# Project Element tag name computation functions
#-------------------------------------------------------------------------------
- # Compute a pou transition name
+ # Compute a data type name
+ def ComputeDataTypeName(self, datatype):
+ return "D::%s" % datatype
+
+ # Compute a pou name
def ComputePouName(self, pou):
return "P::%s" % pou
@@ -905,6 +1067,112 @@
# Compute a pou name
def ComputeConfigurationResourceName(self, config, resource):
return "R::%s::%s" % (config, resource)
+
+#-------------------------------------------------------------------------------
+# Project opened Data types management functions
+#-------------------------------------------------------------------------------
+
+ # Return the data type informations
+ def GetDataTypeInfos(self, tagname):
+ words = tagname.split("::")
+ if words[0] == "D":
+ infos = {}
+ datatype = self.Project.getDataType(words[1])
+ basetype_content = datatype.baseType.getContent()
+ if basetype_content["value"] is None:
+ infos["type"] = "Directly"
+ infos["base_type"] = basetype_content["name"]
+ elif basetype_content["name"] == "derived":
+ infos["type"] = "Directly"
+ infos["base_type"] = basetype_content["value"].getName()
+ elif basetype_content["name"] in ["subrangeSigned", "subrangeUnsigned"]:
+ infos["type"] = "Subrange"
+ infos["min"] = basetype_content["value"].range.getLower()
+ infos["max"] = basetype_content["value"].range.getUpper()
+ base_type = basetype_content["value"].baseType.getContent()
+ if base_type["value"] is None:
+ infos["base_type"] = base_type["name"]
+ else:
+ infos["base_type"] = base_type["value"].getName()
+ elif basetype_content["name"] == "enum":
+ infos["type"] = "Enumerated"
+ infos["values"] = []
+ for value in basetype_content["value"].values.getValue():
+ infos["values"].append(value.getName())
+ elif basetype_content["name"] == "array":
+ infos["type"] = "Array"
+ infos["dimensions"] = []
+ for dimension in basetype_content["value"].getDimension():
+ infos["dimensions"].append(str(dimension.getUpper()))
+ base_type = basetype_content["value"].baseType.getContent()
+ if base_type["value"] is None:
+ infos["base_type"] = base_type["name"]
+ else:
+ infos["base_type"] = base_type["value"].getName()
+ if datatype.initialValue is not None:
+ infos["initial"] = str(datatype.initialValue.getValue())
+ else:
+ infos["initial"] = ""
+ return infos
+ return None
+
+ # Change the data type informations
+ def SetDataTypeInfos(self, tagname, infos):
+ words = tagname.split("::")
+ if words[0] == "D":
+ datatype = self.Project.getDataType(words[1])
+ if infos["type"] == "Directly":
+ if infos["base_type"] in self.GetBaseTypes():
+ datatype.baseType.setContent(infos["base_type"], None)
+ else:
+ derived_datatype = plcopen.derived()
+ derived_datatype.setName(infos["base_type"])
+ datatype.baseType.setContent("derived", derived_datatype)
+ elif infos["type"] == "Subrange":
+ if infos["base_type"] in GetSubTypes("ANY_UINT"):
+ subrange = plcopen.subrangeUnsigned()
+ datatype.baseType.setContent("subrangeUnsigned", subrange)
+ else:
+ subrange = plcopen.subrangeSigned()
+ datatype.baseType.setContent("subrangeSigned", subrange)
+ subrange.range.setLower(infos["min"])
+ subrange.range.setUpper(infos["max"])
+ if infos["base_type"] in self.GetBaseTypes():
+ subrange.baseType.setContent(infos["base_type"], None)
+ else:
+ derived_datatype = plcopen.derived()
+ derived_datatype.setName(infos["base_type"])
+ subrange.baseType.setContent("derived", derived_datatype)
+ elif infos["type"] == "Enumerated":
+ enumerated = plcopen.enum()
+ for enum_value in infos["values"]:
+ value = plcopen.values_value()
+ value.setName(enum_value)
+ enumerated.values.appendValue(value)
+ datatype.baseType.setContent("enum", enumerated)
+ elif infos["type"] == "Array":
+ array = plcopen.array()
+ for dimension in infos["dimensions"]:
+ dimension_range = plcopen.rangeSigned()
+ dimension_range.setLower(1)
+ dimension_range.setUpper(int(dimension))
+ array.appendDimension(dimension_range)
+ if infos["base_type"] in self.GetBaseTypes():
+ array.baseType.setContent(infos["base_type"], None)
+ else:
+ derived_datatype = plcopen.derived()
+ derived_datatype.setName(infos["base_type"])
+ array.baseType.setContent("derived", derived_datatype)
+ datatype.baseType.setContent("array", array)
+ if infos["initial"] != "":
+ if datatype.initialValue is None:
+ datatype.initialValue = plcopen.value()
+ datatype.initialValue.setValue(infos["initial"])
+ else:
+ datatype.initialValue = None
+ self.RefreshDataTypeUsingTree()
+ self.RefreshDataTypes()
+ self.BufferProject()
#-------------------------------------------------------------------------------
# Project opened Pous management functions
@@ -972,7 +1240,7 @@
return "BOOL"
return None
- # Change the edited element taxt
+ # Change the edited element text
def SetEditedElementText(self, tagname, text):
element = self.GetEditedElement(tagname)
if element != None:
@@ -1331,7 +1599,11 @@
for type, varlist in pou.getVars():
for var in varlist.getVariable():
if var.getName() == varname:
- return var.getType().getValue()
+ vartype_content = var.getType().getContent()
+ if vartype_content["value"] is None:
+ return vartype_content["name"]
+ else:
+ return vartype_content["value"].getName()
return None
def SetConnectionWires(self, connection, connector):
@@ -1998,7 +2270,7 @@
if self.VerifyXML:
if sys:
sys.stdout = HolePseudoFile()
- result = pyxsval.parseAndValidate(filepath, os.path.join(sys.path[0], "plcopen/TC6_XML_V10_B.xsd"))
+ result = pyxsval.parseAndValidate(filepath, os.path.join(ScriptDirectory, "plcopen", "TC6_XML_V10_B.xsd"))
if sys:
sys.stdout = sys.__stdout__
tree = result.getTree()
@@ -2016,6 +2288,8 @@
self.Buffering = False
self.ElementsOpened = []
self.CurrentElementEditing = None
+ self.RefreshDataTypeUsingTree()
+ self.RefreshDataTypes()
self.RefreshPouUsingTree()
self.RefreshBlockTypes()
return None
@@ -2031,11 +2305,11 @@
"xmlns:xsi" : "http://www.w3.org/2001/XMLSchema-instance",
"xsi:schemaLocation" : "http://www.plcopen.org/xml/tc6.xsd http://www.plcopen.org/xml/tc6.xsd"}
text += self.Project.generateXMLText("project", 0, extras)
-
+
if self.VerifyXML:
if sys:
sys.stdout = HolePseudoFile()
- pyxsval.parseAndValidateString(text, open(os.path.join(sys.path[0], "plcopen/TC6_XML_V10_B.xsd"),"r").read())
+ pyxsval.parseAndValidateString(text, open(os.path.join(ScriptDirectory, "plcopen", "TC6_XML_V10_B.xsd"),"r").read())
if sys:
sys.stdout = sys.__stdout__
--- a/PLCGenerator.py Tue Nov 27 12:58:34 2007 +0100
+++ b/PLCGenerator.py Thu Dec 06 18:05:29 2007 +0100
@@ -34,6 +34,7 @@
currentProject = None
currentProgram = ""
+datatypeComputed = {}
pouComputed = {}
def ReIndentText(text, nb_spaces):
@@ -53,6 +54,49 @@
compute += "\n"
return compute
+def GenerateDataType(datatype_name):
+ if not datatypeComputed.get(datatype_name, True):
+ datatypeComputed[datatype_name] = True
+ global currentProject, currentProgram
+ datatype = currentProject.getDataType(datatype_name)
+ datatype_def = " %s :"%datatype.getName()
+ basetype_content = datatype.baseType.getContent()
+ if basetype_content["value"] is None:
+ datatype_def += " %s"%basetype_content["name"]
+ elif basetype_content["name"] == "derived":
+ basetype_name = basetype_content["value"].getName()
+ GenerateDataType(basetype_name)
+ datatype_def += " %s"%basetype_name
+ elif basetype_content["name"] in ["subrangeSigned", "subrangeUnsigned"]:
+ base_type = basetype_content["value"].baseType.getContent()
+ if base_type["value"] is None:
+ basetype_name = base_type["name"]
+ else:
+ basetype_name = base_type["value"].getName()
+ GenerateDataType(basetype_name)
+ min_value = basetype_content["value"].range.getLower()
+ max_value = basetype_content["value"].range.getUpper()
+ datatype_def += " %s (%d..%d)"%(basetype_name, min_value, max_value)
+ elif basetype_content["name"] == "enum":
+ values = []
+ for value in basetype_content["value"].values.getValue():
+ values.append(value.getName())
+ datatype_def += " (%s)"%", ".join(values)
+ elif basetype_content["name"] == "array":
+ base_type = basetype_content["value"].baseType.getContent()
+ if base_type["value"] is None:
+ basetype_name = base_type["name"]
+ else:
+ basetype_name = base_type["value"].getName()
+ GenerateDataType(basetype_name)
+ dimensions = []
+ for dimension in basetype_content["value"].getDimension():
+ dimensions.append("0..%d"%(dimension.getUpper() - 1))
+ datatype_def += " ARRAY [%s] OF %s"%(",".join(dimensions), basetype_name)
+ if datatype.initialValue is not None:
+ datatype_def += " := %s"%str(datatype.initialValue.getValue())
+ currentProgram += "%s;\n"%datatype_def
+
def GeneratePouProgram(pou_name):
if not pouComputed.get(pou_name, True):
pouComputed[pou_name] = True
@@ -64,6 +108,8 @@
else:
raise ValueError, "Undefined pou type"
pou_program.GenerateInterface(pou.getInterface())
+ pou_program.GenerateConnectionTypes(pou)
+ #print pou.getName(), pou_program.ConnectionTypes, pou_program.RelatedConnections
pou_program.GenerateProgram(pou)
currentProgram += pou_program.GenerateSTProgram()
@@ -77,7 +123,11 @@
config += " CONSTANT"
config += "\n"
for var in varlist.getVariable():
- var_type = var.getType().getValue()
+ vartype_content = var.getType().getContent()
+ if vartype_content["value"] is None:
+ var_type = vartype_content["name"]
+ else:
+ var_type = vartype_content["value"].getName()
config += " %s "%var.getName()
address = var.getAddress()
if address:
@@ -110,12 +160,16 @@
resrce += " CONSTANT"
resrce += "\n"
for var in varlist.getVariable():
- var_type = var.getType().getValue()
+ vartype_content = var.getType().getContent()
+ if vartype_content["value"] is None:
+ var_type = vartype_content["name"]
+ else:
+ var_type = vartype_content["value"].getName()
resrce += " %s "%var.getName()
address = var.getAddress()
if address:
resrce += "AT %s "%address
- resrce += ": %s"%var.getType().getValue()
+ resrce += ": %s"%var_type
initial = var.getInitialValue()
if initial:
value = str(initial.getValue())
@@ -171,6 +225,8 @@
self.InitialSteps = []
self.ComputedBlocks = {}
self.ComputedConnectors = {}
+ self.ConnectionTypes = {}
+ self.RelatedConnections = []
self.SFCNetworks = {"Steps":{}, "Transitions":{}, "Actions":{}}
self.SFCComputedBlocks = ""
self.ActionNumber = 0
@@ -187,22 +243,71 @@
return True
return False
+ def GetVariableType(self, name):
+ for list_type, retain, constant, located, vars in self.Interface:
+ for var_type, var_name, var_address, var_initial in vars:
+ if name == var_name:
+ return var_type
+ return None
+
+ def GetConnectedConnection(self, connection, body):
+ links = connection.getConnections()
+ if links and len(links) == 1:
+ return self.GetLinkedConnection(links[0], body)
+ return None
+
+ def GetLinkedConnection(self, link, body):
+ parameter = link.getFormalParameter()
+ instance = body.getContentInstance(link.getRefLocalId())
+ if isinstance(instance, (plcopen.inVariable, plcopen.inOutVariable, plcopen.continuation, plcopen.contact, plcopen.coil)):
+ return instance.connectionPointOut
+ elif isinstance(instance, plcopen.block):
+ outputvariables = instance.outputVariables.getVariable()
+ if len(outputvariables) == 1:
+ return outputvariables[0].connectionPointOut
+ elif parameter:
+ for variable in outputvariables:
+ if variable.getFormalParameter() == parameter:
+ return variable.connectionPointOut
+ else:
+ point = link.getPosition()[-1]
+ for variable in outputvariables:
+ relposition = variable.connectionPointOut.getRelPosition()
+ blockposition = instance.getPosition()
+ if point.x == blockposition.x + relposition[0] and point.y == blockposition.y + relposition[1]:
+ return variable.connectionPointOut
+ elif isinstance(instance, plcopen.leftPowerRail):
+ outputconnections = instance.getConnectionPointOut()
+ if len(outputconnections) == 1:
+ return outputconnections[0]
+ else:
+ point = link.getPosition()[-1]
+ for outputconnection in outputconnections:
+ relposition = outputconnection.getRelPosition()
+ powerrailposition = instance.getPosition()
+ if point.x == powerrailposition.x + relposition[0] and point.y == powerrailposition.y + relposition[1]:
+ return outputconnection
+ return None
+
+ def ExtractRelatedConnections(self, connection):
+ for i, related in enumerate(self.RelatedConnections):
+ if connection in related:
+ return self.RelatedConnections.pop(i)
+ return [connection]
+
def GenerateInterface(self, interface):
if self.Type == "FUNCTION":
- self.ReturnType = interface.getReturnType().getValue()
+ returntype_content = interface.getReturnType().getContent()
+ if returntype_content["value"] is None:
+ self.ReturnType = returntype_content["name"]
+ else:
+ self.ReturnType = returntype_content["value"].getName()
for varlist in interface.getContent():
variables = []
located = False
for var in varlist["value"].getVariable():
- type = var.getType().getValue()
- if not isinstance(type, (StringType, UnicodeType)):
- type = type.getName()
- GeneratePouProgram(type)
- blocktype = GetBlockType(type)
- if blocktype:
- variables.extend(blocktype["initialise"](type, var.getName()))
- located = False
- else:
+ vartype_content = var.getType().getContent()
+ if vartype_content["value"] is None:
initial = var.getInitialValue()
if initial:
initial_value = initial.getValue()
@@ -211,11 +316,120 @@
address = var.getAddress()
if address:
located = True
- variables.append((type, var.getName(), address, initial_value))
+ variables.append((vartype_content["name"], var.getName(), address, initial_value))
+ else:
+ var_type = vartype_content["value"].getName()
+ GeneratePouProgram(var_type)
+ blocktype = GetBlockType(var_type)
+ if blocktype is not None:
+ variables.extend(blocktype["initialise"](var_type, var.getName()))
+ located = False
+ else:
+ initial = var.getInitialValue()
+ if initial:
+ initial_value = initial.getValue()
+ else:
+ initial_value = None
+ address = var.getAddress()
+ if address:
+ located = True
+ variables.append((vartype_content["value"].getName(), var.getName(), address, initial_value))
if len(variables) > 0:
self.Interface.append((varTypeNames[varlist["name"]], varlist["value"].getRetain(),
varlist["value"].getConstant(), located, variables))
+ def GenerateConnectionTypes(self, pou):
+ body = pou.getBody()
+ body_content = body.getContent()
+ body_type = body_content["name"]
+ if body_type in ["FBD", "LD", "SFC"]:
+ for instance in body.getContentInstances():
+ if isinstance(instance, (plcopen.inVariable, plcopen.outVariable, plcopen.inOutVariable)):
+ expression = instance.getExpression()
+ var_type = self.GetVariableType(expression)
+ if expression == pou.getName():
+ returntype_content = pou.interface.getReturnType().getContent()
+ if returntype_content["value"] is None:
+ var_type = returntype_content["name"]
+ else:
+ var_type = returntype_content["value"].getName()
+ elif var_type is None:
+ var_type = expression.split("#")[0]
+ if isinstance(instance, (plcopen.inVariable, plcopen.inOutVariable)):
+ self.ConnectionTypes[instance.connectionPointOut] = var_type
+ if isinstance(instance, (plcopen.outVariable, plcopen.inOutVariable)):
+ self.ConnectionTypes[instance.connectionPointIn] = var_type
+ connected = self.GetConnectedConnection(instance.connectionPointIn, body)
+ if connected and connected not in self.ConnectionTypes:
+ for connection in self.ExtractRelatedConnections(connected):
+ self.ConnectionTypes[connection] = var_type
+ elif isinstance(instance, (plcopen.contact, plcopen.coil)):
+ self.ConnectionTypes[instance.connectionPointOut] = "BOOL"
+ self.ConnectionTypes[instance.connectionPointIn] = "BOOL"
+ connected = self.GetConnectedConnection(instance.connectionPointIn, body)
+ if connected and connected not in self.ConnectionTypes:
+ for connection in self.ExtractRelatedConnections(connected):
+ self.ConnectionTypes[connection] = "BOOL"
+ elif isinstance(instance, plcopen.leftPowerRail):
+ for connection in instance.getConnectionPointOut():
+ self.ConnectionTypes[connection] = "BOOL"
+ elif isinstance(instance, plcopen.rightPowerRail):
+ for connection in instance.getConnectionPointIn():
+ self.ConnectionTypes[connection] = "BOOL"
+ connected = self.GetConnectedConnection(connection, body)
+ if connected and connected not in self.ConnectionTypes:
+ for connection in self.ExtractRelatedConnections(connected):
+ self.ConnectionTypes[connection] = "BOOL"
+ elif isinstance(instance, plcopen.transition):
+ content = instance.condition.getContent()
+ if content["name"] == "connection" and len(content["value"]) == 1:
+ connected = self.GetLinkedConnection(content["value"][0], body)
+ if connected and connected not in self.ConnectionTypes:
+ for connection in self.ExtractRelatedConnections(connected):
+ self.ConnectionTypes[connection] = "BOOL"
+ elif isinstance(instance, plcopen.block):
+ block_infos = GetBlockType(instance.getTypeName())
+ undefined = {}
+ for variable in instance.outputVariables.getVariable():
+ output_name = variable.getFormalParameter()
+ for oname, otype, oqualifier in block_infos["outputs"]:
+ if output_name == oname and variable.connectionPointOut not in self.ConnectionTypes:
+ if otype.startswith("ANY"):
+ if otype not in undefined:
+ undefined[otype] = []
+ undefined[otype].append(variable.connectionPointOut)
+ else:
+ for connection in self.ExtractRelatedConnections(variable.connectionPointOut):
+ self.ConnectionTypes[connection] = otype
+ for variable in instance.inputVariables.getVariable():
+ input_name = variable.getFormalParameter()
+ for iname, itype, iqualifier in block_infos["inputs"]:
+ if input_name == iname:
+ connected = self.GetConnectedConnection(variable.connectionPointIn, body)
+ if itype.startswith("ANY"):
+ if itype not in undefined:
+ undefined[itype] = []
+ undefined[itype].append(variable.connectionPointIn)
+ if connected:
+ undefined[itype].append(connected)
+ else:
+ self.ConnectionTypes[variable.connectionPointIn] = itype
+ if connected and connected not in self.ConnectionTypes:
+ for connection in self.ExtractRelatedConnections(connected):
+ self.ConnectionTypes[connection] = itype
+ for var_type, connections in undefined.items():
+ related = []
+ for connection in connections:
+ if connection in self.ConnectionTypes:
+ var_type = self.ConnectionTypes[connection]
+ else:
+ related.extend(self.ExtractRelatedConnections(connection))
+ if var_type.startswith("ANY") and len(related) > 0:
+ self.RelatedConnections.append(related)
+ else:
+ for connection in related:
+ self.ConnectionTypes[connection] = var_type
+
def GenerateProgram(self, pou):
body = pou.getBody()
body_content = body.getContent()
@@ -223,7 +437,20 @@
if body_type in ["IL","ST"]:
self.Program = ReIndentText(body_content["value"].getText(), 2)
elif body_type == "FBD":
+ orderedInstances = []
+ otherInstances = []
for instance in body.getContentInstances():
+ if isinstance(instance, (plcopen.outVariable, plcopen.inOutVariable, plcopen.block)):
+ executionOrderId = instance.getExecutionOrderId()
+ if executionOrderId > 0:
+ orderedInstances.append((executionOrderId, instance))
+ else:
+ otherInstances.append(instance)
+ elif isinstance(instance, plcopen.connector):
+ otherInstances.append(instance)
+ orderedInstances.sort()
+ instances = [instance for (executionOrderId, instance) in orderedInstances] + otherInstances
+ for instance in instances:
if isinstance(instance, (plcopen.outVariable, plcopen.inOutVariable)):
var = instance.getExpression()
connections = instance.connectionPointIn.getConnections()
@@ -231,8 +458,9 @@
expression = self.ComputeFBDExpression(body, connections[0])
self.Program += " %s := %s;\n"%(var, expression)
elif isinstance(instance, plcopen.block):
- type = instance.getTypeName()
- block_infos = GetBlockType(type)
+ block_type = instance.getTypeName()
+ self.GeneratePouProgram(block_type)
+ block_infos = GetBlockType(block_type)
block_infos["generate"](self, instance, body, None)
elif isinstance(instance, plcopen.connector):
connector = instance.getName()
@@ -271,15 +499,16 @@
for initialstep in self.InitialSteps:
self.ComputeSFCStep(initialstep)
- def ComputeFBDExpression(self, body, link):
+ def ComputeFBDExpression(self, body, link, order = False):
localid = link.getRefLocalId()
instance = body.getContentInstance(localid)
if isinstance(instance, (plcopen.inVariable, plcopen.inOutVariable)):
return instance.getExpression()
elif isinstance(instance, plcopen.block):
block_type = instance.getTypeName()
+ self.GeneratePouProgram(block_type)
block_infos = GetBlockType(block_type)
- return block_infos["generate"](self, instance, body, link)
+ return block_infos["generate"](self, instance, body, link, order)
elif isinstance(instance, plcopen.continuation):
name = instance.getName()
computed_value = self.ComputedConnectors.get(name, None)
@@ -290,7 +519,7 @@
if tmp_instance.getName() == name:
connections = tmp_instance.connectionPointIn.getConnections()
if connections and len(connections) == 1:
- expression = self.ComputeFBDExpression(body, connections[0])
+ expression = self.ComputeFBDExpression(body, connections[0], order)
self.ComputedConnectors[name] = expression
return expression
raise ValueError, "No connector found"
@@ -304,6 +533,7 @@
paths.append(None)
elif isinstance(next, plcopen.block):
block_type = next.getTypeName()
+ self.GeneratePouProgram(block_type)
block_infos = GetBlockType(block_type)
paths.append(block_infos["generate"](self, next, body, connection))
else:
@@ -662,8 +892,15 @@
global currentProject, currentProgram
currentProject = project
currentProgram = ""
+ for datatype in project.getDataTypes():
+ datatypeComputed[datatype.getName()] = False
for pou in project.getPous():
pouComputed[pou.getName()] = False
+ if len(datatypeComputed) > 0:
+ currentProgram += "TYPE\n"
+ for datatype_name in datatypeComputed.keys():
+ GenerateDataType(datatype_name)
+ currentProgram += "END_TYPE\n\n"
for pou_name in pouComputed.keys():
GeneratePouProgram(pou_name)
for config in project.getConfigurations():
--- a/PLCOpenEditor.py Tue Nov 27 12:58:34 2007 +0100
+++ b/PLCOpenEditor.py Thu Dec 06 18:05:29 2007 +0100
@@ -34,6 +34,7 @@
from Viewer import *
from TextViewer import *
from RessourceEditor import *
+from DataTypeEditor import *
from PLCControler import *
from plcopen import OpenPDFDoc
from plcopen.structures import LOCATIONDATATYPES
@@ -42,7 +43,7 @@
__version__ = "$Revision$"
-CWD = os.path.split(__file__)[0]
+CWD = os.path.split(os.path.realpath(__file__))[0]
[ID_PLCOPENEDITOR, ID_PLCOPENEDITORPROJECTTREE,
ID_PLCOPENEDITORMAINSPLITTER, ID_PLCOPENEDITORSECONDSPLITTER,
@@ -71,11 +72,12 @@
] = [wx.NewId() for _init_coll_HelpMenu_Items in range(2)]
[ID_PLCOPENEDITOREDITMENUITEMS0, ID_PLCOPENEDITOREDITMENUITEMS1,
- ID_PLCOPENEDITOREDITMENUITEMS11, ID_PLCOPENEDITOREDITMENUITEMS12,
ID_PLCOPENEDITOREDITMENUITEMS2, ID_PLCOPENEDITOREDITMENUITEMS4,
ID_PLCOPENEDITOREDITMENUITEMS5, ID_PLCOPENEDITOREDITMENUITEMS6,
ID_PLCOPENEDITOREDITMENUITEMS8, ID_PLCOPENEDITOREDITMENUITEMS9,
-] = [wx.NewId() for _init_coll_EditMenu_Items in range(10)]
+ ID_PLCOPENEDITOREDITMENUITEMS11, ID_PLCOPENEDITOREDITMENUITEMS12,
+ ID_PLCOPENEDITOREDITMENUITEMS14, ID_PLCOPENEDITOREDITMENUITEMS15,
+] = [wx.NewId() for _init_coll_EditMenu_Items in range(12)]
[ID_PLCOPENEDITORSFCMENUITEMS0, ID_PLCOPENEDITORSFCMENUITEMS1,
ID_PLCOPENEDITORSFCMENUITEMS2, ID_PLCOPENEDITORSFCMENUITEMS3,
@@ -171,13 +173,18 @@
kind=wx.ITEM_NORMAL, text=u'Paste\tCTRL+V')
parent.AppendSeparator()
AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUITEMS8,
+ kind=wx.ITEM_NORMAL, text=u'Add Data Type')
+ AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUITEMS9,
+ kind=wx.ITEM_NORMAL, text=u'Remove Data Type')
+ parent.AppendSeparator()
+ AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUITEMS11,
kind=wx.ITEM_NORMAL, text=u'Add POU')
- AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUITEMS9,
+ AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUITEMS12,
kind=wx.ITEM_NORMAL, text=u'Remove POU')
parent.AppendSeparator()
- AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUITEMS11,
+ AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUITEMS14,
kind=wx.ITEM_NORMAL, text=u'Add Configuration')
- AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUITEMS12,
+ AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUITEMS15,
kind=wx.ITEM_NORMAL, text=u'Remove Configuration')
self.Bind(wx.EVT_MENU, self.OnRefreshMenu,
id=ID_PLCOPENEDITOREDITMENUITEMS0)
@@ -191,14 +198,18 @@
id=ID_PLCOPENEDITOREDITMENUITEMS5)
self.Bind(wx.EVT_MENU, self.OnPasteMenu,
id=ID_PLCOPENEDITOREDITMENUITEMS6)
+ self.Bind(wx.EVT_MENU, self.OnAddDataTypeMenu,
+ id=ID_PLCOPENEDITOREDITMENUITEMS8)
+ self.Bind(wx.EVT_MENU, self.OnRemoveDataTypeMenu,
+ id=ID_PLCOPENEDITOREDITMENUITEMS9)
self.Bind(wx.EVT_MENU, self.OnAddPouMenu,
- id=ID_PLCOPENEDITOREDITMENUITEMS8)
+ id=ID_PLCOPENEDITOREDITMENUITEMS11)
self.Bind(wx.EVT_MENU, self.OnRemovePouMenu,
- id=ID_PLCOPENEDITOREDITMENUITEMS9)
+ id=ID_PLCOPENEDITOREDITMENUITEMS12)
self.Bind(wx.EVT_MENU, self.OnAddConfigurationMenu,
- id=ID_PLCOPENEDITOREDITMENUITEMS11)
+ id=ID_PLCOPENEDITOREDITMENUITEMS14)
self.Bind(wx.EVT_MENU, self.OnRemoveConfigurationMenu,
- id=ID_PLCOPENEDITOREDITMENUITEMS12)
+ id=ID_PLCOPENEDITOREDITMENUITEMS15)
def _init_coll_menuBar1_Menus(self, parent):
if self.ModeSolo:
@@ -416,7 +427,7 @@
self.VariablePanelIndexer = VariablePanelIndexer(self, self.Controler)
self.AUIManager.AddPane(self.VariablePanelIndexer, wx.aui.AuiPaneInfo().Caption("Variable Panel").Bottom().Layer(0).BestSize(wx.Size(800, 200)).CloseButton(False))
- self.AUIManager.Update();
+ self.AUIManager.Update()
def __init__(self, parent, controler = None, fileOpen = None):
self.ModeSolo = controler == None
@@ -594,10 +605,18 @@
self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUITEMS0, False)
self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUITEMS8, True)
self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUITEMS9, True)
+ self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUITEMS11, True)
+ self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUITEMS12, True)
+ self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUITEMS14, True)
+ self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUITEMS15, True)
else:
self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUITEMS0, False)
self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUITEMS8, False)
self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUITEMS9, False)
+ self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUITEMS11, False)
+ self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUITEMS12, False)
+ self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUITEMS14, False)
+ self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUITEMS15, False)
self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUITEMS4, True)
self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUITEMS5, True)
if self.CopyBuffer is not None:
@@ -798,7 +817,7 @@
tool.SetToggle(False)
def OnSelectionTool(self, event):
- self.GetPageSelection()
+ selected = self.GetPageSelection()
if selected != -1:
self.GetPage(selected).SetMode(MODE_SELECTION)
event.Skip()
@@ -1018,6 +1037,14 @@
itemtype = self.ProjectTree.GetPyData(item)
if itemtype == ITEM_PROJECT:
self.Controler.SetProjectProperties(name = new_name)
+ elif itemtype == ITEM_DATATYPE:
+ if new_name.upper() in [name.upper() for name in self.Controler.GetProjectDataTypeNames() if name != old_name]:
+ message = "\"%s\" data type already exists!"%new_name
+ abort = True
+ if not abort:
+ self.Controler.ChangeDataTypeName(old_name, new_name)
+ self.RefreshEditorNames(itemtype, old_name, new_name)
+ self.RefreshPageTitles()
elif itemtype == ITEM_POU:
if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames() if name != old_name]:
message = "\"%s\" pou already exists!"%new_name
@@ -1135,7 +1162,9 @@
data = self.ProjectTree.GetPyData(selected)
if name == "Properties":
self.ShowProperties()
- if data == ITEM_POU:
+ if data == ITEM_DATATYPE:
+ self.EditProjectElement(data, self.Controler.ComputeDataTypeName(name))
+ elif data == ITEM_POU:
self.EditProjectElement(data, self.Controler.ComputePouName(name))
elif data == ITEM_CONFIGURATION:
self.EditProjectElement(data, self.Controler.ComputeConfigurationName(name))
@@ -1162,11 +1191,12 @@
def OnProjectTreeLeftUp(self, event):
if self.SelectedItem is not None:
- print "LeftUp", self.ProjectTree.GetItemText(self.SelectedItem)
self.ProjectTree.SelectItem(self.SelectedItem)
name = self.ProjectTree.GetItemText(self.SelectedItem)
data = self.ProjectTree.GetPyData(self.SelectedItem)
- if data == ITEM_POU:
+ if data == ITEM_DATATYPE:
+ self.EditProjectElement(data, self.Controler.ComputeDataTypeName(name), True)
+ elif data == ITEM_POU:
self.EditProjectElement(data, self.Controler.ComputePouName(name), True)
elif data == ITEM_CONFIGURATION:
self.EditProjectElement(data, self.Controler.ComputeConfigurationName(name), True)
@@ -1191,15 +1221,9 @@
tagname = self.Controler.ComputePouActionName(pou_name, name)
self.EditProjectElement(data, tagname, True)
wx.CallAfter(self.ResetSelectedItem)
- else:
- print "LeftUp", None
event.Skip()
def OnProjectTreeItemChanging(self, event):
- if self.SelectedItem is not None:
- print "Changing", self.ProjectTree.GetItemText(event.GetItem()), self.ProjectTree.GetItemText(self.SelectedItem)
- else:
- print "Changing", None, self.ProjectTree.GetItemText(event.GetItem())
if self.ProjectTree.GetPyData(event.GetItem()) != ITEM_UNEDITABLE and self.SelectedItem is None:
self.SelectedItem = event.GetItem()
event.Veto()
@@ -1230,10 +1254,8 @@
if wx.VERSION >= (2, 8, 0):
if elementtype == ITEM_CONFIGURATION:
new_window = MDIConfigurationEditor(self, tagname, self, self.Controler)
- self.VariablePanelIndexer.AddVariablePanel(tagname, "config")
elif elementtype == ITEM_RESOURCE:
new_window = MDIResourceEditor(self, tagname, self, self.Controler)
- self.VariablePanelIndexer.AddVariablePanel(tagname, "resource")
elif elementtype in [ITEM_POU, ITEM_TRANSITION, ITEM_ACTION]:
bodytype = self.Controler.GetEditedElementBodyType(tagname)
if bodytype == "FBD":
@@ -1250,17 +1272,18 @@
viewer.SetKeywords(IL_KEYWORDS)
else:
viewer.SetKeywords(ST_KEYWORDS)
+ elif elementtype == ITEM_DATATYPE:
+ new_window = MDIDataTypeEditor(self, tagname, self, self.Controler)
new_window.Bind(wx.EVT_ACTIVATE, self.OnPouSelectedChanged)
new_window.Bind(wx.EVT_CLOSE, self.OnPageClose)
+ new_window.Layout()
else:
if elementtype == ITEM_CONFIGURATION:
new_window = ConfigurationEditor(self.TabsOpened, tagname, self, self.Controler)
self.TabsOpened.AddPage(new_window, "")
- self.VariablePanelIndexer.AddVariablePanel(tagname, "config")
elif elementtype == ITEM_RESOURCE:
new_window = ResourceEditor(self.TabsOpened, tagname, self, self.Controler)
self.TabsOpened.AddPage(new_window, "")
- self.VariablePanelIndexer.AddVariablePanel(tagname, "resource")
elif elementtype in [ITEM_POU, ITEM_TRANSITION, ITEM_ACTION]:
bodytype = self.Controler.GetEditedElementBodyType(tagname)
if bodytype == "FBD":
@@ -1277,13 +1300,16 @@
else:
new_window.SetKeywords(ST_KEYWORDS)
self.TabsOpened.AddPage(new_window, "")
- if elementtype == ITEM_POU:
+ elif elementtype == ITEM_DATATYPE:
+ new_window = DataTypeEditor(self.TabsOpened, tagname, self, self.Controler)
+ self.TabsOpened.AddPage(new_window, "")
+ if elementtype == ITEM_CONFIGURATION:
+ self.VariablePanelIndexer.AddVariablePanel(tagname, "config")
+ elif elementtype == ITEM_RESOURCE:
+ self.VariablePanelIndexer.AddVariablePanel(tagname, "resource")
+ elif elementtype in [ITEM_POU, ITEM_TRANSITION, ITEM_ACTION]:
words = tagname.split("::")
self.VariablePanelIndexer.AddVariablePanel(tagname, self.Controler.GetPouType(words[1]))
- elif elementtype == ITEM_TRANSITION:
- self.VariablePanelIndexer.AddVariablePanel(tagname, "transition")
- elif elementtype == ITEM_TRANSITION:
- self.VariablePanelIndexer.AddVariablePanel(tagname, "action")
self.VariablePanelIndexer.ChangeVariablePanel(tagname)
openedidx = self.IsOpened(tagname)
old_selected = self.GetPageSelection()
@@ -1457,6 +1483,38 @@
pass
event.Skip()
+ def OnAddDataTypeMenu(self, event):
+ dialog = DataTypeDialog(self, "Add a new data type", "Please enter data type name", "", wx.OK|wx.CANCEL)
+ dialog.SetDataTypeNames(self.Controler.GetProjectDataTypeNames())
+ if dialog.ShowModal() == wx.ID_OK:
+ self.Controler.ProjectAddDataType(dialog.GetValue())
+ self.RefreshTitle()
+ self.RefreshEditMenu()
+ self.RefreshProjectTree()
+ dialog.Destroy()
+ event.Skip()
+
+ def OnRemoveDataTypeMenu(self, event):
+ datatypes = self.Controler.GetProjectDataTypeNames()
+ dialog = wx.SingleChoiceDialog(self, "Select Data Type to remove:", "Data Type Remove", datatypes, wx.OK|wx.CANCEL)
+ if dialog.ShowModal() == wx.ID_OK:
+ selected = dialog.GetStringSelection()
+ if not self.Controler.DataTypeIsUsed(selected):
+ self.Controler.ProjectRemoveDataType(selected)
+ tagname = self.Controler.ComputeDataTypeName(selected)
+ idx = self.IsOpened(tagname)
+ if idx is not None:
+ self.DeletePage(idx)
+ self.RefreshTitle()
+ self.RefreshEditMenu()
+ self.RefreshProjectTree()
+ self.RefreshToolBar()
+ else:
+ message = wx.MessageDialog(self, "%s is used by one or more POUs. It can't be removed!"%selected, "Error", wx.OK|wx.ICON_ERROR)
+ message.ShowModal()
+ message.Destroy()
+ event.Skip()
+
def OnAddPouMenu(self, event):
dialog = PouDialog(self)
dialog.SetPouNames(self.Controler.GetProjectPouNames())
@@ -1840,6 +1898,59 @@
return values
#-------------------------------------------------------------------------------
+# Edit Step Name Dialog
+#-------------------------------------------------------------------------------
+
+class DataTypeDialog(wx.TextEntryDialog):
+
+ if wx.VERSION < (2, 6, 0):
+ def Bind(self, event, function, id = None):
+ if id is not None:
+ event(self, id, function)
+ else:
+ event(self, function)
+
+
+ def __init__(self, parent, message, caption = "Please enter text", defaultValue = "",
+ style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition):
+ wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos)
+
+ self.DataTypeNames = []
+ if wx.VERSION >= (2, 8, 0):
+ self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(2).GetSizer().GetItem(1).GetSizer().GetAffirmativeButton().GetId())
+ elif wx.VERSION >= (2, 6, 0):
+ self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetAffirmativeButton().GetId())
+ else:
+ self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetChildren()[0].GetSizer().GetChildren()[0].GetWindow().GetId())
+
+ def OnOK(self, event):
+ datatype_name = self.GetSizer().GetItem(1).GetWindow().GetValue()
+ if datatype_name == "":
+ message = wx.MessageDialog(self, "You must type a name!", "Error", wx.OK|wx.ICON_ERROR)
+ message.ShowModal()
+ message.Destroy()
+ elif not TestIdentifier(datatype_name):
+ message = wx.MessageDialog(self, "\"%s\" is not a valid identifier!"%datatype_name, "Error", wx.OK|wx.ICON_ERROR)
+ message.ShowModal()
+ message.Destroy()
+ elif datatype_name.upper() in IEC_KEYWORDS:
+ message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%datatype_name, "Error", wx.OK|wx.ICON_ERROR)
+ message.ShowModal()
+ message.Destroy()
+ elif datatype_name.upper() in self.DataTypeNames:
+ message = wx.MessageDialog(self, "\"%s\" data type already exists!"%datatype_name, "Error", wx.OK|wx.ICON_ERROR)
+ message.ShowModal()
+ message.Destroy()
+ else:
+ self.EndModal(wx.ID_OK)
+
+ def SetDataTypeNames(self, datatype_names):
+ self.DataTypeNames = [datatype_name.upper() for datatype_name in datatype_names]
+
+ def GetValue(self):
+ return self.GetSizer().GetItem(1).GetWindow().GetValue()
+
+#-------------------------------------------------------------------------------
# Create Pou Dialog
#-------------------------------------------------------------------------------
@@ -2462,12 +2573,18 @@
self.CurrentPanel = new_tagname
def ChangeVariablePanel(self, tagname):
- if tagname in self.VariablePanelList and tagname != self.CurrentPanel:
+ if tagname in self.VariablePanelList:
+ if tagname != self.CurrentPanel:
+ if self.CurrentPanel is not None:
+ self.VariablePanelList[self.CurrentPanel].Hide()
+ self.CurrentPanel = tagname
+ self.VariablePanelList[self.CurrentPanel].RefreshView()
+ self.VariablePanelList[self.CurrentPanel].Show()
+ self.MainSizer.Layout()
+ else:
if self.CurrentPanel is not None:
self.VariablePanelList[self.CurrentPanel].Hide()
- self.CurrentPanel = tagname
- self.VariablePanelList[self.CurrentPanel].RefreshView()
- self.VariablePanelList[self.CurrentPanel].Show()
+ self.CurrentPanel = None
self.MainSizer.Layout()
def RefreshVariablePanel(self, tagname):
@@ -2874,12 +2991,10 @@
self.RefreshTypeList()
self.OptionList = "Yes,No"
- self.TypeList = [value for value, parent in TypeHierarchy_list if not value.startswith("ANY")]
if element_type == "function":
- for value, parent in TypeHierarchy_list:
- if not value.startswith("ANY"):
- self.ReturnType.Append(value)
+ for base_type in self.Controler.GetBaseTypes():
+ self.ReturnType.Append(base_type)
self.ReturnType.Enable(True)
else:
self.ReturnType.Enable(False)
@@ -3033,11 +3148,17 @@
if self.Table.GetColLabelValue(col) == "Type":
type_menu = wx.Menu(title='')
base_menu = wx.Menu(title='')
- for base_type in self.TypeList:
+ for base_type in self.Controler.GetBaseTypes():
new_id = wx.NewId()
AppendMenu(base_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=base_type)
self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(base_type), id=new_id)
type_menu.AppendMenu(wx.NewId(), "Base Types", base_menu)
+ datatype_menu = wx.Menu(title='')
+ for datatype in self.Controler.GetDataTypes(basetypes = False):
+ new_id = wx.NewId()
+ AppendMenu(datatype_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype)
+ self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(datatype), id=new_id)
+ type_menu.AppendMenu(wx.NewId(), "User Data Types", datatype_menu)
functionblock_menu = wx.Menu(title='')
for functionblock_type in self.Controler.GetFunctionBlockTypes():
new_id = wx.NewId()
@@ -3072,7 +3193,7 @@
data = wx.TextDataObject(str((var_name, var_class, var_type, self.TagName)))
dragSource = wx.DropSource(self.VariablesGrid)
dragSource.SetData(data)
- dragSource.DoDragDrop()
+ print dragSource.DoDragDrop()
event.Skip()
def OnVariablesGridSelectCell(self, event):
--- a/TextViewer.py Tue Nov 27 12:58:34 2007 +0100
+++ b/TextViewer.py Thu Dec 06 18:05:29 2007 +0100
@@ -160,6 +160,7 @@
self.Variables = []
self.Functions = []
self.Jumps = []
+ self.EnumeratedValues = []
self.TextChanged = False
self.DisableEvents = True
self.TextSyntax = "ST"
@@ -287,6 +288,10 @@
if blocktype["type"] == "function" and blocktype["name"] not in self.Keywords and blocktype["name"] not in self.Variables:
self.Functions.append(blocktype["name"].upper())
+ self.EnumeratedValues = []
+ for value in self.Controler.GetEnumeratedDataValues():
+ self.EnumeratedValues.append(value.upper())
+
self.Colourise(0, -1)
def OnStyleNeeded(self, event):
@@ -320,6 +325,8 @@
self.SetStyling(i - start_pos, STC_PLC_FUNCTION)
elif word in self.Jumps:
self.SetStyling(i - start_pos, STC_PLC_JUMP)
+ elif word in self.EnumeratedValues:
+ self.SetStyling(i - start_pos, STC_PLC_NUMBER)
else:
self.SetStyling(i - start_pos, 31)
if self.GetCurrentPos() < start_pos or self.GetCurrentPos() > i:
@@ -368,6 +375,8 @@
self.SetStyling(i - start_pos, STC_PLC_FUNCTION)
elif word in self.Jumps:
self.SetStyling(i - start_pos, STC_PLC_JUMP)
+ elif word in self.EnumeratedValues:
+ self.SetStyling(i - start_pos, STC_PLC_NUMBER)
else:
self.SetStyling(i - start_pos, 31)
if self.GetCurrentPos() < start_pos or self.GetCurrentPos() > i:
@@ -395,6 +404,8 @@
self.SetStyling(i - start_pos, STC_PLC_FUNCTION)
elif word in self.Jumps:
self.SetStyling(i - start_pos, STC_PLC_JUMP)
+ elif word in self.EnumeratedValues:
+ self.SetStyling(i - start_pos, STC_PLC_NUMBER)
else:
self.SetStyling(i - start_pos, 31)
else:
--- a/Viewer.py Tue Nov 27 12:58:34 2007 +0100
+++ b/Viewer.py Thu Dec 06 18:05:29 2007 +0100
@@ -113,7 +113,7 @@
width, height = variable.GetMinSize()
variable.SetSize(width, height)
self.ParentWindow.AddBlock(variable)
- self.ParentWindow.Controler.AddEditedElementVariable(self.TagName, id, var_type)
+ self.ParentWindow.Controler.AddEditedElementVariable(self.ParentWindow.TagName, id, var_type)
self.ParentWindow.RefreshVariableModel(variable)
self.ParentWindow.RefreshBuffer()
self.ParentWindow.RefreshScrollBars()
--- a/plcopen/plcopen.py Tue Nov 27 12:58:34 2007 +0100
+++ b/plcopen/plcopen.py Thu Dec 06 18:05:29 2007 +0100
@@ -46,39 +46,6 @@
PLCOpenClasses, PLCOpenTypes = GenerateClassesFromXSD(os.path.join(os.path.split(__file__)[0], "TC6_XML_V10_B.xsd"))
-cls = PLCOpenClasses.get("dataType", None)
-if cls:
- cls.value = None
-
- def getValue(self):
- return self.value
- setattr(cls, "getValue", getValue)
-
- def setValue(self, value):
- self.value = value
- setattr(cls, "setValue", setValue)
-
- def loadXMLTree(self, tree):
- node = tree.childNodes[1]
- if node.nodeName == "derived":
- self.value = PLCOpenClasses["derived"]()
- self.value.loadXMLTree(node)
- else:
- self.value = node.nodeName
- setattr(cls, "loadXMLTree", loadXMLTree)
-
- def generateXMLText(self, name, indent, extras = {}):
- ind1, ind2 = getIndent(indent, name)
- text = ind1 + "<%s>\n"%name
- if isinstance(self.value, (StringType, UnicodeType)):
- ind3, ind4 = getIndent(indent + 1, self.value)
- text += ind3 + "<%s/>\n"%self.value
- else:
- text += self.value.generateXMLText("derived", indent + 1)
- text += ind1 + "</%s>\n"%name
- return text
- setattr(cls, "generateXMLText", generateXMLText)
-
cls = PLCOpenClasses.get("formattedText", None)
if cls:
cls.text = ""
@@ -159,6 +126,26 @@
def getName(self):
return self.contentHeader.getName()
setattr(cls, "getName", getName)
+
+ def getDataTypes(self):
+ return self.types.getDataTypeElements()
+ setattr(cls, "getDataTypes", getDataTypes)
+
+ def getDataType(self, name):
+ return self.types.getDataTypeElement(name)
+ setattr(cls, "getDataType", getDataType)
+
+ def appendDataType(self, name):
+ self.types.appendDataTypeElement(name)
+ setattr(cls, "appendDataType", appendDataType)
+
+ def insertDataType(self, index, datatype):
+ self.types.insertDataTypeElement(index, datatype)
+ setattr(cls, "insertDataType", insertDataType)
+
+ def removeDataType(self, name):
+ self.types.removeDataTypeElement(name)
+ setattr(cls, "removeDataType", removeDataType)
def getPous(self):
return self.types.getPouElements()
@@ -293,6 +280,43 @@
cls = PLCOpenClasses.get("project_types", None)
if cls:
+ def getDataTypeElements(self):
+ return self.dataTypes.getDataType()
+ setattr(cls, "getDataTypeElements", getDataTypeElements)
+
+ def getDataTypeElement(self, name):
+ elements = self.dataTypes.getDataType()
+ for element in elements:
+ if element.getName() == name:
+ return element
+ return None
+ setattr(cls, "getDataTypeElement", getDataTypeElement)
+
+ def appendDataTypeElement(self, name):
+ for element in self.dataTypes.getDataType():
+ if element.getName() == name:
+ raise ValueError, "\"%s\" Data Type already exists !!!"%name
+ new_datatype = PLCOpenClasses["dataTypes_dataType"]()
+ new_datatype.setName(name)
+ new_datatype.baseType.setContent("BOOL", None)
+ self.dataTypes.appendDataType(new_datatype)
+ setattr(cls, "appendDataTypeElement", appendDataTypeElement)
+
+ def insertDataTypeElement(self, index, datatype):
+ self.dataTypes.insertDataType(index, datatype)
+ setattr(cls, "insertDataTypeElement", insertDataTypeElement)
+
+ def removeDataTypeElement(self, name):
+ found = False
+ for idx, element in enumerate(self.dataTypes.getDataType()):
+ if element.getName() == name:
+ self.dataTypes.removeDataType(idx)
+ found = True
+ break
+ if not found:
+ raise ValueError, "\"%s\" Data Type doesn't exist !!!"%name
+ setattr(cls, "removeDataTypeElement", removeDataTypeElement)
+
def getPouElements(self):
return self.pous.getPou()
setattr(cls, "getPouElements", getPouElements)
@@ -440,10 +464,10 @@
variables = varlist["value"].getVariable()
for var in variables:
if var.getName() == old_name:
- var_type = var.getType().getValue()
- if isinstance(var_type, PLCOpenClasses["derived"]) and var_type.getName() == old_type:
+ vartype_content = var.getType().getContent()
+ if vartype_content["value"] is not None and vartype_content["value"].getName() == old_type:
var.setName(new_name)
- var.getType().getValue().setName(new_type)
+ vartype_content["value"].setName(new_type)
return
setattr(cls, "changePouVar", changePouVar)
@@ -1415,61 +1439,71 @@
cls = PLCOpenClasses.get("value", None)
if cls:
def setValue(self, value):
- try:
- value = eval(value)
- except:
- pass
- if type(value) == ListType:
+ if value.startswith("[") and value.endswith("]"):
arrayValue = PLCOpenClasses["value_arrayValue"]()
- arrayValue.setValue(value)
self.content = {"name":"arrayValue","value":arrayValue}
- elif type(value) == DictType:
+ elif value.startswith("(") and value.endswith(")"):
structValue = PLCOpenClasses["value_structValue"]()
- structValue.setValue(value)
self.content = {"name":"structValue","value":structValue}
else:
simpleValue = PLCOpenClasses["value_simpleValue"]()
- simpleValue.setValue(str(value))
self.content = {"name":"simpleValue","value":simpleValue}
+ self.content["value"].setValue(value)
setattr(cls, "setValue", setValue)
def getValue(self):
- value = self.content["value"].getValue()
- try:
- value = eval(value)
- except:
- pass
- return value
+ return self.content["value"].getValue()
setattr(cls, "getValue", getValue)
cls = PLCOpenClasses.get("value_arrayValue", None)
if cls:
- def setValue(self, array):
+ arrayValue_model = re.compile("([0-9]*)\((.*)\)")
+
+ def setValue(self, value):
self.value = []
- for value in array:
+ for item in value[1:-1].split(","):
+ item = item.strip()
element = PLCOpenClasses["arrayValue_value"]()
- element.setValue(value)
+ result = arrayValue_model.match(item)
+ if result is not None:
+ groups = result.groups()
+ element.setRepetitionValue(int(groups[0]))
+ element.setValue(groups[1].strip())
+ else:
+ element.setValue(item)
self.value.append(element)
setattr(cls, "setValue", setValue)
def getValue(self):
- return [element.getValue() for element in self.value]
+ values = []
+ for element in self.value:
+ repetition = element.getRepetitionValue()
+ if repetition is not None and repetition > 1:
+ values.append("%d(%s)"%(repetition, element.getValue()))
+ else:
+ values.append(element.getValue())
+ return "[%s]"%", ".join(values)
setattr(cls, "getValue", getValue)
cls = PLCOpenClasses.get("value_structValue", None)
if cls:
- def setValue(self, dict):
+ structValue_model = re.compile("(.*):=(.*)")
+
+ def setValue(self, value):
self.value = []
- for name,value in dict.items():
- element = PLCOpenClasses["structValue_value"]()
- element.setMember(name)
- element.setValue(value)
+ for item in value[1:-1].split(","):
+ result = arrayValue_model.match(item)
+ if result is not None:
+ groups = result.groups()
+ element = PLCOpenClasses["structValue_value"]()
+ element.setMember(groups[0].strip())
+ element.setValue(groups[1].strip())
self.value.append(element)
setattr(cls, "setValue", setValue)
def getValue(self):
- value = {}
+ values = []
for element in self.value:
- value[element.getMember()] = element.getValue()
- return value
+ values.append("%s := %s"%(element.getMember(), element.getValue()))
+ return "(%s)"%", ".join(values)
setattr(cls, "getValue", getValue)
--- a/plcopen/structures.py Tue Nov 27 12:58:34 2007 +0100
+++ b/plcopen/structures.py Thu Dec 06 18:05:29 2007 +0100
@@ -33,38 +33,48 @@
"D" : ["DINT", "UDINT", "REAL", "DWORD"],
"L" : ["LINT", "ULINT", "LREAL", "LWORD"]}
-def generate_block(generator, block, body, link):
+def generate_block(generator, block, body, link, order=False):
body_type = body.getContent()["name"]
name = block.getInstanceName()
type = block.getTypeName()
+ executionOrderId = block.getExecutionOrderId()
block_infos = GetBlockType(type)
- if block_infos["type"] == "function" and link:
- generator.GeneratePouProgram(type)
- vars = []
- for variable in block.inputVariables.getVariable():
- connections = variable.connectionPointIn.getConnections()
- if connections and len(connections) == 1:
- if body_type == "FBD" or body_type == "SFC":
- value = generator.ComputeFBDExpression(body, connections[0])
- elif body_type == "LD":
- paths = generator.GenerateLDPaths(variable.connectionPointIn.getConnections(), body)
- if len(paths) > 0:
- paths = tuple(paths)
- else:
- paths = paths[0]
- value = generator.ComputeLDExpression(paths, True)
- vars.append(generator.ExtractModifier(variable, value))
- variable = block.outputVariables.getVariable()[0]
- return generator.ExtractModifier(variable, "%s(%s)"%(type, ", ".join(vars)))
+ if block_infos["type"] == "function":
+ output_variable = block.outputVariables.getVariable()[0]
+ output_name = "%s%d_OUT"%(type, block.getLocalId())
+ if not generator.ComputedBlocks.get(block, False) and not order:
+ if generator.Interface[-1][0] != "VAR" or generator.Interface[-1][1] or generator.Interface[-1][2] or generator.Interface[-1][3]:
+ generator.Interface.append(("VAR", False, False, False, []))
+ if output_variable.connectionPointOut in generator.ConnectionTypes:
+ generator.Interface[-1][4].append((generator.ConnectionTypes[output_variable.connectionPointOut], output_name, None, None))
+ else:
+ generator.Interface[-1][4].append(("ANY", output_name, None, None))
+ vars = []
+ for variable in block.inputVariables.getVariable():
+ connections = variable.connectionPointIn.getConnections()
+ if connections and len(connections) == 1:
+ if body_type == "FBD" or body_type == "SFC":
+ value = generator.ComputeFBDExpression(body, connections[0], executionOrderId > 0)
+ elif body_type == "LD":
+ paths = generator.GenerateLDPaths(variable.connectionPointIn.getConnections(), body)
+ if len(paths) > 0:
+ paths = tuple(paths)
+ else:
+ paths = paths[0]
+ value = generator.ComputeLDExpression(paths, True)
+ vars.append(generator.ExtractModifier(variable, value))
+ generator.Program += " %s := %s(%s);\n"%(output_name, type, ", ".join(vars))
+ generator.ComputedBlocks[block] = True
+ return generator.ExtractModifier(output_variable, output_name)
elif block_infos["type"] == "functionBlock":
- if not generator.ComputedBlocks.get(name, False):
+ if not generator.ComputedBlocks.get(block, False) and not order:
vars = []
for variable in block.inputVariables.getVariable():
connections = variable.connectionPointIn.getConnections()
if connections and len(connections) == 1:
parameter = variable.getFormalParameter()
if body_type == "FBD" or body_type == "SFC":
- value = generator.ComputeFBDExpression(body, connections[0])
+ value = generator.ComputeFBDExpression(body, connections[0], executionOrderId > 0)
vars.append("%s := %s"%(parameter, generator.ExtractModifier(variable, value)))
elif body_type == "LD":
paths = generator.GenerateLDPaths(variable.connectionPointIn.getConnections(), body)
@@ -75,7 +85,7 @@
value = generator.ComputeLDExpression(paths, True)
vars.append("%s := %s"%(parameter, generator.ExtractModifier(variable, value)))
generator.Program += " %s(%s);\n"%(name, ", ".join(vars))
- generator.ComputedBlocks[name] = True
+ generator.ComputedBlocks[block] = True
if link:
connectionPoint = link.getPosition()[-1]
else:
@@ -281,6 +291,31 @@
TypeHierarchy = dict(TypeHierarchy_list)
+def ResetTypeHierarchy():
+ TypeHierarchy = dict(TypeHierarchy_list)
+
+def AddDataTypeHierarchy(name, reference):
+ TypeHierarchy[name] = reference
+
+DataTypeRange_list = [
+ ("SINT", (-2**7, 2**7 - 1)),
+ ("INT", (-2**15, 2**15 - 1)),
+ ("DINT", (-2**31, 2**31 - 1)),
+ ("LINT", (-2**31, 2**31 - 1)),
+ ("USINT", (0, 2**8 - 1)),
+ ("UINT", (0, 2**16 - 1)),
+ ("UDINT", (0, 2**31 - 1)),
+ ("ULINT", (0, 2**31 - 1))
+]
+
+DataTypeRange = dict(DataTypeRange_list)
+
+def ResetDataTypeRange():
+ DataTypeRange = dict(DataTypeRange_list)
+
+def AddDataTypeRange(name, range):
+ DataTypeRange[name] = range
+
"""
returns true if the given data type is the same that "reference" meta-type or one of its types.
"""
@@ -296,16 +331,32 @@
def IsEndType(reference):
if reference is not None:
- return len([typename for typename, parenttype in TypeHierarchy_list if parenttype == reference]) == 0
+ return not reference.startswith("ANY")
else:
return True
+def GetDataTypeRange(reference):
+ while reference is not None:
+ if reference in DataTypeRange:
+ return DataTypeRange[reference]
+ else:
+ reference = TypeHierarchy[reference]
+ return None
+
"""
returns list of all types that correspont to the ANY* meta type
"""
def GetSubTypes(reference):
- return [typename for typename, parenttype in TypeHierarchy_list if typename[:3] != "ANY" and IsOfType(typename, reference)]
-
+ return [typename for typename, parenttype in TypeHierarchy.items() if not typename.startswith("ANY") and IsOfType(typename, reference)]
+
+
+EnumeratedDataValues = []
+
+def ResetEnumeratedDataValues():
+ EnumeratedDataValues = []
+
+def AddEnumeratedDataValues(values):
+ EnumeratedDataValues.extend(values)
#-------------------------------------------------------------------------------
# Test identifier
@@ -489,7 +540,7 @@
else:
input_ovrloading_types = [None]
output_types = [None]
-
+
funcdeclname_orig = Function_decl["name"]
funcdeclname = Function_decl["name"].strip('*_')
fdc = Function_decl["inputs"][:]
--- a/xmlclass/xmlclass.py Tue Nov 27 12:58:34 2007 +0100
+++ b/xmlclass/xmlclass.py Thu Dec 06 18:05:29 2007 +0100
@@ -212,8 +212,11 @@
classname = "%s_%s"%(parent, nodename)
else:
classname = nodename
- self.GenerateXSDClasses(node, classname)
- nodetype = "cls:%s"%classname
+ if len(node.childNodes) > 0:
+ self.GenerateXSDClasses(node, classname)
+ nodetype = "cls:%s"%classname
+ else:
+ nodetype = classname
if name == "attribute":
if "use" in node._attrs:
use = GetAttributeValue(node._attrs["use"])
@@ -683,8 +686,10 @@
elif attr_type.startswith("cls:"):
val = classes[attr_type[4:].replace("[]","")]()
val.loadXMLTree(node)
+ else:
+ val = None
# Stock value in content attribute
- if val:
+ if val is not None:
if attr_type.endswith("[]"):
if self.content:
self.content["value"].append(val)
@@ -692,6 +697,8 @@
self.content = {"name":name,"value":[val]}
else:
self.content = {"name":name,"value":val}
+ else:
+ self.content = {"name":name,"value":None}
# Class has a list of attributes that can have different value types
elif "multichoice_content" in members.keys() and name in members["multichoice_content"].keys():
@@ -803,8 +810,11 @@
elif value_type.endswith("[]"):
for content in self.content["value"]:
text += content.generateXMLText(self.content["name"], indent + 1)
+ elif self.content["value"] is not None:
+ text += self.content["value"].generateXMLText(self.content["name"], indent + 1)
else:
- text += self.content["value"].generateXMLText(self.content["name"], indent + 1)
+ ind5, ind6 = getIndent(indent + 1, self.content["name"])
+ text += ind5 + "<%s/>\n"%self.content["name"]
elif attr == "multichoice_content":
if len(self.content) > 0:
for element in self.content: