Files
templates/python/set_devices/qt_ports/wavegen.py

107 lines
5.8 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.
"""USB CDC/COM worker for WG v1/v2/v3, with SET v2 block uploads. All waits run in a worker, never the GUI thread."""
import time
from PySide6.QtCore import QObject, QRunnable, Signal, QIODevice
from PySide6.QtSerialPort import QSerialPort
from set_devices.wavegen_protocol import WaveProtocol
class _Signals(QObject):
finished = Signal(object, str)
progress = Signal(int)
class WaveTransfer(QRunnable):
def __init__(self, port_name, address, action, waveform=None, port_factory=None):
super().__init__()
self.port_name, self.address, self.action, self.waveform = port_name, address, action, waveform
self.signals = _Signals()
self.port_factory = port_factory or QSerialPort
def run(self):
port = self.port_factory()
try:
protocol = WaveProtocol(self.address)
port.setPortName(self.port_name)
port.setBaudRate(115200)
port.setDataBits(QSerialPort.Data8)
port.setParity(QSerialPort.NoParity)
port.setStopBits(QSerialPort.OneStop)
port.setFlowControl(QSerialPort.NoFlowControl)
if not port.open(QIODevice.ReadWrite):
raise OSError(port.errorString())
port.clear()
def transfer(request, decode):
if port.write(request) != len(request):
raise OSError(port.errorString())
if port.bytesToWrite() and not port.waitForBytesWritten(1000):
raise OSError("Таймаут передачи USB")
reply = bytearray()
budget = getattr(port, 'response_timeout', lambda ms: ms)(1500)
deadline = time.monotonic() + budget / 1000
while time.monotonic() < deadline:
if port.bytesAvailable() or port.waitForReadyRead(50):
reply.extend(bytes(port.readAll()))
response = decode(request, reply)
if response is not None:
return response
raise OSError("Нет подтверждения USB. Состояние выхода неизвестно; проверьте связь и нажмите Стоп.")
def exchange(operation, index=0, value=0):
return transfer(protocol.request(operation, index, value), protocol.response)
def read_status():
words = exchange(0)
result = protocol.status(words)
if result['version'] >= 2:
result = protocol.status(words, exchange(8)[0])
return result
status = read_status() # Positive device identification before any write.
if self.action == "upload":
wave = self.waveform
if wave is None or len(wave.codes) > status["capacity"]:
raise ValueError("Таблица не помещается в память устройства")
if status['version'] == 1 and wave.sample_rate > 50000:
raise ValueError("Для частоты выше 50 000 отсчётов/с обновите прошивку МК: нужна карта генератора версии 2")
exchange(1)
if status['version'] >= 2:
exchange(9, value=wave.sample_rate >> 16)
exchange(2, value=wave.sample_rate & 0xffff)
exchange(3, value=len(wave.codes))
blocks = status['version'] >= 3 and getattr(port, 'supports_wave_blocks', False)
step = 120 if blocks else 1
for index in range(0, len(wave.codes), step):
values = wave.codes[index:index + step]
if blocks:
transfer(protocol.block_request(index, values), protocol.block_response)
else:
exchange(4, index, values[0])
self.signals.progress.emit(int((index + len(values)) * 50 / len(wave.codes)))
for index in range(0, len(wave.codes), step):
values = wave.codes[index:index + step]
actual = (transfer(protocol.block_request(index, count=len(values)), protocol.block_response)
if blocks else exchange(7, index))
if tuple(actual) != tuple(values):
raise ValueError(f"Проверка таблицы не пройдена: отсчёты с {index}")
self.signals.progress.emit(50 + int((index + len(values)) * 50 / len(wave.codes)))
exchange(5)
elif self.action == "start":
if not status["ready"]:
raise ValueError("Сначала загрузите и проверьте таблицу")
exchange(6)
elif self.action == "stop":
exchange(1)
elif self.action != "status":
raise ValueError("Неизвестное действие")
result = read_status()
if self.action == "upload" and (not result["ready"] or result["running"] or
result["count"] != len(self.waveform.codes) or result["rate"] != self.waveform.sample_rate):
raise ValueError("Устройство не подтвердило загруженную таблицу")
if self.action in ("start", "stop") and result["running"] != (self.action == "start"):
raise ValueError("Устройство не подтвердило состояние выхода")
self.signals.progress.emit(100)
self.signals.finished.emit(result, "")
except Exception as error:
self.signals.finished.emit(None, str(error))
finally:
port.close()