Add shared waveform processing, generation and firmware image support
This commit is contained in:
106
python/set_devices/qt_ports/wavegen.py
Normal file
106
python/set_devices/qt_ports/wavegen.py
Normal file
@@ -0,0 +1,106 @@
|
||||
"""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()
|
||||
Reference in New Issue
Block a user