Files
templates/python/set_devices/deif_controls.py
T
Andrey 41e24629ce Расширить DEIF, загрузку CAN и общую обработку сигналов
Добавить общее ядро DEIF, эмуляцию приборов и переносимые панели Python/Qt.
Расширить загрузчики F2812 и F28335, обновление Flash и профиль STM Invertor.
Добавить альтернативный МНК Eigen, модели неисправностей и диагностику сигналов.
Обновить справочники устройств, проекты CCS и регрессионные проверки.
2026-10-24 15:40:51 +03:00

53 lines
8.0 KiB
Python

"""Готовые операции DEIF для GUI без знания wire-разметки и адресных масок.""" # Все числовые правила реализованы единственным C99-ядром templates.
import ctypes as C # Преобразование фиксированных ABI-структур не является вторым кодеком.
from dataclasses import dataclass # Именованные поля исключают индексы метаданных в GUI.
from .deif_native import get_deif_native, Frame # Общий декодер и builders используются независимо от приложения.
from .can_transport import build_frame # Транспорт получает уже готовые CAN-кадры.
@dataclass(frozen=True) # Неизменяемые описания безопасно используются диагностикой и редакторами.
class SelectorInfo: # Это скалярный результат C, а не wire-структура.
node: int; index: int; subindex: int; dam: bool; legacy_key: str # Последний элемент сохраняет только формат прежних ключей настроек Desktop.
@dataclass(frozen=True) # Описание входного кадра отделено от его транспортного контейнера.
class PacketInfo: # GUI не обращается к смещениям payload.
kind: int; node: int; index: int; subindex: int; raw: int; status: int; dam: bool # Все значения получены из C-декодера.
@property # Диагностический ключ независим от адресного байта SAM/DAM.
def object_key(self): # Для TX-эхо достаточно индекса и подиндекса готового объекта.
return self.index, self.subindex # Это идентичность объекта, а не повторная распаковка CAN-data.
def selector_info(selector): # Редактор получает имена полей вместо ручных масок.
raw = bytes.fromhex(selector) if isinstance(selector, str) else bytes(selector) # HEX — только формат хранения пользовательской настройки.
if len(raw) != 4: return None # Буфер неправильного размера не передаётся C.
metadata = (C.c_int32 * 4)() # Node, index, subindex и DAM определены публичным ABI.
if not get_deif_native().selector_info(raw, metadata): return None # Некорректная привязка не становится источником на рисунке.
return SelectorInfo(metadata[0], metadata[1], metadata[2], bool(metadata[3]), raw[1:].hex()) # Срез используется только для совместимости непрозрачного старого ключа настроек.
def readdress_selector(selector, node, dam=None): # Меняет адрес пользовательской привязки общим алгоритмом C.
if not selector: return "" # Явно отключённое поле остаётся отключённым.
raw = bytes.fromhex(selector) if isinstance(selector, str) else bytes(selector) # Порт преобразует текст настройки в буфер ABI.
output = (C.c_uint8 * 4)() # Готовый селектор создаёт C-код.
if len(raw) != 4 or not get_deif_native().readdress(raw, node, 2 if dam is None else int(bool(dam)), output): raise ValueError("Неверный селектор или Node-ID DEIF") # Индекс не пересобирается в Python.
return bytes(output).hex(" ").upper() # Формат вывода совместим с прежним редактором HEX.
def route_parameters(node, mode, identifier, operation=0): # Согласует параметры редактора с C-правилами адресации.
output = (C.c_uint32 * 3)() # COB-ID, Node и адресный байт возвращаются одним вызовом.
if not get_deif_native().route(node, mode == "dam", identifier, operation, output): return None # Неверный диапазон не вызывает произвольную перенастройку привязок.
return tuple(output) # GUI хранит и отображает готовые значения.
def data_node(identifier, fallback=1): # Получает узел из CAN ID без повторения маски в GUI.
result = route_parameters(fallback or 1, "sam", identifier, 2) # Legacy SAM сохраняет явно выбранный источник.
return result[1] if result else fallback # Вне диапазона данных остаётся пользовательское исходное значение.
def packet_info(frame): # Метаданные для подтверждения команд и TX-эхо.
code, metadata = get_deif_native().inspect_frame(frame.can_id, frame.data, frame.ide, frame.rtr) # Wire-разбор находится в C.
return PacketInfo(metadata[0], metadata[1], metadata[2], metadata[3], metadata[4], metadata[7], bool(metadata[8])) if code > 0 else None # Некорректный кадр не получает выдуманных полей.
def heartbeat_description(identifier, data, extended=False, rtr=False): # Приложение не содержит собственного классификатора CANopen error control.
code, _ = get_deif_native().inspect_frame(identifier, data, extended, rtr) # Проверку COB-ID, DLC и состояния выполняет C.
if code not in (2, -3): return None # Обычные MPDO не попадают в поле heartbeat.
from .deif_xdi import decode # Общий локализованный formatter используется обоими CAN-мониторами и прибором.
return decode(build_frame(identifier, bytes(data), ide=extended, rtr=rtr)).summary # Готовая подпись не подтверждает получение конкретного измерения.
def _frame(output): # Общий адаптер переводит структуру C в существующий транспортный контейнер.
return build_frame(output.can_id, bytes(output.data[:output.dlc]), ide=False) # Идентификатор, длина и данные уже вычислены ядром.
def service_frame(node, value, nmt=False): # Строит heartbeat либо локальную NMT-команду через C.
output = Frame() # Память результата принадлежит Python-порту.
if not get_deif_native().service(bool(nmt), node, value, C.byref(output)): raise ValueError("Неверный Node-ID или CANopen-сервис") # Ни COB-ID, ни служебные байты не собираются в GUI.
return _frame(output) # Физическую отправку выполняет выбранный приложением транспорт.
def angle_setpoint_frame(actual): # Формирует отдельный кадр задания с тем же значением фактического азимута.
source, output = Frame(), Frame() # Оба контейнера имеют стабильный layout ABI.
source.can_id, source.dlc, source.data[:] = actual.can_id, len(actual.data), bytes(actual.data) # Это копирование готового CAN-кадра, не декодирование его полей.
if not get_deif_native().angle_command(C.byref(source), C.byref(output)): raise ValueError("Кадр не содержит поддерживаемый азимут DEIF") # Проверку семейства и сборку 0x07 выполняет C.
return _frame(output) # Штатный передатчик получает второй независимый MPDO.