--- a/Beremiz.py Tue Aug 21 17:21:26 2007 +0200
+++ b/Beremiz.py Mon Aug 27 17:54:55 2007 +0200
@@ -22,6 +22,8 @@
#License along with this library; if not, write to the Free Software
#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+__version__ = "$Revision$" from time import localtime
@@ -41,43 +43,6 @@
from plcopen.structures import IEC_KEYWORDS#, AddPlugin
from PLCControler import PLCControler
-__version__ = "$Revision$"
- print "\nUsage of Beremiz.py :"
- print "\n %s [Projectpath]\n"%sys.argv[0]
- opts, args = getopt.getopt(sys.argv[1:], "h", ["help"])
-except getopt.GetoptError:
- # print help information and exit:
- if o in ("-h", "--help"):
-re_texts["letter"] = "[A-Za-z]"
-re_texts["digit"] = "[0-9]"
-LOCATED_MODEL = re.compile("__LOCATED_VAR\(([A-Z]*),([_A-Za-z0-9]*)\)")
""" Base class for file like objects to facilitate StdOut for the Shell."""
def __init__(self, output = None):
@@ -328,8 +293,8 @@
id=ID_BEREMIZDELETEBUSBUTTON)
- def __init__(self, parent):
+ def __init__(self, parent, projectOpen): for name in plugins.__all__:
@@ -680,6 +645,8 @@
return (err, outdata, errdata)
+ LOCATED_MODEL = re.compile("__LOCATED_VAR\(([A-Z]*),([_A-Za-z0-9]*)\)") self.TargetDir = os.path.join(self.CurrentProjectPath, "build")
if not os.path.exists(self.TargetDir):
@@ -710,7 +677,7 @@
lines = [line.strip() for line in location_file.readlines()]
- result = LOCATED_MODEL.match(line)
+ result = self.LOCATED_MODEL.match(line) locations.append(result.groups())
self.Log.write("Generating Network Configurations...\n")
@@ -979,13 +946,37 @@
sys.excepthook = handle_exception
if __name__ == '__main__':
+ print "\nUsage of Beremiz.py :" + print "\n %s [Projectpath]\n"%sys.argv[0] + opts, args = getopt.getopt(sys.argv[1:], "h", ["help"]) + except getopt.GetoptError: + # print help information and exit: + if o in ("-h", "--help"): wx.InitAllImageHandlers()
# Install a exception handle for bug reports
AddExceptHook(os.getcwd(),__version__)
+ frame = Beremiz(None, projectOpen) --- a/plugins/__init__.py Tue Aug 21 17:21:26 2007 +0200
+++ b/plugins/__init__.py Mon Aug 27 17:54:55 2007 +0200
@@ -1,11 +1,10 @@
from os import listdir, path
-from xmlclass import DeclareXSDClass
-from __templates import *
+from __templates import PlugTemplate _base_path = path.split(__file__)[0]
__all__ = [name for name in listdir(_base_path) if path.isdir(path.join(_base_path, name)) and name != "CVS" or name.endswith(".py") and not name.startswith("__")]
- __import__(name, globals(), locals(), [])
+# __import__(name, globals(), locals(), []) --- a/plugins/__templates.py Tue Aug 21 17:21:26 2007 +0200
+++ b/plugins/__templates.py Mon Aug 27 17:54:55 2007 +0200
@@ -1,20 +1,119 @@
-" Here are base type definitions for plugins "
+Base definitions for beremiz plugins +from xml.dom import minidom -class PluggableTemplate:
+_BaseParamsClass = GenerateClassesFromXSDstring("""<?xml version="1.0" encoding="ISO-8859-1" ?> + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <xsd:element name="BaseParams"> + <xsd:attribute name="Name" type="xsd:string" use="required"/> + <xsd:attribute name="IEC_Channel" type="xsd:integer" use="required" default="-1"/> + <xsd:attribute name="Enabled" type="xsd:boolean" use="required" default="true"/> + </xsd:schema>""")[0]["BaseParams"] + This class is the one that define plugins. + def _AddParamsMembers(self): + Classes = GenerateClassesFromXSDstring(self.XSD)[0] + for name, XSDclass in Classes.items(): + if XSDclass.IsBaseClass: + self.PlugParams.append( (name, obj) ) + setattr(self, name, obj) + def __init__(self, PlugPath): + self.BaseParams = _BaseParamsClass() + self.MandatoryParams = [("BaseParams", self.BaseParams)] + self._AddParamsMembers() + self.PluggedChilds = {} - def __init__(self, buspath):
+ def PluginXmlFilePath(self, PlugName=None): + return os.path.join(self.PlugPath(PlugName), "plugin.xml") - def TestModified(self):
+ def PlugPath(self,PlugName=None): + PlugName = self.BaseParams.getName() + return os.path.join(self.PlugParent.PlugPath(), PlugName + NameTypeSeparator + self.PlugType) + def PlugTestModified(self):
+ def PlugRequestSave(self): + # If plugin do not have corresponding directory + if not os.path.isdir(self.PlugPath(PlugName)): + os.mkdir(self.PlugPath(PlugName)) + # generate XML for all XML parameters controllers of the plugin + XMLString = '<?xml version="1.0" encoding="UTF-8"?>' + for nodeName, XMLController in self.PlugParams + self.MandatoryParams: + XMLString += XMLController.generateXMLTextMethod(self, nodeName, 0) + XMLFile = open(self.PluginXmlFilePath(PlugName),'w') + XMLFile.write(XMLString) + # Call the plugin specific OnPlugSave method + # go through all childs and do the same + for PlugChild in self.IterChilds(): + PlugChild.PlugRequestSave() + def PlugImport(self, src_PlugPath): + shutil.copytree(src_PlugPath, self.PlugPath) - def Generate_C(self, dirpath, locations):
- return [] # [filenames, ...]
+ def PlugGenerate_C(self, buildpath, current_location, locations): + @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) + @param locations: List of complete variables locations \ + [(IEC_loc, IEC_Direction IEC_Type, Name)]\ + ex: [((0,0,4,5),'I','X','__IX_0_0_4_5'),...] + def _Generate_C(self, buildpath, current_location, locations): + # Generate plugins [(Cfiles, CFLAGS)], LDFLAGS + PlugCFilesAndCFLAGS, PlugLDFLAGS = self._Generate_C(buildpath, current_location, locations) + # recurse through all childs, and stack their results + for PlugChild in self.IterChilds(): + # Get childs [(Cfiles, CFLAGS)], LDFLAGS + CFilesAndCFLAGS, LDFLAGS = \ + # but update location (add curent IEC channel at the end) + current_location + (self.BaseParams.getIEC_Channel()), + # filter locations that start with current IEC location + [ (l,d,t,n) for l,d,t,n in locations if l[0:len(current_location)] == current_location ]) + PlugCFilesAndCFLAGS += CFilesAndCFLAGS + return PlugCFilesAndCFLAGS,PlugLDFLAGS def BlockTypesFactory(self):
@@ -22,51 +121,169 @@
def STLibraryFactory(self):
- self.View = self.ViewClass()
- self.View.OnPluggClose = _onclose
+ for PlugType, PluggedChilds in self.PluggedChilds.items(): + for PlugInstance in PluggedChilds: + def _GetChildBySomething(self, sep, something, matching): + toks = matching.split(sep,1) + for PlugInstance in self.IterChilds: + # if match component of the name + if getattr(PlugInstance.BaseParams, something) == toks[0]: + # if Name have other components + # Recurse in order to find the latest object + return PlugInstance._GetChildBySomething( sep, something, toks[1]) + def GetChildByName(self, Name): + return self._GetChildBySomething('.',"Name", Name) -def _do_BaseParamsClasses():
- GenerateClassesFromXSDstring("""<?xml version="1.0" encoding="ISO-8859-1" ?>
- <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <xsd:element name="BaseParams">
- <xsd:attribute name="Enabled" type="xsd:string" use="required" />
- CreateClasses(Classes, Types)
+ def GetChildByIECLocation(self, Location): + return self._GetChildBySomething('_',"IEC_Channel", Name) - PluginsBaseParamsClass = Classes["BaseParams"]
+ def FindNewIEC_Channel(self, DesiredChannel): + Changes IEC Channel number to DesiredChannel if available, nearest available if not. + @param DesiredChannel: The desired IEC channel (int) + # Get Current IEC channel + CurrentChannel = self.BaseParams.getIEC_Channel() + # Do nothing if no change + if CurrentChannel == DesiredChannel: return CurrentChannel + # Build a list of used Channels out of parent's PluggedChilds + for PlugInstance in self.PlugParent.IterChilds(): + if PlugInstance != self: + AllChannels.append(PlugInstance.BaseParams.getIEC_Channel()) + # Now, try to guess the nearest available channel + while res in AllChannels: # While channel not free + if res < CurrentChannel: # Want to go down ? + res -= 1 # Test for n-1 + if res < 0 : return CurrentChannel # Can't go bellow 0, do nothing + else : # Want to go up ? + res += 1 # Test for n-1 + # Finally set IEC Channel + self.BaseParams.setIEC_Channel(res) + def _doRemoveChild(self, PlugInstance): + # Remove all childs of child + for SubPlugInstance in PlugInstance.IterChilds(): + PlugInstance._doRemoveChild(SubPlugInstance) + # Call the OnCloseMethod + PlugInstance.OnPlugClose() + shutil.rmtree(PlugInstance.PlugPath()) + # Remove child of PluggedChilds + self.PluggedChilds[PlugInstance.PlugType].remove(PlugInstance) + # Forget it... (View have to refresh) + def PlugRemoveChild(self, PlugName): + PlugInstance = self.GetChildByName(PlugName) + # Ask to his parent to remove it + PlugInstance.PlugParent._doRemoveChild(PlugInstance)
- GenerateClassesFromXSDstring("""<?xml version="1.0" encoding="ISO-8859-1" ?>
- <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <xsd:element name="BaseParams">
- <xsd:attribute name="BusId" type="xsd:integer" use="required" />
- <xsd:attribute name="Name" type="xsd:string" use="required" />
- CreateClasses(Classes, Types)
- BusBaseParamsClass = Classes["BaseParams"]
- return PluginsBaseParamsClass, BusBaseParamsClass
-PluginsBaseParamsClass, BusBaseParamsClass = _do_BaseParamsClasses()
+ def PlugAddChild(self, PlugName, PlugType): + Create the plugins that may be added as child to this node self + @param PlugType: string desining the plugin class name (get name from PlugChildsTypes) + @param PlugName: string for the name of the plugin instance + PlugChildsTypes = dict(self.PlugChildsTypes) + # Check that adding this plugin is allowed + PlugClass = PlugChildsTypes[PlugType] + raise Exception, "Cannot create child %s of type %s "%(PlugName, PlugType) + # if PlugClass is a class factory, call it. (prevent unneeded imports) + if type(PlugClass) == types.FunctionType: + PlugClass = PlugClass() + # Eventualy Initialize child instance list for this class of plugin + PluggedChildsWithSameClass = self.PluggedChilds.setdefault(PlugType,list()) + if PlugClass.MaxCount and len(PluggedChildsWithSameClass) >= PlugClass.MaxCount: + raise Exception, "Max count (%d) reached for this plugin of type %s "%(PlugClass.MaxCount, PlugType) + # create the final class, derived of provided plugin and template + class FinalPlugClass(PlugClass, PlugTemplate): + Plugin class is derivated into FinalPlugClass before being instanciated + This way __init__ is overloaded to ensure PlugTemplate.__init__ is called + before PlugClass.__init__, and to do the file related stuff. + _self.PlugParent = self + # Keep track of the plugin type name + _self.PlugType = PlugType + # Call the base plugin template init - change XSD into class members + PlugTemplate.__init__(_self) + # If dir have already be made, and file exist + if os.path.isdir(_self.PlugPath(PlugName)) and os.path.isfile(_self.PluginXmlFilePath(PlugName)): + #Load the plugin.xml file into parameters members + # Call the plugin real __init__ + PlugClass.__init__(_self) + #Load and init all the childs + # Check that IEC_Channel is not already in use. + self.FindNewIEC_Channel(self.BaseParams.getIEC_Channel()) + # If plugin do not have corresponding file/dirs - they will be created on Save + _self.BaseParams.setName(PlugName) + _self.FindNewIEC_Channel(0) + # Call the plugin real __init__ + PlugClass.__init__(_self) + # Create the object out of the resulting class + newPluginOpj = FinalPlugClass() + # Store it in PluggedChils + PluggedChildsWithSameClass.append(newPluginOpj) + def LoadXMLParams(self): + # PlugParams have been filled, make a local dict to work with + PlugParams = dict(self.PlugParams + self.MandatoryParams) + xmlfile = open(self.PluginXmlFilePath(PlugName), 'r') + tree = minidom.parse(xmlfile) + # for each root elements + for subtree in tree.childNodes: + # if a plugin specific parameter set + if subtree.nodeName in PlugParams: + #Load into associated xmlclass. + PlugParams[subtree.nodeName].loadXMLTree(subtree) + # Basic check. Better to fail immediately. + if(self.BaseParams.getName() != PlugName): + raise Exception, "Project tree layout do not match plugin.xml %s!=%s "%(PlugName,self.BaseParams.getName()) + # Now, self.PlugPath() should be OK + # Iterate over all PlugName@PlugType in plugin directory, and try to open them + for PlugDir in os.listdir(self.PlugPath()): + if os.path.isdir(os.path.join(self.PlugPath(),PlugDir)) and \ + PlugDir.count(NameTypeSeparator) == 1: + self.PlugAddChild(*PlugDir.split[NameTypeSeparator]) --- a/plugins/canfestival/canfestival.py Tue Aug 21 17:21:26 2007 +0200
+++ b/plugins/canfestival/canfestival.py Mon Aug 27 17:54:55 2007 +0200
@@ -4,12 +4,14 @@
import config_utils, gen_cfile
from networkedit import networkedit
-class _NetworkEditPlugg(networkedit):
+class _NetworkEdit(networkedit): + " Overload some of CanFestival Network Editor methods " def OnCloseFrame(self, event):
+ " Do reset _NodeListPlug.View when closed" -class BusController(NodeList):
+class _NodeListPlug(NodeList): XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="CanFestivalNode">
@@ -20,17 +22,29 @@
- ViewClass = _NetworkEditPlugg
def __init__(self, buspath):
NodeList.__init__(self, manager)
self.LoadProject(buspath)
- def TestModified(self):
+ self._View = _NetworkEdit() + self._View._onclose = _onclose + PluginMethods = [("NetworkEdit",_OpenView)] + def PlugTestModified(self):
+ def PlugRequestSave(self): @@ -43,14 +57,14 @@
res = gen_cfile.GenerateFile(filepath, master)
s = str(self.BaseParams.BusId)+"_IN(){}\n"
- s += "CanOpen(str(\""+self.CanFestivalNode.CAN_Device)+"\")"
+ s += "CanOpen(\""+self.CanFestivalNode.CAN_Device+"\")" return {"headers":["master.h"],"sources":["master.c"]}
XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="CanFestivalInstance">
@@ -61,6 +75,8 @@
+ PlugChildsTypes = [("CanOpenNode",_NodeListPlug)] def Generate_C(self, filepath, locations):
return C code for network dictionnary
@@ -69,7 +85,7 @@
res = gen_cfile.GenerateFile(filepath, master)
s = str(self.BaseParams.BusId)+"_IN(){}\n"
- s += "CanOpen(str(\""+self.CanFestivalNode.CAN_Device)+"\")"
+ s += "CanOpen(str(\""+self.CanFestivalNode.CAN_Device+"\")" --- a/plugins/svgui/svgui.py Tue Aug 21 17:21:26 2007 +0200
+++ b/plugins/svgui/svgui.py Mon Aug 27 17:54:55 2007 +0200
@@ -2,20 +2,20 @@
from DEFControler import DEFControler
from defeditor import EditorFrame
-class _EditorFramePlugg(EditorFrame):
+class _EditorFramePlug(EditorFrame): def OnClose(self, event):
-class BusController(DEFControler):
+class _DEFControlerPlug(DEFControler): - ViewClass = _EditorFramePlugg
+ ViewClass = _EditorFramePlug def __init__(self, buspath):
filepath = os.path.join(buspath, "gui.def")
if os.path.isfile(filepath):
self.OpenXMLFile(filepath)
self.SetFilePath(filepath)
@@ -31,7 +31,10 @@
"USINT" : "B", "UINT" : "W", "UDINT" : "D", "ULINT" : "L", "REAL" : "D", "LREAL" : "L",
"STRING" : "B", "BYTE" : "B", "WORD" : "W", "DWORD" : "D", "LWORD" : "L", "WSTRING" : "W"}
+ ChildsType = _DEFControlerPlug def BlockTypesFactory(self):
def generate_svgui_block(generator, block, body, link):
controller = generator.GetController()
@@ -39,7 +42,7 @@
type = block.getTypeName()
block_infos = GetBlockType(type)
bus_id, name = [word for word in name.split("_") if word != ""]
- block_id = self.PluginBuses[bus_id].GetElementIdFromName(name)
+ block_id = self.PlugChilds[bus_id].GetElementIdFromName(name) raise ValueError, "No corresponding block found"
if not generator.ComputedBlocks.get(name, False):