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. |
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 |