plugger.py
changeset 395 433fd448dd31
parent 392 6617d3fb43e2
child 396 d1083f580ca1
equal deleted inserted replaced
394:5371e3d32f05 395:433fd448dd31
     9 from xml.dom import minidom
     9 from xml.dom import minidom
    10 import wx
    10 import wx
    11 
    11 
    12 #Quick hack to be able to find Beremiz IEC tools. Should be config params.
    12 #Quick hack to be able to find Beremiz IEC tools. Should be config params.
    13 base_folder = os.path.split(sys.path[0])[0]
    13 base_folder = os.path.split(sys.path[0])[0]
    14 sys.path.append(os.path.join(base_folder, "plcopeneditor"))
       
    15 sys.path.append(os.path.join(base_folder, "docutils"))
       
    16 
    14 
    17 from docpdf import *
    15 from docpdf import *
    18 from xmlclass import GenerateClassesFromXSDstring
    16 from xmlclass import GenerateClassesFromXSDstring
    19 from wxPopen import ProcessLogger
    17 from wxPopen import ProcessLogger
    20 
    18 
   175         if self.MandatoryParams and parts[0] == self.MandatoryParams[0]:
   173         if self.MandatoryParams and parts[0] == self.MandatoryParams[0]:
   176             self.MandatoryParams[1].setElementValue(parts[1], value)
   174             self.MandatoryParams[1].setElementValue(parts[1], value)
   177         elif self.PlugParams and parts[0] == self.PlugParams[0]:
   175         elif self.PlugParams and parts[0] == self.PlugParams[0]:
   178             self.PlugParams[1].setElementValue(parts[1], value)
   176             self.PlugParams[1].setElementValue(parts[1], value)
   179         return value, False
   177         return value, False
       
   178 
       
   179     def PlugMakeDir(self):
       
   180         os.mkdir(self.PlugPath())
   180 
   181 
   181     def PlugRequestSave(self):
   182     def PlugRequestSave(self):
   182         # If plugin do not have corresponding directory
   183         # If plugin do not have corresponding directory
   183         plugpath = self.PlugPath()
   184         plugpath = self.PlugPath()
   184         if not os.path.isdir(plugpath):
   185         if not os.path.isdir(plugpath):
   531                     _self.LoadChilds()
   532                     _self.LoadChilds()
   532                     #just loaded, nothing to saved
   533                     #just loaded, nothing to saved
   533                     _self.ChangesToSave = False
   534                     _self.ChangesToSave = False
   534                 else:
   535                 else:
   535                     # If plugin do not have corresponding file/dirs - they will be created on Save
   536                     # If plugin do not have corresponding file/dirs - they will be created on Save
   536                     os.mkdir(_self.PlugPath())
   537                     _self.PlugMakeDir()
   537                     # Find an IEC number
   538                     # Find an IEC number
   538                     _self.FindNewIEC_Channel(0)
   539                     _self.FindNewIEC_Channel(0)
   539                     # Call the plugin real __init__
   540                     # Call the plugin real __init__
   540                     if getattr(PlugClass, "__init__", None):
   541                     if getattr(PlugClass, "__init__", None):
   541                         PlugClass.__init__(_self)
   542                         PlugClass.__init__(_self)
   720         self.MandatoryParams = None
   721         self.MandatoryParams = None
   721         self.AppFrame = frame
   722         self.AppFrame = frame
   722         self.logger = logger
   723         self.logger = logger
   723         self._builder = None
   724         self._builder = None
   724         self._connector = None
   725         self._connector = None
       
   726         self.Deleting = False
   725         
   727         
   726         # Setup debug information
   728         # Setup debug information
   727         self.IECdebug_datas = {}
   729         self.IECdebug_datas = {}
   728         self.IECdebug_lock = Lock()
   730         self.IECdebug_lock = Lock()
   729 
   731 
   746         # Keep track of the plugin type name
   748         # Keep track of the plugin type name
   747         self.PlugType = "Beremiz"
   749         self.PlugType = "Beremiz"
   748         # After __init__ root plugin is not valid
   750         # After __init__ root plugin is not valid
   749         self.ProjectPath = None
   751         self.ProjectPath = None
   750         self.BuildPath = None
   752         self.BuildPath = None
   751         self.PLCEditor = None
       
   752         self.PLCDebug = None
       
   753         self.DebugThread = None
   753         self.DebugThread = None
   754         self.debug_break = False
   754         self.debug_break = False
   755         self.previous_plcstate = None
   755         self.previous_plcstate = None
   756         self.StatusPrint = {"Broken": self.logger.write_error,
   756         self.StatusPrint = {"Broken": self.logger.write_error,
   757                             None: lambda x: None}
   757                             None: lambda x: None}
   758         # copy PluginMethods so that it can be later customized
   758         # copy PluginMethods so that it can be later customized
   759         self.PluginMethods = [dic.copy() for dic in self.PluginMethods]
   759         self.PluginMethods = [dic.copy() for dic in self.PluginMethods]
   760         self.LoadSTLibrary()
   760         self.LoadSTLibrary()
       
   761 
       
   762     def __del__(self):
       
   763         self.Deleting = True
   761 
   764 
   762     def PluginLibraryFilePath(self):
   765     def PluginLibraryFilePath(self):
   763         return os.path.join(os.path.split(__file__)[0], "pous.xml")
   766         return os.path.join(os.path.split(__file__)[0], "pous.xml")
   764 
   767 
   765     def PlugTestModified(self):
   768     def PlugTestModified(self):
   862         return None
   865         return None
   863     
   866     
   864     def SaveProject(self):
   867     def SaveProject(self):
   865         if not self.SaveXMLFile():
   868         if not self.SaveXMLFile():
   866             self.SaveXMLFile(os.path.join(self.ProjectPath, 'plc.xml'))
   869             self.SaveXMLFile(os.path.join(self.ProjectPath, 'plc.xml'))
   867         if self.PLCEditor:
       
   868             self.PLCEditor.RefreshTitle()
       
   869         result = self.PlugRequestSave()
   870         result = self.PlugRequestSave()
   870         if result:
   871         if result:
   871             self.logger.write_error(result)
   872             self.logger.write_error(result)
   872     
       
   873     def CloseProject(self):
       
   874         if self.PLCEditor is not None:
       
   875             self.PLCEditor.Close()
       
   876         if self.PLCDebug is not None:
       
   877             self.PLCDebug.Close()
       
   878         
       
   879     
   873     
   880     # Update PLCOpenEditor Plugin Block types from loaded plugins
   874     # Update PLCOpenEditor Plugin Block types from loaded plugins
   881     def RefreshPluginsBlockLists(self):
   875     def RefreshPluginsBlockLists(self):
   882         if getattr(self, "PluggedChilds", None) is not None:
   876         if getattr(self, "PluggedChilds", None) is not None:
   883             self.ClearPluginTypes()
   877             self.ClearPluginTypes()
   884             self.AddPluginBlockList(self.PluginsBlockTypesFactory())
   878             self.AddPluginBlockList(self.PluginsBlockTypesFactory())
   885         if self.PLCEditor is not None:
   879         if self.AppFrame is not None:
   886             self.PLCEditor.RefreshEditor()
   880             self.AppFrame.RefreshLibraryTree()
       
   881             self.AppFrame.RefreshEditor()
   887     
   882     
   888     def PluginPath(self):
   883     def PluginPath(self):
   889         return os.path.join(os.path.split(__file__)[0], "plugins")
   884         return os.path.join(os.path.split(__file__)[0], "plugins")
   890     
   885     
   891     def PlugPath(self, PlugName=None):
   886     def PlugPath(self, PlugName=None):
  1231         
  1226         
  1232     def _build(self):
  1227     def _build(self):
  1233         """
  1228         """
  1234         Method called by user to (re)build SoftPLC and plugin tree
  1229         Method called by user to (re)build SoftPLC and plugin tree
  1235         """
  1230         """
  1236         if self.PLCEditor is not None:
  1231         if self.AppFrame is not None:
  1237             self.PLCEditor.ClearErrors()
  1232             self.AppFrame.ClearErrors()
  1238         
  1233         
  1239         buildpath = self._getBuildPath()
  1234         buildpath = self._getBuildPath()
  1240 
  1235 
  1241         # Eventually create build dir
  1236         # Eventually create build dir
  1242         if not os.path.exists(buildpath):
  1237         if not os.path.exists(buildpath):
  1332         chunk_infos = self.GetChunkInfos(from_location, to_location)
  1327         chunk_infos = self.GetChunkInfos(from_location, to_location)
  1333         self._EditPLC()
  1328         self._EditPLC()
  1334         for infos, (start_row, start_col) in chunk_infos:
  1329         for infos, (start_row, start_col) in chunk_infos:
  1335             start = (from_location[0] - start_row, from_location[1] - start_col)
  1330             start = (from_location[0] - start_row, from_location[1] - start_col)
  1336             end = (to_location[0] - start_row, to_location[1] - start_col)
  1331             end = (to_location[0] - start_row, to_location[1] - start_col)
  1337             self.PLCEditor.ShowError(infos, start, end)
  1332             self.AppFrame.ShowError(infos, start, end)
  1338 
  1333 
  1339     def _showIECcode(self):
  1334     def _showIECcode(self):
  1340         plc_file = self._getIECcodepath()
  1335         plc_file = self._getIECcodepath()
  1341         new_dialog = wx.Frame(self.AppFrame)
  1336         new_dialog = wx.Frame(self.AppFrame)
  1342         ST_viewer = TextViewer(new_dialog, "", None, None)
  1337         ST_viewer = TextViewer(new_dialog, "", None, None)
  1473 
  1468 
  1474     def ReArmDebugRegisterTimer(self):
  1469     def ReArmDebugRegisterTimer(self):
  1475         if self.DebugTimer is not None:
  1470         if self.DebugTimer is not None:
  1476             self.DebugTimer.cancel()
  1471             self.DebugTimer.cancel()
  1477 
  1472 
  1478         # Timer to prevent rapid-fire when registering many variables
  1473         if not self.Deleting:
  1479         # use wx.CallAfter use keep using same thread. TODO : use wx.Timer instead
  1474             # Timer to prevent rapid-fire when registering many variables
  1480         self.DebugTimer=Timer(0.5,wx.CallAfter,args = [self.RegisterDebugVarToConnector])
  1475             # use wx.CallAfter use keep using same thread. TODO : use wx.Timer instead
  1481         # Rearm anti-rapid-fire timer
  1476             self.DebugTimer=Timer(0.5,wx.CallAfter,args = [self.RegisterDebugVarToConnector])
  1482         self.DebugTimer.start()
  1477             # Rearm anti-rapid-fire timer
       
  1478             self.DebugTimer.start()
  1483 
  1479 
  1484         
  1480         
  1485     def SubscribeDebugIECVariable(self, IECPath, callableobj, *args, **kwargs):
  1481     def SubscribeDebugIECVariable(self, IECPath, callableobj, *args, **kwargs):
  1486         """
  1482         """
  1487         Dispatching use a dictionnary linking IEC variable paths
  1483         Dispatching use a dictionnary linking IEC variable paths
  1577         Start PLC (Debug Mode)
  1573         Start PLC (Debug Mode)
  1578         """
  1574         """
  1579         if self.GetIECProgramsAndVariables():
  1575         if self.GetIECProgramsAndVariables():
  1580             self._connector.StartPLC(debug=True)
  1576             self._connector.StartPLC(debug=True)
  1581             self.logger.write(_("Starting PLC (debug mode)\n"))
  1577             self.logger.write(_("Starting PLC (debug mode)\n"))
  1582             if self.PLCDebug is None:
  1578             if self.AppFrame:
  1583                 self.RefreshPluginsBlockLists()
  1579                 self.AppFrame.ResetGraphicViewers()
  1584                 def _onclose():
       
  1585                     self.PLCDebug = None
       
  1586                 self.PLCDebug = PLCOpenEditor(self.AppFrame, self, debug=True)
       
  1587                 self.PLCDebug._onclose = _onclose
       
  1588                 self.PLCDebug.Show()
       
  1589             else:
       
  1590                 self.PLCDebug.ResetGraphicViewers()
       
  1591             self.DebugThread = Thread(target=self.DebugThreadProc)
  1580             self.DebugThread = Thread(target=self.DebugThreadProc)
  1592             self.DebugThread.start()
  1581             self.DebugThread.start()
  1593         else:
  1582         else:
  1594             self.logger.write_error(_("Couldn't start PLC debug !\n"))
  1583             self.logger.write_error(_("Couldn't start PLC debug !\n"))
  1595         self.UpdateMethodsFromPLCStatus()
  1584         self.UpdateMethodsFromPLCStatus()
  1734         builder = self.GetBuilder()
  1723         builder = self.GetBuilder()
  1735         if builder is not None:
  1724         if builder is not None:
  1736             data = builder.GetBinaryCode()
  1725             data = builder.GetBinaryCode()
  1737             if data is not None :
  1726             if data is not None :
  1738                 if self._connector.NewPLC(MD5, data, extrafiles):
  1727                 if self._connector.NewPLC(MD5, data, extrafiles):
  1739                     if self.PLCDebug is not None:
  1728                     if self.AppFrame is not None:
  1740                         self.PLCDebug.Close()
  1729                         self.AppFrame.CloseDebugTabs()
  1741                         self.PLCDebug = None
       
  1742                     self.UnsubscribeAllDebugIECVariable()
  1730                     self.UnsubscribeAllDebugIECVariable()
  1743                     self.ProgramTransferred()
  1731                     self.ProgramTransferred()
  1744                     self.logger.write(_("Transfer completed successfully.\n"))
  1732                     self.logger.write(_("Transfer completed successfully.\n"))
  1745                 else:
  1733                 else:
  1746                     self.logger.write_error(_("Transfer failed\n"))
  1734                     self.logger.write_error(_("Transfer failed\n"))
  1747             else:
  1735             else:
  1748                 self.logger.write_error(_("No PLC to transfer (did build success ?)\n"))
  1736                 self.logger.write_error(_("No PLC to transfer (did build success ?)\n"))
  1749         self.UpdateMethodsFromPLCStatus()
  1737         self.UpdateMethodsFromPLCStatus()
  1750 
  1738 
  1751     PluginMethods = [
  1739     PluginMethods = [
  1752         {"bitmap" : opjimg("editPLC"),
       
  1753          "name" : _("Edit PLC"),
       
  1754          "tooltip" : _("Edit PLC program with PLCOpenEditor"),
       
  1755          "method" : "_EditPLC"},
       
  1756         {"bitmap" : opjimg("Build"),
  1740         {"bitmap" : opjimg("Build"),
  1757          "name" : _("Build"),
  1741          "name" : _("Build"),
  1758          "tooltip" : _("Build project into build folder"),
  1742          "tooltip" : _("Build project into build folder"),
  1759          "method" : "_build"},
  1743          "method" : "_build"},
  1760         {"bitmap" : opjimg("Clean"),
  1744         {"bitmap" : opjimg("Clean"),