Base definitions for beremiz plugins
from xml.dom import minidom
_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():
self.PlugParams.append( (name, obj) )
def __init__(self, PlugPath):
self.BaseParams = _BaseParamsClass()
self.MandatoryParams = [("BaseParams", self.BaseParams)]
def PluginXmlFilePath(self, PlugName=None):
return os.path.join(self.PlugPath(PlugName), "plugin.xml")
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')
# 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 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):
def STLibraryFactory(self):
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 GetChildByIECLocation(self, Location):
return self._GetChildBySomething('_',"IEC_Channel", Name)
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():
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 ?
if res < 0 : return CurrentChannel # Can't go bellow 0, do nothing
# 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)
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)
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:
# 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.
# 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)
# 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 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])