Files
templates/python/altera_logic/qt_port.py

118 lines
4.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Последовательный Qt-порт анализатора Altera. Порт обслуживает соединение, таймеры и события,
# а решения о запросах, ответах и таймаутах принимает автомат C99.
"""Qt serial/lifecycle port. Protocol decisions are exclusively in C99."""
from __future__ import annotations
from set_devices.qt_ports.qt_compat import QObject, QTimer, QElapsedTimer, Signal
from set_devices.qt_ports.qt_compat import QSerialPort, QSerialPortInfo
from .native import NativeAnalyzer
class AnalyzerPort(QObject):
changed = Signal()
completed = Signal(object)
error = Signal(str)
log = Signal(str)
def __init__(self, parent=None):
super().__init__(parent)
self.core = None
self.active = False
self._last_done = False
self.serial = QSerialPort(self)
self.serial.readyRead.connect(self._read)
self.serial.errorOccurred.connect(self._serial_error)
self.timer = QTimer(self)
self.timer.setInterval(10)
self.timer.timeout.connect(self._tick)
self.clock = QElapsedTimer()
@staticmethod
def ports():
return [(p.portName(), p.description()) for p in QSerialPortInfo.availablePorts()]
def open(self, name, demo=False):
self.close()
try:
self.core = NativeAnalyzer()
self.core.reset(demo)
except RuntimeError as exc:
self.error.emit(str(exc))
return
if not demo:
self.serial.setPortName(name)
self.serial.setBaudRate(921600)
self.serial.setDataBits(QSerialPort.DataBits.Data8)
self.serial.setParity(QSerialPort.Parity.NoParity)
self.serial.setStopBits(QSerialPort.StopBits.OneStop)
self.serial.setFlowControl(QSerialPort.FlowControl.NoFlowControl)
if not self.serial.open(QSerialPort.OpenModeFlag.ReadWrite):
self.error.emit(self.serial.errorString())
return
self.active = True
self._last_done = False
self.clock.start()
self.timer.start()
self.log.emit("ДЕМО: синтетические данные, триггер не моделируется" if demo
else "%s · 921600 8N1" % name)
self._pump()
def close(self):
self.active = False
self.timer.stop()
self.serial.close()
self.changed.emit()
def start(self, *settings):
if not self.active or not self.core:
return
try:
self.core.start(*settings)
except ValueError as exc:
self.error.emit(str(exc))
return
self._last_done = False
self._pump()
def _tick(self):
if not self.active:
return
self.core.tick(self.clock.restart())
self._pump()
def _read(self):
data = bytes(self.serial.readAll())
if self.active and data:
self.log.emit("RX " + data.hex(" ").upper())
self.core.feed(data)
self._pump()
def _pump(self):
if not self.active:
return
if self.core.state == NativeAnalyzer.ERROR:
message = self.core.error
self.close()
self.error.emit(message)
return
packet = self.core.next_request()
if packet:
self.log.emit("TX " + packet.hex(" ").upper())
if self.serial.write(packet) != len(packet):
self.core.fail_io()
self._pump()
return
self.clock.restart()
if self.core.state == NativeAnalyzer.DONE and not self._last_done:
self._last_done = True
self.completed.emit(self.core.capture())
self.changed.emit()
def _serial_error(self, code):
if self.active and code != QSerialPort.SerialPortError.NoError:
message = self.serial.errorString()
self.core.fail_io()
self.close()
self.error.emit(message)