ProjectController.py
changeset 1995 691d119ba20f
parent 1953 5736d25bb393
child 1996 4ae9c4447947
equal deleted inserted replaced
1994:1fdc32be71b8 1995:691d119ba20f
   240         self.DebugTicks = []
   240         self.DebugTicks = []
   241         self.SetAppFrame(frame, logger)
   241         self.SetAppFrame(frame, logger)
   242 
   242 
   243         # Setup debug information
   243         # Setup debug information
   244         self.IECdebug_datas = {}
   244         self.IECdebug_datas = {}
   245         self.IECdebug_lock = Lock()
       
   246 
   245 
   247         self.DebugTimer = None
   246         self.DebugTimer = None
   248         self.ResetIECProgramsAndVariables()
   247         self.ResetIECProgramsAndVariables()
   249 
   248 
   250         # In both new or load scenario, no need to save
   249         # In both new or load scenario, no need to save
   256         self.Children = {}
   255         self.Children = {}
   257         self._View = None
   256         self._View = None
   258         # After __init__ root confnode is not valid
   257         # After __init__ root confnode is not valid
   259         self.ProjectPath = None
   258         self.ProjectPath = None
   260         self._setBuildPath(None)
   259         self._setBuildPath(None)
   261         self.DebugThread = None
       
   262         self.debug_break = False
   260         self.debug_break = False
   263         self.previous_plcstate = None
   261         self.previous_plcstate = None
   264         # copy ConfNodeMethods so that it can be later customized
   262         # copy ConfNodeMethods so that it can be later customized
   265         self.StatusMethods = [dic.copy() for dic in self.StatusMethods]
   263         self.StatusMethods = [dic.copy() for dic in self.StatusMethods]
   266 
   264 
  1418 
  1416 
  1419     def PullPLCStatusProc(self, event):
  1417     def PullPLCStatusProc(self, event):
  1420         self.UpdateMethodsFromPLCStatus()
  1418         self.UpdateMethodsFromPLCStatus()
  1421 
  1419 
  1422     def SnapshotAndResetDebugValuesBuffers(self):
  1420     def SnapshotAndResetDebugValuesBuffers(self):
       
  1421         plc_status, Traces = self._connector.GetTraceVariables()
       
  1422         # print [dict.keys() for IECPath, (dict, log, status, fvalue) in self.IECdebug_datas.items()]
       
  1423         if plc_status == "Started":
       
  1424             if len(Traces) > 0:
       
  1425                 for debug_tick, debug_buff in Traces:
       
  1426                     debug_vars = UnpackDebugBuffer(debug_buff, self.TracedIECTypes)
       
  1427                     if debug_vars is not None and len(debug_vars) == len(self.TracedIECPath):
       
  1428                         for IECPath, values_buffer, value in izip(
       
  1429                                 self.TracedIECPath,
       
  1430                                 self.DebugValuesBuffers,
       
  1431                                 debug_vars):
       
  1432                             IECdebug_data = self.IECdebug_datas.get(IECPath, None)
       
  1433                             if IECdebug_data is not None and value is not None:
       
  1434                                 forced = IECdebug_data[2:4] == ["Forced", value]
       
  1435                                 if not IECdebug_data[4] and len(values_buffer) > 0:
       
  1436                                     values_buffer[-1] = (value, forced)
       
  1437                                 else:
       
  1438                                     values_buffer.append((value, forced))
       
  1439                         self.DebugTicks.append(debug_tick)
       
  1440 
       
  1441 
  1423         buffers, self.DebugValuesBuffers = (self.DebugValuesBuffers,
  1442         buffers, self.DebugValuesBuffers = (self.DebugValuesBuffers,
  1424                                             [list() for dummy in xrange(len(self.TracedIECPath))])
  1443                                             [list() for dummy in xrange(len(self.TracedIECPath))])
       
  1444 
  1425         ticks, self.DebugTicks = self.DebugTicks, []
  1445         ticks, self.DebugTicks = self.DebugTicks, []
       
  1446 
  1426         return ticks, buffers
  1447         return ticks, buffers
  1427 
  1448 
  1428     def RegisterDebugVarToConnector(self):
  1449     def RegisterDebugVarToConnector(self):
  1429         self.DebugTimer = None
  1450         self.DebugTimer = None
  1430         Idxs = []
  1451         Idxs = []
  1431         self.TracedIECPath = []
  1452         self.TracedIECPath = []
  1432         self.TracedIECTypes = []
  1453         self.TracedIECTypes = []
  1433         if self._connector is not None:
  1454         if self._connector is not None:
  1434             self.IECdebug_lock.acquire()
       
  1435             IECPathsToPop = []
  1455             IECPathsToPop = []
  1436             for IECPath, data_tuple in self.IECdebug_datas.iteritems():
  1456             for IECPath, data_tuple in self.IECdebug_datas.iteritems():
  1437                 WeakCallableDict, _data_log, _status, fvalue, _buffer_list = data_tuple
  1457                 WeakCallableDict, _data_log, _status, fvalue, _buffer_list = data_tuple
  1438                 if len(WeakCallableDict) == 0:
  1458                 if len(WeakCallableDict) == 0:
  1439                     # Callable Dict is empty.
  1459                     # Callable Dict is empty.
  1460                 self._connector.SetTraceVariablesList(zip(*IdxsT[0:3]))
  1480                 self._connector.SetTraceVariablesList(zip(*IdxsT[0:3]))
  1461             else:
  1481             else:
  1462                 self.TracedIECPath = []
  1482                 self.TracedIECPath = []
  1463                 self._connector.SetTraceVariablesList([])
  1483                 self._connector.SetTraceVariablesList([])
  1464             self.SnapshotAndResetDebugValuesBuffers()
  1484             self.SnapshotAndResetDebugValuesBuffers()
  1465             self.IECdebug_lock.release()
       
  1466 
  1485 
  1467     def IsPLCStarted(self):
  1486     def IsPLCStarted(self):
  1468         return self.previous_plcstate == "Started"
  1487         return self.previous_plcstate == "Started"
  1469 
  1488 
  1470     def ReArmDebugRegisterTimer(self):
  1489     def ReArmDebugRegisterTimer(self):
  1492         weakly referenced callables
  1511         weakly referenced callables
  1493         """
  1512         """
  1494         if IECPath != "__tick__" and IECPath not in self._IECPathToIdx:
  1513         if IECPath != "__tick__" and IECPath not in self._IECPathToIdx:
  1495             return None
  1514             return None
  1496 
  1515 
  1497         self.IECdebug_lock.acquire()
       
  1498         # If no entry exist, create a new one with a fresh WeakKeyDictionary
  1516         # If no entry exist, create a new one with a fresh WeakKeyDictionary
  1499         IECdebug_data = self.IECdebug_datas.get(IECPath, None)
  1517         IECdebug_data = self.IECdebug_datas.get(IECPath, None)
  1500         if IECdebug_data is None:
  1518         if IECdebug_data is None:
  1501             IECdebug_data = [
  1519             IECdebug_data = [
  1502                 WeakKeyDictionary(),  # Callables
  1520                 WeakKeyDictionary(),  # Callables
  1508         else:
  1526         else:
  1509             IECdebug_data[4] |= buffer_list
  1527             IECdebug_data[4] |= buffer_list
  1510 
  1528 
  1511         IECdebug_data[0][callableobj] = buffer_list
  1529         IECdebug_data[0][callableobj] = buffer_list
  1512 
  1530 
  1513         self.IECdebug_lock.release()
       
  1514 
       
  1515         self.ReArmDebugRegisterTimer()
  1531         self.ReArmDebugRegisterTimer()
  1516 
  1532 
  1517         return IECdebug_data[1]
  1533         return IECdebug_data[1]
  1518 
  1534 
  1519     def UnsubscribeDebugIECVariable(self, IECPath, callableobj):
  1535     def UnsubscribeDebugIECVariable(self, IECPath, callableobj):
  1520         self.IECdebug_lock.acquire()
       
  1521         IECdebug_data = self.IECdebug_datas.get(IECPath, None)
  1536         IECdebug_data = self.IECdebug_datas.get(IECPath, None)
  1522         if IECdebug_data is not None:
  1537         if IECdebug_data is not None:
  1523             IECdebug_data[0].pop(callableobj, None)
  1538             IECdebug_data[0].pop(callableobj, None)
  1524             if len(IECdebug_data[0]) == 0:
  1539             if len(IECdebug_data[0]) == 0:
  1525                 self.IECdebug_datas.pop(IECPath)
  1540                 self.IECdebug_datas.pop(IECPath)
  1526             else:
  1541             else:
  1527                 IECdebug_data[4] = reduce(
  1542                 IECdebug_data[4] = reduce(
  1528                     lambda x, y: x | y,
  1543                     lambda x, y: x | y,
  1529                     IECdebug_data[0].itervalues(),
  1544                     IECdebug_data[0].itervalues(),
  1530                     False)
  1545                     False)
  1531         self.IECdebug_lock.release()
       
  1532 
  1546 
  1533         self.ReArmDebugRegisterTimer()
  1547         self.ReArmDebugRegisterTimer()
  1534 
  1548 
  1535     def UnsubscribeAllDebugIECVariable(self):
  1549     def UnsubscribeAllDebugIECVariable(self):
  1536         self.IECdebug_lock.acquire()
       
  1537         self.IECdebug_datas = {}
  1550         self.IECdebug_datas = {}
  1538         self.IECdebug_lock.release()
       
  1539 
  1551 
  1540         self.ReArmDebugRegisterTimer()
  1552         self.ReArmDebugRegisterTimer()
  1541 
  1553 
  1542     def ForceDebugIECVariable(self, IECPath, fvalue):
  1554     def ForceDebugIECVariable(self, IECPath, fvalue):
  1543         if IECPath not in self.IECdebug_datas:
  1555         if IECPath not in self.IECdebug_datas:
  1544             return
  1556             return
  1545 
  1557 
  1546         self.IECdebug_lock.acquire()
       
  1547 
  1558 
  1548         # If no entry exist, create a new one with a fresh WeakKeyDictionary
  1559         # If no entry exist, create a new one with a fresh WeakKeyDictionary
  1549         IECdebug_data = self.IECdebug_datas.get(IECPath, None)
  1560         IECdebug_data = self.IECdebug_datas.get(IECPath, None)
  1550         IECdebug_data[2] = "Forced"
  1561         IECdebug_data[2] = "Forced"
  1551         IECdebug_data[3] = fvalue
  1562         IECdebug_data[3] = fvalue
  1552 
  1563 
  1553         self.IECdebug_lock.release()
       
  1554 
  1564 
  1555         self.ReArmDebugRegisterTimer()
  1565         self.ReArmDebugRegisterTimer()
  1556 
  1566 
  1557     def ReleaseDebugIECVariable(self, IECPath):
  1567     def ReleaseDebugIECVariable(self, IECPath):
  1558         if IECPath not in self.IECdebug_datas:
  1568         if IECPath not in self.IECdebug_datas:
  1559             return
  1569             return
  1560 
  1570 
  1561         self.IECdebug_lock.acquire()
       
  1562 
  1571 
  1563         # If no entry exist, create a new one with a fresh WeakKeyDictionary
  1572         # If no entry exist, create a new one with a fresh WeakKeyDictionary
  1564         IECdebug_data = self.IECdebug_datas.get(IECPath, None)
  1573         IECdebug_data = self.IECdebug_datas.get(IECPath, None)
  1565         IECdebug_data[2] = "Registered"
  1574         IECdebug_data[2] = "Registered"
  1566         IECdebug_data[3] = None
  1575         IECdebug_data[3] = None
  1567 
  1576 
  1568         self.IECdebug_lock.release()
       
  1569 
  1577 
  1570         self.ReArmDebugRegisterTimer()
  1578         self.ReArmDebugRegisterTimer()
  1571 
  1579 
  1572     def CallWeakcallables(self, IECPath, function_name, *cargs):
  1580     def CallWeakcallables(self, IECPath, function_name, *cargs):
  1573         data_tuple = self.IECdebug_datas.get(IECPath, None)
  1581         data_tuple = self.IECdebug_datas.get(IECPath, None)
  1588     def RemoteExec(self, script, **kwargs):
  1596     def RemoteExec(self, script, **kwargs):
  1589         if self._connector is None:
  1597         if self._connector is None:
  1590             return -1, "No runtime connected!"
  1598             return -1, "No runtime connected!"
  1591         return self._connector.RemoteExec(script, **kwargs)
  1599         return self._connector.RemoteExec(script, **kwargs)
  1592 
  1600 
  1593     def DebugThreadProc(self):
       
  1594         """
       
  1595         This thread waid PLC debug data, and dispatch them to subscribers
       
  1596         """
       
  1597         self.debug_break = False
       
  1598         debug_getvar_retry = 0
       
  1599         while (not self.debug_break) and (self._connector is not None):
       
  1600             plc_status, Traces = self._connector.GetTraceVariables()
       
  1601             debug_getvar_retry += 1
       
  1602             # print [dict.keys() for IECPath, (dict, log, status, fvalue) in self.IECdebug_datas.items()]
       
  1603             if plc_status == "Started":
       
  1604                 if len(Traces) > 0:
       
  1605                     self.IECdebug_lock.acquire()
       
  1606                     for debug_tick, debug_buff in Traces:
       
  1607                         debug_vars = UnpackDebugBuffer(debug_buff, self.TracedIECTypes)
       
  1608                         if debug_vars is not None and len(debug_vars) == len(self.TracedIECPath):
       
  1609                             for IECPath, values_buffer, value in izip(
       
  1610                                     self.TracedIECPath,
       
  1611                                     self.DebugValuesBuffers,
       
  1612                                     debug_vars):
       
  1613                                 IECdebug_data = self.IECdebug_datas.get(IECPath, None)  # FIXME get
       
  1614                                 if IECdebug_data is not None and value is not None:
       
  1615                                     forced = IECdebug_data[2:4] == ["Forced", value]
       
  1616                                     if not IECdebug_data[4] and len(values_buffer) > 0:
       
  1617                                         values_buffer[-1] = (value, forced)
       
  1618                                     else:
       
  1619                                         values_buffer.append((value, forced))
       
  1620                             self.DebugTicks.append(debug_tick)
       
  1621                             debug_getvar_retry = 0
       
  1622                     self.IECdebug_lock.release()
       
  1623 
       
  1624                 if debug_getvar_retry != 0:
       
  1625                     # Be patient, tollerate PLC to come with fresh samples
       
  1626                     time.sleep(0.1)
       
  1627             else:
       
  1628                 self.debug_break = True
       
  1629         self.logger.write(_("Debugger disabled\n"))
       
  1630         self.DebugThread = None
       
  1631         if self.DispatchDebugValuesTimer is not None:
       
  1632             self.DispatchDebugValuesTimer.Stop()
       
  1633 
  1601 
  1634     def DispatchDebugValuesProc(self, event):
  1602     def DispatchDebugValuesProc(self, event):
  1635         self.IECdebug_lock.acquire()
       
  1636         debug_ticks, buffers = self.SnapshotAndResetDebugValuesBuffers()
  1603         debug_ticks, buffers = self.SnapshotAndResetDebugValuesBuffers()
  1637         self.IECdebug_lock.release()
       
  1638         start_time = time.time()
  1604         start_time = time.time()
  1639         if len(self.TracedIECPath) == len(buffers):
  1605         if len(self.TracedIECPath) == len(buffers):
  1640             for IECPath, values in izip(self.TracedIECPath, buffers):
  1606             for IECPath, values in izip(self.TracedIECPath, buffers):
  1641                 if len(values) > 0:
  1607                 if len(values) > 0:
  1642                     self.CallWeakcallables(IECPath, "NewValues", debug_ticks, values)
  1608                     self.CallWeakcallables(IECPath, "NewValues", debug_ticks, values)
  1643             if len(debug_ticks) > 0:
  1609             if len(debug_ticks) > 0:
  1644                 self.CallWeakcallables("__tick__", "NewDataAvailable", debug_ticks)
  1610                 self.CallWeakcallables("__tick__", "NewDataAvailable", debug_ticks)
  1645 
  1611 
  1646         delay = time.time() - start_time
  1612         delay = time.time() - start_time
  1647         next_refresh = max(REFRESH_PERIOD - delay, 0.2 * delay)
  1613         next_refresh = max(REFRESH_PERIOD - delay, 0.2 * delay)
  1648         if self.DispatchDebugValuesTimer is not None and self.DebugThread is not None:
  1614         if self.DispatchDebugValuesTimer is not None:
  1649             self.DispatchDebugValuesTimer.Start(
  1615             self.DispatchDebugValuesTimer.Start(
  1650                 int(next_refresh * 1000), oneShot=True)
  1616                 int(next_refresh * 1000), oneShot=True)
  1651         event.Skip()
  1617         event.Skip()
  1652 
  1618 
  1653     def KillDebugThread(self):
  1619     def KillDebugThread(self):
  1654         tmp_debugthread = self.DebugThread
       
  1655         self.debug_break = True
       
  1656         if tmp_debugthread is not None:
       
  1657             self.logger.writeyield(_("Stopping debugger...\n"))
       
  1658             tmp_debugthread.join(timeout=5)
       
  1659             if tmp_debugthread.isAlive() and self.logger:
       
  1660                 self.logger.write_warning(_("Couldn't stop debugger.\n"))
       
  1661             else:
       
  1662                 self.logger.write(_("Debugger stopped.\n"))
       
  1663         self.DebugThread = None
       
  1664         if self.DispatchDebugValuesTimer is not None:
  1620         if self.DispatchDebugValuesTimer is not None:
  1665             self.DispatchDebugValuesTimer.Stop()
  1621             self.DispatchDebugValuesTimer.Stop()
  1666 
  1622 
  1667     def _connect_debug(self):
  1623     def _connect_debug(self):
  1668         self.previous_plcstate = None
  1624         self.previous_plcstate = None
  1670             self.AppFrame.ResetGraphicViewers()
  1626             self.AppFrame.ResetGraphicViewers()
  1671         self.RegisterDebugVarToConnector()
  1627         self.RegisterDebugVarToConnector()
  1672         if self.DispatchDebugValuesTimer is not None:
  1628         if self.DispatchDebugValuesTimer is not None:
  1673             self.DispatchDebugValuesTimer.Start(
  1629             self.DispatchDebugValuesTimer.Start(
  1674                 int(REFRESH_PERIOD * 1000), oneShot=True)
  1630                 int(REFRESH_PERIOD * 1000), oneShot=True)
  1675         if self.DebugThread is None:
       
  1676             self.DebugThread = Thread(target=self.DebugThreadProc)
       
  1677             self.DebugThread.start()
       
  1678 
  1631 
  1679     def _Run(self):
  1632     def _Run(self):
  1680         """
  1633         """
  1681         Start PLC
  1634         Start PLC
  1682         """
  1635         """