etisserant@31: import wx
lbessard@145: import os
etisserant@31: from plugger import PlugTemplate
lbessard@145: from CFileEditor import CFileEditor
lbessard@145: 
lbessard@145: from xml.dom import minidom
lbessard@145: from xmlclass import *
lbessard@145: import cPickle
lbessard@145: 
lbessard@145: CFileClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "cext_xsd.xsd")) 
lbessard@145: 
lbessard@145: #-------------------------------------------------------------------------------
lbessard@145: #                         Undo Buffer for CFile
lbessard@145: #-------------------------------------------------------------------------------
lbessard@145: 
lbessard@145: # Length of the buffer
lbessard@145: UNDO_BUFFER_LENGTH = 20
lbessard@145: 
lbessard@145: """
lbessard@145: Class implementing a buffer of changes made on the current editing model
lbessard@145: """
lbessard@145: class UndoBuffer:
lbessard@145: 
lbessard@145:     # Constructor initialising buffer
lbessard@145:     def __init__(self, currentstate, issaved = False):
lbessard@145:         self.Buffer = []
lbessard@145:         self.CurrentIndex = -1
lbessard@145:         self.MinIndex = -1
lbessard@145:         self.MaxIndex = -1
lbessard@145:         # if current state is defined
lbessard@145:         if currentstate:
lbessard@145:             self.CurrentIndex = 0
lbessard@145:             self.MinIndex = 0
lbessard@145:             self.MaxIndex = 0
lbessard@145:         # Initialising buffer with currentstate at the first place
lbessard@145:         for i in xrange(UNDO_BUFFER_LENGTH):
lbessard@145:             if i == 0:
lbessard@145:                 self.Buffer.append(currentstate)
lbessard@145:             else:
lbessard@145:                 self.Buffer.append(None)
lbessard@145:         # Initialising index of state saved
lbessard@145:         if issaved:
lbessard@145:             self.LastSave = 0
lbessard@145:         else:
lbessard@145:             self.LastSave = -1
lbessard@145:     
lbessard@145:     # Add a new state in buffer
lbessard@145:     def Buffering(self, currentstate):
lbessard@145:         self.CurrentIndex = (self.CurrentIndex + 1) % UNDO_BUFFER_LENGTH
lbessard@145:         self.Buffer[self.CurrentIndex] = currentstate
lbessard@145:         # Actualising buffer limits
lbessard@145:         self.MaxIndex = self.CurrentIndex
lbessard@145:         if self.MinIndex == self.CurrentIndex:
lbessard@145:             # If the removed state was the state saved, there is no state saved in the buffer
lbessard@145:             if self.LastSave == self.MinIndex:
lbessard@145:                 self.LastSave = -1
lbessard@145:             self.MinIndex = (self.MinIndex + 1) % UNDO_BUFFER_LENGTH
lbessard@145:         self.MinIndex = max(self.MinIndex, 0)
lbessard@145:     
lbessard@145:     # Return current state of buffer
lbessard@145:     def Current(self):
lbessard@145:         return self.Buffer[self.CurrentIndex]
lbessard@145:     
lbessard@145:     # Change current state to previous in buffer and return new current state
lbessard@145:     def Previous(self):
lbessard@145:         if self.CurrentIndex != self.MinIndex:
lbessard@145:             self.CurrentIndex = (self.CurrentIndex - 1) % UNDO_BUFFER_LENGTH
lbessard@145:             return self.Buffer[self.CurrentIndex]
lbessard@145:         return None
lbessard@145:     
lbessard@145:     # Change current state to next in buffer and return new current state
lbessard@145:     def Next(self):
lbessard@145:         if self.CurrentIndex != self.MaxIndex:
lbessard@145:             self.CurrentIndex = (self.CurrentIndex + 1) % UNDO_BUFFER_LENGTH
lbessard@145:             return self.Buffer[self.CurrentIndex]
lbessard@145:         return None
lbessard@145:     
lbessard@145:     # Return True if current state is the first in buffer
lbessard@145:     def IsFirst(self):
lbessard@145:         return self.CurrentIndex == self.MinIndex
lbessard@145:     
lbessard@145:     # Return True if current state is the last in buffer
lbessard@145:     def IsLast(self):
lbessard@145:         return self.CurrentIndex == self.MaxIndex
lbessard@145: 
lbessard@145:     # Note that current state is saved
lbessard@145:     def CurrentSaved(self):
lbessard@145:         self.LastSave = self.CurrentIndex
lbessard@145:         
lbessard@145:     # Return True if current state is saved
lbessard@145:     def IsCurrentSaved(self):
lbessard@145:         return self.LastSave == self.CurrentIndex
lbessard@145: 
lbessard@145: 
lbessard@145: TYPECONVERSION = {"BOOL" : "X", "SINT" : "B", "INT" : "W", "DINT" : "D", "LINT" : "L",
lbessard@145:     "USINT" : "B", "UINT" : "W", "UDINT" : "D", "ULINT" : "L", "REAL" : "D", "LREAL" : "L",
lbessard@145:     "STRING" : "B", "BYTE" : "B", "WORD" : "W", "DWORD" : "D", "LWORD" : "L", "WSTRING" : "W"}
etisserant@31: 
etisserant@31: class _Cfile:
etisserant@31:     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
etisserant@31:     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
lbessard@145:       <xsd:element name="CExtension">
etisserant@31:         <xsd:complexType>
etisserant@45:           <xsd:attribute name="CFLAGS" type="xsd:string" use="required"/>
etisserant@45:           <xsd:attribute name="LDFLAGS" type="xsd:string" use="required"/>
etisserant@31:         </xsd:complexType>
etisserant@31:       </xsd:element>
etisserant@31:     </xsd:schema>
etisserant@31:     """
etisserant@31:     def __init__(self):
lbessard@145:         filepath = self.CFileName()
lbessard@145:         
lbessard@145:         self.Buffering = False
lbessard@145:         self.CFile = CFileClasses["CFile"]()
lbessard@145:         self.CFileBuffer = UndoBuffer(self.Copy(self.CFile), False)
lbessard@145:         if os.path.isfile(filepath):
lbessard@145:             xmlfile = open(filepath, 'r')
lbessard@145:             tree = minidom.parse(xmlfile)
lbessard@145:             xmlfile.close()
lbessard@145:             
lbessard@145:             for child in tree.childNodes:
lbessard@145:                 if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "CFile":
lbessard@145:                     self.CFile.loadXMLTree(child, ["xmlns", "xmlns:xsi", "xsi:schemaLocation"])
lbessard@145:                     self.CFileBuffer = UndoBuffer(self.Copy(self.CFile), True)
lbessard@145:         else:
lbessard@145:             self.OnPlugSave()
lbessard@145: 
lbessard@145:     def CFileName(self):
lbessard@145:         return os.path.join(self.PlugPath(), "cfile.xml")
lbessard@145: 
lbessard@145:     def GetFilename(self):
lbessard@145:         if self.CFileBuffer.IsCurrentSaved():
lbessard@145:             return "cfile"
lbessard@145:         else:
lbessard@145:             return "~cfile~"
lbessard@145: 
lbessard@145:     def GetBaseTypes(self):
lbessard@145:         return self.GetPlugRoot().GetBaseTypes()
lbessard@145: 
lbessard@145:     def GetDataTypes(self, basetypes = False):
lbessard@145:         return self.GetPlugRoot().GetDataTypes(basetypes = basetypes)
lbessard@145: 
lbessard@145:     def GetSizeOfType(self, type):
lbessard@145:         return TYPECONVERSION[self.GetPlugRoot().GetBaseType(type)]
lbessard@145: 
lbessard@145:     def SetVariables(self, variables):
lbessard@145:         self.CFile.variables.setvariable([])
lbessard@145:         for var in variables:
lbessard@145:             variable = CFileClasses["variables_variable"]()
lbessard@145:             variable.setname(var["Name"])
lbessard@145:             variable.settype(var["Type"])
lbessard@145:             variable.setclass(var["Class"])
lbessard@145:             self.CFile.variables.appendvariable(variable)
lbessard@145:     
lbessard@145:     def GetVariables(self):
lbessard@145:         datas = []
lbessard@145:         for var in self.CFile.variables.getvariable():
lbessard@145:             datas.append({"Name" : var.getname(), "Type" : var.gettype(), "Class" : var.getclass()})
lbessard@145:         return datas
lbessard@145: 
lbessard@145:     def SetPartText(self, name, text):
lbessard@145:         if name == "Includes":
lbessard@145:             self.CFile.includes.settext(text)
lbessard@145:         elif name == "Globals":
lbessard@145:             self.CFile.globals.settext(text)
lbessard@145:         elif name == "Init":
lbessard@145:             self.CFile.initFunction.settext(text)
lbessard@145:         elif name == "CleanUp":
lbessard@145:             self.CFile.cleanUpFunction.settext(text)
lbessard@145:         elif name == "Retrieve":
lbessard@145:             self.CFile.retrieveFunction.settext(text)
lbessard@145:         elif name == "Publish":
lbessard@145:             self.CFile.publishFunction.settext(text)
lbessard@145:         
lbessard@145:     def GetPartText(self, name):
lbessard@145:         if name == "Includes":
lbessard@145:             return self.CFile.includes.gettext()
lbessard@145:         elif name == "Globals":
lbessard@145:             return self.CFile.globals.gettext()
lbessard@145:         elif name == "Init":
lbessard@145:             return self.CFile.initFunction.gettext()
lbessard@145:         elif name == "CleanUp":
lbessard@145:             return self.CFile.cleanUpFunction.gettext()
lbessard@145:         elif name == "Retrieve":
lbessard@145:             return self.CFile.retrieveFunction.gettext()
lbessard@145:         elif name == "Publish":
lbessard@145:             return self.CFile.publishFunction.gettext()
lbessard@145:         return ""
lbessard@145:     
lbessard@145:     _View = None
etisserant@203:     def _OpenView(self):
lbessard@145:         if not self._View:
lbessard@145:             def _onclose():
lbessard@145:                 self._View = None
lbessard@145:             def _onsave():
lbessard@145:                 self.GetPlugRoot().SaveProject()
lbessard@145:             self._View = CFileEditor(self.GetPlugRoot().AppFrame, self)
lbessard@145:             self._View._onclose = _onclose
lbessard@145:             self._View._onsave = _onsave
lbessard@145:             self._View.Show()
etisserant@45: 
lbessard@65:     PluginMethods = [
etisserant@199:         {"bitmap" : os.path.join("images", "EditCfile"),
etisserant@199:          "name" : "Edit C File", 
lbessard@65:          "tooltip" : "Edit C File",
etisserant@105:          "method" : "_OpenView"},
lbessard@65:     ]
etisserant@45: 
etisserant@31:     def OnPlugSave(self):
lbessard@145:         filepath = self.CFileName()
lbessard@145:         
lbessard@145:         text = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
lbessard@145:         extras = {"xmlns":"http://www.w3.org/2001/XMLSchema",
lbessard@145:                   "xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance",
lbessard@145:                   "xsi:schemaLocation" : "cext_xsd.xsd"}
lbessard@145:         text += self.CFile.generateXMLText("CFile", 0, extras)
lbessard@145: 
lbessard@145:         xmlfile = open(filepath,"w")
lbessard@145:         xmlfile.write(text)
lbessard@145:         xmlfile.close()
lbessard@145:         
lbessard@145:         self.CFileBuffer.CurrentSaved()
etisserant@31:         return True
etisserant@31: 
etisserant@203:     def PlugGenerate_C(self, buildpath, locations):
etisserant@31:         """
etisserant@31:         Generate C code
etisserant@31:         @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5)
etisserant@31:         @param locations: List of complete variables locations \
etisserant@31:             [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...)
etisserant@31:             "NAME" : name of the variable (generally "__IW0_1_2" style)
etisserant@31:             "DIR" : direction "Q","I" or "M"
etisserant@31:             "SIZE" : size "X", "B", "W", "D", "L"
etisserant@31:             "LOC" : tuple of interger for IEC location (0,1,2,...)
etisserant@31:             }, ...]
etisserant@31:         @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
etisserant@31:         """
etisserant@31:         current_location = self.GetCurrentLocation()
etisserant@31:         # define a unique name for the generated C file
etisserant@45:         location_str = "_".join(map(lambda x:str(x), current_location))
lbessard@145:         
lbessard@145:         text = "/* Code generated by Beremiz c_ext plugin */\n\n"
lbessard@145:         
lbessard@145:         # Adding includes
lbessard@145:         text += "/* User includes */\n"
lbessard@145:         text += self.CFile.includes.gettext()
lbessard@145:         text += "\n"
lbessard@145:         
lbessard@145:         text += """/* Beremiz c_ext plugin includes */
lbessard@145: #ifdef _WINDOWS_H
lbessard@145:   #include "iec_types.h"
lbessard@145: #else
lbessard@145:   #include "iec_std_lib.h"
lbessard@145: #endif
lbessard@145: 
lbessard@145: """
lbessard@145: 
lbessard@145:         # Adding variables
lbessard@145:         vars = []
lbessard@145:         inputs = outputs = 0
lbessard@145:         for variable in self.CFile.variables.variable:
lbessard@145:             var = {"Name" : variable.getname(), "Type" : variable.gettype()}
lbessard@145:             if variable.getclass() == "input":
lbessard@145:                 var["location"] = "__I%s%s_%d"%(self.GetSizeOfType(var["Type"]), location_str, inputs)
lbessard@145:                 inputs += 1
lbessard@145:             else:
lbessard@145:                 var["location"] = "__Q%s%s_%d"%(self.GetSizeOfType(var["Type"]), location_str, outputs)
lbessard@145:                 outputs += 1
lbessard@145:             vars.append(var)
lbessard@145:         text += "/* Beremiz c_ext plugin user variables definition */\n"
lbessard@145:         base_types = self.GetPlugRoot().GetBaseTypes()
lbessard@145:         for var in vars:
lbessard@145:             if var["Type"] in base_types:
lbessard@145:                 prefix = "IEC_"
lbessard@145:             else:
lbessard@145:                 prefix = ""
etisserant@180:             text += "%s%s beremiz%s;\n"%(prefix, var["Type"], var["location"])
etisserant@180:             text += "%s%s *%s = &beremiz%s;\n"%(prefix, var["Type"], var["location"], var["location"])
lbessard@145:         text += "/* User variables reference */\n"
lbessard@145:         for var in vars:
etisserant@180:             text += "#define %s beremiz%s\n"%(var["Name"], var["location"])
lbessard@145:         text += "\n"
lbessard@145:         
lbessard@145:         # Adding user global variables and routines
lbessard@145:         text += "/* User internal user variables and routines */\n"
lbessard@145:         text += self.CFile.globals.gettext()
lbessard@145:         
lbessard@145:         # Adding Beremiz plugin functions
lbessard@145:         text += "/* Beremiz plugin functions */\n"
lbessard@145:         text += "int __init_%s(int argc,char **argv)\n{\n"%location_str
lbessard@145:         text += self.CFile.initFunction.gettext()
etisserant@180:         text += "  return 0;\n"
lbessard@145:         text += "\n}\n\n"
lbessard@145:         
lbessard@145:         text += "void __cleanup_%s()\n{\n"%location_str
lbessard@145:         text += self.CFile.cleanUpFunction.gettext()
lbessard@145:         text += "\n}\n\n"
lbessard@145:         
lbessard@145:         text += "void __retrieve_%s()\n{\n"%location_str
lbessard@145:         text += self.CFile.retrieveFunction.gettext()
lbessard@145:         text += "\n}\n\n"
lbessard@145:         
lbessard@145:         text += "void __publish_%s()\n{\n"%location_str
lbessard@145:         text += self.CFile.publishFunction.gettext()
lbessard@145:         text += "\n}\n\n"
lbessard@145:         
lbessard@145:         Gen_Cfile_path = os.path.join(buildpath, "CFile_%s.c"%location_str)
lbessard@145:         cfile = open(Gen_Cfile_path,'w')
lbessard@145:         cfile.write(text)
lbessard@145:         cfile.close()
lbessard@145:         
lbessard@145:         if wx.Platform == '__WXMSW__':
lbessard@145:             matiec_flags = " -I../../matiec/lib"
lbessard@145:         else:
lbessard@145:             matiec_flags = " -I../matiec/lib"
lbessard@145:         
lbessard@145:         return [(Gen_Cfile_path, str(self.CExtension.getCFLAGS() + matiec_flags))],str(self.CExtension.getLDFLAGS()),True
lbessard@145:         
lbessard@145: #-------------------------------------------------------------------------------
lbessard@145: #                      Current Buffering Management Functions
lbessard@145: #-------------------------------------------------------------------------------
lbessard@145: 
lbessard@145:     """
lbessard@145:     Return a copy of the project
lbessard@145:     """
lbessard@145:     def Copy(self, model):
lbessard@145:         return cPickle.loads(cPickle.dumps(model))
lbessard@145: 
lbessard@145:     def BufferCFile(self):
lbessard@145:         self.CFileBuffer.Buffering(self.Copy(self.CFile))
lbessard@145:     
lbessard@145:     def StartBuffering(self):
lbessard@145:         self.CFileBuffer.Buffering(self.CFile)
lbessard@145:         self.Buffering = True
lbessard@145:         
lbessard@145:     def EndBuffering(self):
lbessard@145:         if self.Buffering:
lbessard@145:             self.CFile = self.Copy(self.CFile)
lbessard@145:             self.Buffering = False
lbessard@145:     
lbessard@145:     def CFileIsSaved(self):
lbessard@145:         if self.CFileBuffer:
lbessard@145:             return self.CFileBuffer.IsCurrentSaved()
lbessard@145:         else:
lbessard@145:             return True
lbessard@145: 
lbessard@145:     def LoadPrevious(self):
lbessard@145:         self.CFile = self.Copy(self.CFileBuffer.Previous())
lbessard@145:     
lbessard@145:     def LoadNext(self):
lbessard@145:         self.CFile = self.Copy(self.CFileBuffer.Next())
lbessard@145:     
lbessard@145:     def GetBufferState(self):
lbessard@145:         first = self.CFileBuffer.IsFirst()
lbessard@145:         last = self.CFileBuffer.IsLast()
lbessard@145:         return not first, not last
lbessard@145: 
etisserant@31: class RootClass:
etisserant@31: 
etisserant@106:     PlugChildsTypes = [("C_File",_Cfile, "C file")]
etisserant@31:     
etisserant@203:     def PlugGenerate_C(self, buildpath, locations):
etisserant@55:         return [],"",False
etisserant@31: 
etisserant@31: