Расширить DEIF и генератор сигналов, подключить исходники KDiff3
Добавить общую модель сигналов XY и адаптировать генератор к двум каналам. Расширить Android-порт DEIF общим контроллером рабочей области и проверками. Подключить официальный репозиторий KDiff3 вложенным подмодулем.
This commit is contained in:
@@ -57,7 +57,14 @@ class WaveTransfer(QRunnable):
|
||||
result = protocol.status(words)
|
||||
if result['version'] >= 2:
|
||||
result = protocol.status(words, exchange(8)[0])
|
||||
return result
|
||||
try: # Дополнительные регистры объявляют XY независимо от версии прежнего восьмисловного статуса.
|
||||
channels,selected,maximum,other=exchange(12) # Четыре слова 0x1309…0x130C читаются общим C-кодеком.
|
||||
result.update(channels=channels,selected=selected,max_channels=maximum,received_other=other) # Сохраняет фактические возможности порта и состояние обеих таблиц.
|
||||
except ValueError as error: # Старые WG v1/v2/v3 отвечают исключением адреса либо имеют прежний native-кодек.
|
||||
if "(-102)" not in str(error) and "Недопустимая команда" not in str(error): # Ошибки CRC и структуры ответа нельзя скрывать как одноканальную плату.
|
||||
raise # Сохраняет штатный отказ передачи при повреждённом ответе.
|
||||
result.update(channels=1,max_channels=1) # Старый клиент и прошивка сохраняют одноканальную работу без новых записей.
|
||||
return result # Возможности XY проверяются до stop и изменения таблиц устройства.
|
||||
|
||||
status = read_status() # Positive device identification before any write.
|
||||
if self.action == "upload":
|
||||
@@ -66,27 +73,40 @@ class WaveTransfer(QRunnable):
|
||||
raise ValueError("Таблица не помещается в память устройства")
|
||||
if status['version'] == 1 and wave.sample_rate > 50000:
|
||||
raise ValueError("Для частоты выше 50 000 отсчётов/с обновите прошивку МК: нужна карта генератора версии 2")
|
||||
channel_codes=(wave.codes,) if not hasattr(wave,"codes_y") else (wave.codes,wave.codes_y) # Одна временная сетка содержит один канал либо обе координаты XY.
|
||||
if len(channel_codes)>status["max_channels"]: # Устройство обязано явно подтвердить аппаратный порт второго канала.
|
||||
raise ValueError("Для XY нужны прошивка F407/HOPE и native-кодек templates с поддержкой двух каналов") # Отказ происходит до остановки ранее работающего выхода.
|
||||
if any(len(codes)!=len(wave.codes) for codes in channel_codes): # Нельзя загружать пару с разными длинами даже из вручную созданного задания.
|
||||
raise ValueError("X и Y должны иметь одинаковую длину") # Не меняет оборудование при несовместимой временной сетке.
|
||||
exchange(1)
|
||||
if status["max_channels"]>=2: # Новый порт явно сбрасывает формат перед каждой загрузкой, включая возврат XY→mono.
|
||||
exchange(10,value=len(channel_codes)) # Выбирает число одновременно воспроизводимых каналов и инвалидирует обе прежние таблицы.
|
||||
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)))
|
||||
total=len(wave.codes)*len(channel_codes)*2 # Прогресс учитывает запись и чтение каждого кода обеих координат.
|
||||
completed=0 # Общий счётчик исключает откат процентов при переходе от X к Y.
|
||||
for channel,codes in enumerate(channel_codes): # Загружает и проверяет X, затем Y без промежуточного пуска.
|
||||
if status["max_channels"]>=2: # Прежняя прошивка не получает неподдерживаемый селектор окна.
|
||||
exchange(11,value=channel) # Одинаковые block/sample команды адресуют выбранную координату через общий регистр 0x130A.
|
||||
for reading in (False,True): # Обратное чтение всей координаты обязательно до общего commit пары.
|
||||
for index in range(0,len(codes),step): # Блочный транспорт ограничен прежними 120 кодами на запрос.
|
||||
values=codes[index:index+step] # Последний блок содержит только действительные отсчёты без дополнения.
|
||||
if reading: # Проверка использует ту же границу блока и тот же селектор, что запись.
|
||||
actual=transfer(protocol.block_request(index,count=len(values)),protocol.block_response) if blocks else exchange(7,index) # Читает реальные коды из памяти устройства.
|
||||
if tuple(actual)!=tuple(values): # Любое расхождение запрещает общий commit и дальнейший пуск.
|
||||
raise ValueError(f"Проверка {'XY'[channel]} не пройдена: отсчёты с {index}") # Показывает ошибочную координату и начало блока.
|
||||
elif blocks: # SET v2 переносит тот же атомарно проверяемый RTU-блок из общего ядра templates.
|
||||
transfer(protocol.block_request(index,values),protocol.block_response) # Подтверждает запись всего блока до следующего запроса.
|
||||
else: # Старый UART/RTU клиент сохраняет поотсчётную загрузку без смены wire-контракта.
|
||||
exchange(4,index,values[0]) # Записывает очередной код выбранной координаты.
|
||||
completed+=len(values) # Каждый подтверждённый код учитывается ровно один раз на фазу.
|
||||
self.signals.progress.emit(int(completed*100/total)) # Общий прогресс монотонно достигает 100 % после проверки обеих таблиц.
|
||||
if status["max_channels"]>=2: # Итоговый статус возвращается к X для одинакового отображения mono и XY.
|
||||
exchange(11,value=0) # Не меняет содержимое пар и не запускает аппаратный вывод.
|
||||
exchange(5)
|
||||
elif self.action == "start":
|
||||
if not status["ready"]:
|
||||
@@ -98,6 +118,7 @@ class WaveTransfer(QRunnable):
|
||||
raise ValueError("Неизвестное действие")
|
||||
result = read_status()
|
||||
if self.action == "upload" and (not result["ready"] or result["running"] or
|
||||
result.get("channels",1)!=(2 if hasattr(self.waveform,"codes_y") else 1) or # Итоговое число каналов обязано совпасть с подготовленным mono/XY заданием.
|
||||
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"):
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
from dataclasses import dataclass, fields # Неизменяемая таблица наследует прежнюю модель, сохраняя сравнение обеих координат перед пуском.
|
||||
from .waveform import Waveform # Общие частота, точки X, Vref и период принадлежат прежней модели генератора.
|
||||
from .signal_reconstruction import dac12 # Напряжения Y квантует то же C-ядро, что используется одиночным выходом X.
|
||||
@dataclass(frozen=True) # Изменение любого кода Y создаёт другое задание и требует повторной загрузки перед start.
|
||||
class XYWaveform(Waveform): # Дополняет один общий период второй синхронной координатой без дублирования настройки таймера.
|
||||
codes_y: tuple # Ровно один 12-битный код Y соответствует каждому коду X с тем же индексом и временем.
|
||||
def with_y(wave, volts): # Добавляет вертикальное отклонение к уже построенной и проверенной временной сетке X.
|
||||
values=tuple(volts) # Однократно фиксирует последовательность, включая генераторы Python.
|
||||
if len(values)!=len(wave.codes): # Оба DMA-канала должны содержать строго одинаковое число пар, без дополнения и обрезки.
|
||||
raise ValueError("X и Y должны иметь одинаковое число отсчётов") # Ошибка выявляется до открытия порта и изменения состояния устройства.
|
||||
codes=dac12(values,wave.vref) # Общая проверка отвергает NaN, бесконечность и выход Y за диапазон 0…Vref.
|
||||
return XYWaveform(**{field.name:getattr(wave,field.name) for field in fields(Waveform)},codes_y=codes) # Сохраняет точные коды X и добавляет Y без интерполяции и изменения частоты.
|
||||
Reference in New Issue
Block a user