ProjectController.py
branchpython3
changeset 3750 f62625418bff
parent 3747 1db10e9df882
child 3752 9f6f46dbe3ae
equal deleted inserted replaced
3749:fda6c1a37662 3750:f62625418bff
    26 """
    26 """
    27 Beremiz Project Controller
    27 Beremiz Project Controller
    28 """
    28 """
    29 
    29 
    30 
    30 
    31 from __future__ import absolute_import
    31 
    32 import os
    32 import os
    33 import traceback
    33 import traceback
    34 import time
    34 import time
    35 from time import localtime
    35 from time import localtime
    36 import shutil
    36 import shutil
    38 import tempfile
    38 import tempfile
    39 import hashlib
    39 import hashlib
    40 from datetime import datetime
    40 from datetime import datetime
    41 from weakref import WeakKeyDictionary
    41 from weakref import WeakKeyDictionary
    42 from functools import reduce
    42 from functools import reduce
    43 from itertools import izip
    43 
    44 from distutils.dir_util import copy_tree
    44 from distutils.dir_util import copy_tree
    45 from six.moves import xrange
    45 from six.moves import xrange
    46 
    46 
    47 import wx
    47 import wx
    48 
    48 
   632         for lib in self.Libraries:
   632         for lib in self.Libraries:
   633             res = lib.Generate_C(buildpath, self._VariablesList, LibIECCflags)
   633             res = lib.Generate_C(buildpath, self._VariablesList, LibIECCflags)
   634             LocatedCCodeAndFlags.append(res[:2])
   634             LocatedCCodeAndFlags.append(res[:2])
   635             if len(res) > 2:
   635             if len(res) > 2:
   636                 Extras.extend(res[2:])
   636                 Extras.extend(res[2:])
   637         return map(list, zip(*LocatedCCodeAndFlags)) + [tuple(Extras)]
   637         return list(map(list, list(zip(*LocatedCCodeAndFlags)))) + [tuple(Extras)]
   638 
   638 
   639     # Update PLCOpenEditor ConfNode Block types from loaded confnodes
   639     # Update PLCOpenEditor ConfNode Block types from loaded confnodes
   640     def RefreshConfNodesBlockLists(self):
   640     def RefreshConfNodesBlockLists(self):
   641         if getattr(self, "Children", None) is not None:
   641         if getattr(self, "Children", None) is not None:
   642             self.ClearConfNodeTypes()
   642             self.ClearConfNodeTypes()
   886         if not C_files:
   886         if not C_files:
   887             self.logger.write_error(
   887             self.logger.write_error(
   888                 _("Error : At least one configuration and one resource must be declared in PLC !\n"))
   888                 _("Error : At least one configuration and one resource must be declared in PLC !\n"))
   889             return False
   889             return False
   890         # transform those base names to full names with path
   890         # transform those base names to full names with path
   891         C_files = map(
   891         C_files = [os.path.join(buildpath, filename) for filename in C_files]
   892             lambda filename: os.path.join(buildpath, filename), C_files)
       
   893 
   892 
   894         # prepend beremiz include to configuration header
   893         # prepend beremiz include to configuration header
   895         H_files = [fname for fname in result.splitlines() if fname[
   894         H_files = [fname for fname in result.splitlines() if fname[
   896             -2:] == ".h" or fname[-2:] == ".H"]
   895             -2:] == ".h" or fname[-2:] == ".H"]
   897         H_files.remove("LOCATED_VARIABLES.h")
   896         H_files.remove("LOCATED_VARIABLES.h")
   898         H_files = map(
   897         H_files = [os.path.join(buildpath, filename) for filename in H_files]
   899             lambda filename: os.path.join(buildpath, filename), H_files)
       
   900         for H_file in H_files:
   898         for H_file in H_files:
   901             with open(H_file, 'r') as original:
   899             with open(H_file, 'r') as original:
   902                 data = original.read()
   900                 data = original.read()
   903             with open(H_file, 'w') as modified:
   901             with open(H_file, 'w') as modified:
   904                 modified.write('#include "beremiz.h"\n' + data)
   902                 modified.write('#include "beremiz.h"\n' + data)
   993 
   991 
   994                 # first section contains programs
   992                 # first section contains programs
   995                 for line in ListGroup[0]:
   993                 for line in ListGroup[0]:
   996                     # Split and Maps each field to dictionnary entries
   994                     # Split and Maps each field to dictionnary entries
   997                     attrs = dict(
   995                     attrs = dict(
   998                         zip(ProgramsListAttributeName, line.strip().split(';')))
   996                         list(zip(ProgramsListAttributeName, line.strip().split(';'))))
   999                     # Truncate "C_path" to remove conf an resources names
   997                     # Truncate "C_path" to remove conf an resources names
  1000                     attrs["C_path"] = '__'.join(
   998                     attrs["C_path"] = '__'.join(
  1001                         attrs["C_path"].split(".", 2)[1:])
   999                         attrs["C_path"].split(".", 2)[1:])
  1002                     # Push this dictionnary into result.
  1000                     # Push this dictionnary into result.
  1003                     self._ProgramList.append(attrs)
  1001                     self._ProgramList.append(attrs)
  1006                 config_FBs = {}
  1004                 config_FBs = {}
  1007                 Idx = 0
  1005                 Idx = 0
  1008                 for line in ListGroup[1]:
  1006                 for line in ListGroup[1]:
  1009                     # Split and Maps each field to dictionnary entries
  1007                     # Split and Maps each field to dictionnary entries
  1010                     attrs = dict(
  1008                     attrs = dict(
  1011                         zip(VariablesListAttributeName, line.strip().split(';')))
  1009                         list(zip(VariablesListAttributeName, line.strip().split(';'))))
  1012                     # Truncate "C_path" to remove conf an resources names
  1010                     # Truncate "C_path" to remove conf an resources names
  1013                     parts = attrs["C_path"].split(".", 2)
  1011                     parts = attrs["C_path"].split(".", 2)
  1014                     if len(parts) > 2:
  1012                     if len(parts) > 2:
  1015                         config_FB = config_FBs.get(tuple(parts[:2]))
  1013                         config_FB = config_FBs.get(tuple(parts[:2]))
  1016                         if config_FB:
  1014                         if config_FB:
  1096         Use confnodes layout given in LocationCFilesAndCFLAGS to
  1094         Use confnodes layout given in LocationCFilesAndCFLAGS to
  1097         generate glue code that dispatch calls to all confnodes
  1095         generate glue code that dispatch calls to all confnodes
  1098         """
  1096         """
  1099         # filter location that are related to code that will be called
  1097         # filter location that are related to code that will be called
  1100         # in retreive, publish, init, cleanup
  1098         # in retreive, publish, init, cleanup
  1101         locstrs = map(lambda x: "_".join(map(str, x)),
  1099         locstrs = ["_".join(map(str, x)) for x in [loc for loc, _Cfiles, DoCalls in
  1102                       [loc for loc, _Cfiles, DoCalls in
  1100                        self.LocationCFilesAndCFLAGS if loc and DoCalls]]
  1103                        self.LocationCFilesAndCFLAGS if loc and DoCalls])
       
  1104 
  1101 
  1105         # Generate main, based on template
  1102         # Generate main, based on template
  1106         if not self.BeremizRoot.getDisable_Extensions():
  1103         if not self.BeremizRoot.getDisable_Extensions():
  1107             plc_main_code = targets.GetCode("plc_main_head.c") % {
  1104             plc_main_code = targets.GetCode("plc_main_head.c") % {
  1108                 "calls_prototypes": "\n".join([(
  1105                 "calls_prototypes": "\n".join([(
  1111                     "void __retrieve_%(s)s(void);\n" +
  1108                     "void __retrieve_%(s)s(void);\n" +
  1112                     "void __publish_%(s)s(void);") % {'s': locstr} for locstr in locstrs]),
  1109                     "void __publish_%(s)s(void);") % {'s': locstr} for locstr in locstrs]),
  1113                 "retrieve_calls": "\n    ".join([
  1110                 "retrieve_calls": "\n    ".join([
  1114                     "__retrieve_%s();" % locstr for locstr in locstrs]),
  1111                     "__retrieve_%s();" % locstr for locstr in locstrs]),
  1115                 "publish_calls": "\n    ".join([  # Call publish in reverse order
  1112                 "publish_calls": "\n    ".join([  # Call publish in reverse order
  1116                     "__publish_%s();" % locstrs[i - 1] for i in xrange(len(locstrs), 0, -1)]),
  1113                     "__publish_%s();" % locstrs[i - 1] for i in range(len(locstrs), 0, -1)]),
  1117                 "init_calls": "\n    ".join([
  1114                 "init_calls": "\n    ".join([
  1118                     "init_level=%d; " % (i + 1) +
  1115                     "init_level=%d; " % (i + 1) +
  1119                     "if((res = __init_%s(argc,argv))){" % locstr +
  1116                     "if((res = __init_%s(argc,argv))){" % locstr +
  1120                     # "printf(\"%s\"); "%locstr + #for debug
  1117                     # "printf(\"%s\"); "%locstr + #for debug
  1121                     "return res;}" for i, locstr in enumerate(locstrs)]),
  1118                     "return res;}" for i, locstr in enumerate(locstrs)]),
  1122                 "cleanup_calls": "\n    ".join([
  1119                 "cleanup_calls": "\n    ".join([
  1123                     "if(init_level >= %d) " % i +
  1120                     "if(init_level >= %d) " % i +
  1124                     "__cleanup_%s();" % locstrs[i - 1] for i in xrange(len(locstrs), 0, -1)])
  1121                     "__cleanup_%s();" % locstrs[i - 1] for i in range(len(locstrs), 0, -1)])
  1125             }
  1122             }
  1126         else:
  1123         else:
  1127             plc_main_code = targets.GetCode("plc_main_head.c") % {
  1124             plc_main_code = targets.GetCode("plc_main_head.c") % {
  1128                 "calls_prototypes": "\n",
  1125                 "calls_prototypes": "\n",
  1129                 "retrieve_calls":   "\n",
  1126                 "retrieve_calls":   "\n",
  1393                                     for extension, edit_name, edit_class in features.file_editors
  1390                                     for extension, edit_name, edit_class in features.file_editors
  1394                                     if extension == file_extension])
  1391                                     if extension == file_extension])
  1395 
  1392 
  1396                     if editor_name == "":
  1393                     if editor_name == "":
  1397                         if len(editors) == 1:
  1394                         if len(editors) == 1:
  1398                             editor_name = editors.keys()[0]
  1395                             editor_name = list(editors.keys())[0]
  1399                         elif len(editors) > 0:
  1396                         elif len(editors) > 0:
  1400                             names = editors.keys()
  1397                             names = list(editors.keys())
  1401                             dialog = wx.SingleChoiceDialog(
  1398                             dialog = wx.SingleChoiceDialog(
  1402                                 self.AppFrame,
  1399                                 self.AppFrame,
  1403                                 _("Select an editor:"),
  1400                                 _("Select an editor:"),
  1404                                 _("Editor selection"),
  1401                                 _("Editor selection"),
  1405                                 names,
  1402                                 names,
  1432             self._IECCodeView = None
  1429             self._IECCodeView = None
  1433         if self._IECRawCodeView == view:
  1430         if self._IECRawCodeView == view:
  1434             self._IECRawCodeView = None
  1431             self._IECRawCodeView = None
  1435         if self._ProjectFilesView == view:
  1432         if self._ProjectFilesView == view:
  1436             self._ProjectFilesView = None
  1433             self._ProjectFilesView = None
  1437         if view in self._FileEditors.values():
  1434         if view in list(self._FileEditors.values()):
  1438             self._FileEditors.pop(view.GetFilePath())
  1435             self._FileEditors.pop(view.GetFilePath())
  1439 
  1436 
  1440     def _Clean(self):
  1437     def _Clean(self):
  1441         self._CloseView(self._IECCodeView)
  1438         self._CloseView(self._IECCodeView)
  1442         if os.path.isdir(os.path.join(self._getBuildPath())):
  1439         if os.path.isdir(os.path.join(self._getBuildPath())):
  1504             status = PlcStatus.Disconnected
  1501             status = PlcStatus.Disconnected
  1505         if self.previous_plcstate != status:
  1502         if self.previous_plcstate != status:
  1506             allmethods = self.DefaultMethods.copy()
  1503             allmethods = self.DefaultMethods.copy()
  1507             allmethods.update(
  1504             allmethods.update(
  1508                 self.MethodsFromStatus.get(status, {}))
  1505                 self.MethodsFromStatus.get(status, {}))
  1509             for method, active in allmethods.items():
  1506             for method, active in list(allmethods.items()):
  1510                 self.ShowMethod(method, active)
  1507                 self.ShowMethod(method, active)
  1511             self.previous_plcstate = status
  1508             self.previous_plcstate = status
  1512             if self.AppFrame is not None:
  1509             if self.AppFrame is not None:
  1513                 updated = True
  1510                 updated = True
  1514                 self.AppFrame.RefreshStatusToolBar()
  1511                 self.AppFrame.RefreshStatusToolBar()
  1550                 if len(Traces) > 0:
  1547                 if len(Traces) > 0:
  1551                     for debug_tick, debug_buff in Traces:
  1548                     for debug_tick, debug_buff in Traces:
  1552                         debug_vars = UnpackDebugBuffer(
  1549                         debug_vars = UnpackDebugBuffer(
  1553                             debug_buff, self.TracedIECTypes)
  1550                             debug_buff, self.TracedIECTypes)
  1554                         if debug_vars is not None:
  1551                         if debug_vars is not None:
  1555                             for IECPath, values_buffer, value in izip(
  1552                             for IECPath, values_buffer, value in zip(
  1556                                     self.TracedIECPath,
  1553                                     self.TracedIECPath,
  1557                                     self.DebugValuesBuffers,
  1554                                     self.DebugValuesBuffers,
  1558                                     debug_vars):
  1555                                     debug_vars):
  1559                                 IECdebug_data = self.IECdebug_datas.get(
  1556                                 IECdebug_data = self.IECdebug_datas.get(
  1560                                     IECPath, None)
  1557                                     IECPath, None)
  1576                                 self.LastComplainDebugToken = self.DebugToken
  1573                                 self.LastComplainDebugToken = self.DebugToken
  1577 
  1574 
  1578 
  1575 
  1579 
  1576 
  1580         buffers, self.DebugValuesBuffers = (self.DebugValuesBuffers,
  1577         buffers, self.DebugValuesBuffers = (self.DebugValuesBuffers,
  1581                                             [list() for dummy in xrange(len(self.TracedIECPath))])
  1578                                             [list() for dummy in range(len(self.TracedIECPath))])
  1582 
  1579 
  1583         ticks, self.DebugTicks = self.DebugTicks, []
  1580         ticks, self.DebugTicks = self.DebugTicks, []
  1584 
  1581 
  1585         return debug_status, ticks, buffers
  1582         return debug_status, ticks, buffers
  1586 
  1583 
  1601         Idxs = []
  1598         Idxs = []
  1602         self.TracedIECPath = []
  1599         self.TracedIECPath = []
  1603         self.TracedIECTypes = []
  1600         self.TracedIECTypes = []
  1604         if self._connector is not None and self.debug_status != PlcStatus.Broken:
  1601         if self._connector is not None and self.debug_status != PlcStatus.Broken:
  1605             IECPathsToPop = []
  1602             IECPathsToPop = []
  1606             for IECPath, data_tuple in self.IECdebug_datas.iteritems():
  1603             for IECPath, data_tuple in self.IECdebug_datas.items():
  1607                 WeakCallableDict, _data_log, _status, fvalue, _buffer_list = data_tuple
  1604                 WeakCallableDict, _data_log, _status, fvalue, _buffer_list = data_tuple
  1608                 if len(WeakCallableDict) == 0:
  1605                 if len(WeakCallableDict) == 0:
  1609                     # Callable Dict is empty.
  1606                     # Callable Dict is empty.
  1610                     # This variable is not needed anymore!
  1607                     # This variable is not needed anymore!
  1611                     IECPathsToPop.append(IECPath)
  1608                     IECPathsToPop.append(IECPath)
  1625             for IECPathToPop in IECPathsToPop:
  1622             for IECPathToPop in IECPathsToPop:
  1626                 self.IECdebug_datas.pop(IECPathToPop)
  1623                 self.IECdebug_datas.pop(IECPathToPop)
  1627 
  1624 
  1628             if Idxs:
  1625             if Idxs:
  1629                 Idxs.sort()
  1626                 Idxs.sort()
  1630                 IdxsT = zip(*Idxs)
  1627                 IdxsT = list(zip(*Idxs))
  1631                 self.TracedIECPath = IdxsT[3]
  1628                 self.TracedIECPath = IdxsT[3]
  1632                 self.TracedIECTypes = IdxsT[1]
  1629                 self.TracedIECTypes = IdxsT[1]
  1633                 res = self._connector.SetTraceVariablesList(zip(*IdxsT[0:3]))
  1630                 res = self._connector.SetTraceVariablesList(list(zip(*IdxsT[0:3])))
  1634                 if res is not None and res > 0:
  1631                 if res is not None and res > 0:
  1635                     self.DebugToken = res
  1632                     self.DebugToken = res
  1636                 else:
  1633                 else:
  1637                     self.DebugToken = None
  1634                     self.DebugToken = None
  1638                     self.logger.write_warning(
  1635                     self.logger.write_warning(
  1693             if len(IECdebug_data[0]) == 0:
  1690             if len(IECdebug_data[0]) == 0:
  1694                 self.IECdebug_datas.pop(IECPath)
  1691                 self.IECdebug_datas.pop(IECPath)
  1695             else:
  1692             else:
  1696                 IECdebug_data[4] = reduce(
  1693                 IECdebug_data[4] = reduce(
  1697                     lambda x, y: x | y,
  1694                     lambda x, y: x | y,
  1698                     IECdebug_data[0].itervalues(),
  1695                     iter(IECdebug_data[0].values()),
  1699                     False)
  1696                     False)
  1700 
  1697 
  1701         self.AppendDebugUpdate()
  1698         self.AppendDebugUpdate()
  1702 
  1699 
  1703     def UnsubscribeAllDebugIECVariable(self):
  1700     def UnsubscribeAllDebugIECVariable(self):
  1730     def CallWeakcallables(self, IECPath, function_name, *cargs):
  1727     def CallWeakcallables(self, IECPath, function_name, *cargs):
  1731         data_tuple = self.IECdebug_datas.get(IECPath, None)
  1728         data_tuple = self.IECdebug_datas.get(IECPath, None)
  1732         if data_tuple is not None:
  1729         if data_tuple is not None:
  1733             WeakCallableDict, _data_log, _status, _fvalue, buffer_list = data_tuple
  1730             WeakCallableDict, _data_log, _status, _fvalue, buffer_list = data_tuple
  1734             # data_log.append((debug_tick, value))
  1731             # data_log.append((debug_tick, value))
  1735             for weakcallable, buffer_list in WeakCallableDict.iteritems():
  1732             for weakcallable, buffer_list in WeakCallableDict.items():
  1736                 function = getattr(weakcallable, function_name, None)
  1733                 function = getattr(weakcallable, function_name, None)
  1737                 if function is not None:
  1734                 if function is not None:
  1738                     # FIXME: apparently, despite of weak ref objects,
  1735                     # FIXME: apparently, despite of weak ref objects,
  1739                     # some dead C/C++ wx object are still reachable from here
  1736                     # some dead C/C++ wx object are still reachable from here
  1740                     # leading to RuntimeError exception
  1737                     # leading to RuntimeError exception