Добавить общее ядро DEIF, эмуляцию приборов и переносимые панели Python/Qt. Расширить загрузчики F2812 и F28335, обновление Flash и профиль STM Invertor. Добавить альтернативный МНК Eigen, модели неисправностей и диагностику сигналов. Обновить справочники устройств, проекты CCS и регрессионные проверки.
76 lines
11 KiB
Python
76 lines
11 KiB
Python
"""Тонкий ctypes-порт единственного C99-ядра DEIF из templates/c/set-protocol.""" # В Python нет второго кодека или автомата NMT.
|
|
import ctypes as C # Фиксированные типы повторяют только публичный ABI.
|
|
import os # Путь дополнительной библиотеки передаёт приложение, не общая библиотека.
|
|
from pathlib import Path # Дополнительный нативный компонент может лежать рядом с основной библиотекой любого приложения.
|
|
from protocan.native import _load_library # Стандартный механизм загрузки используется при отсутствии явного пути DEIF.
|
|
|
|
|
|
class Frame(C.Structure): # Структура содержит готовые STD-кадры, а не wire-структуру транспорта.
|
|
_fields_ = [("can_id", C.c_uint32), ("dlc", C.c_uint32), ("data", C.c_uint8 * 8)] # Layout размером 16 байт совпадает с deif_xdi.h.
|
|
|
|
|
|
class NativeDeif: # Экземпляр владеет только сигнатурами C, состояние выделяется отдельными моделями.
|
|
def __init__(self): # Отсутствие общего ядра является ошибкой сборки, алгоритмического fallback нет.
|
|
self.lib = C.CDLL(os.environ["SETPROTOCOL_DEIF_LIBRARY"]) if os.environ.get("SETPROTOCOL_DEIF_LIBRARY") else _load_library() # Выбор пути относится к загрузке, не к протоколу.
|
|
if not hasattr(self.lib, "setp_deif_version"): # Во время обновления основная DLL может оставаться занятой работающим приложением.
|
|
primary = Path(self.lib._name) # Путь сообщает стандартный загрузчик, структура gui_desktop здесь неизвестна.
|
|
self.lib = C.CDLL(str(primary.with_name(primary.stem + "_deif" + primary.suffix))) # Это дополнительная сборка того же C-ядра, а не алгоритмический Python fallback.
|
|
signatures = { # Сигнатуры скалярного ABI не зависят от внутренних C-структур.
|
|
"version": ([], C.c_int), "state_size": ([], C.c_size_t), # Проверка версии и caller-owned памяти.
|
|
"catalog": ([C.c_uint, C.POINTER(C.c_int32)], C.c_int), # Каталог числовых индексов и разрешений.
|
|
"selector": ([C.c_uint, C.c_uint, C.c_uint, C.c_uint, C.c_void_p], C.c_int), # C формирует готовый селектор.
|
|
"inspect": ([C.c_uint32, C.c_void_p, C.c_size_t, C.c_uint, C.POINTER(C.c_int32)], C.c_int), # Единственный разбор входящего wire-кадра.
|
|
"make": ([C.c_uint, C.c_uint, C.c_uint, C.c_int32, C.c_uint32, C.c_uint, C.POINTER(Frame)], C.c_int), # Единственная сборка MPDO.
|
|
"master": ([C.c_uint, C.POINTER(C.c_int32), C.c_uint32, C.c_uint, C.c_uint, C.POINTER(Frame)], C.c_int), # Единственный порядок пяти объектов цикла.
|
|
"service": ([C.c_uint, C.c_uint, C.c_uint, C.POINTER(Frame)], C.c_int), "angle_command": ([C.POINTER(Frame), C.POINTER(Frame)], C.c_int), # Служебные кадры и задание азимута собираются общим C-кодом.
|
|
"selector_info": ([C.c_void_p, C.POINTER(C.c_int32)], C.c_int), "route": ([C.c_uint, C.c_uint, C.c_uint32, C.c_uint, C.POINTER(C.c_uint32)], C.c_int), # Редакторы не разбирают адресный байт или COB-ID самостоятельно.
|
|
"readdress": ([C.c_void_p, C.c_uint, C.c_uint, C.c_void_p], C.c_int), # Перенос селектора сохраняет ручной объект без масок и endian в UI.
|
|
"validate": ([C.c_uint32, C.c_void_p, C.c_size_t, C.c_uint, C.c_uint], C.c_int), # Изолированные выходы MASTER и SLAVE.
|
|
"init": ([C.c_void_p, C.c_size_t] + [C.c_uint] * 7 + [C.c_uint32], C.c_int), # Семь параметров профиля и отдельный CAN ID наблюдателя.
|
|
"bind": ([C.c_void_p, C.c_uint, C.c_void_p, C.c_double], C.c_int), # Селектор и библиотечный масштаб передаются без интерпретации.
|
|
"get_binding": ([C.c_void_p, C.c_uint, C.c_void_p, C.POINTER(C.c_double)], C.c_int), # Исходные значения профиля приходят из единственного C-каталога.
|
|
"default_angle": ([C.c_void_p, C.c_void_p, C.POINTER(C.c_double)], C.c_int), # Общая миграция отсутствующей привязки.
|
|
"start": ([C.c_void_p, C.c_uint64, C.c_uint], C.c_int), "stop": ([C.c_void_p], None), "reset_values": ([C.c_void_p], None), # Жизненный цикл без системных часов C.
|
|
"accept": ([C.c_void_p, C.c_uint32, C.c_void_p, C.c_size_t, C.c_uint, C.c_uint64], C.c_int), # C проверяет NMT, адресацию, объекты и длину.
|
|
"poll": ([C.c_void_p, C.c_uint64, C.POINTER(Frame), C.c_size_t], C.c_size_t), # Порт владеет выходным буфером событий.
|
|
"read": ([C.c_void_p, C.c_uint, C.c_uint64, C.c_uint, C.POINTER(C.c_double), C.POINTER(C.c_int64)], C.c_int), # Готовое значение и временные метаданные индикатора.
|
|
"lost": ([C.c_void_p, C.c_uint64], C.c_uint), # Маска устаревших входов вычисляется в C.
|
|
"angle": ([C.c_void_p, C.c_uint64, C.c_uint, C.POINTER(C.c_double)], C.c_int), "meta": ([C.c_void_p, C.POINTER(C.c_int64)], C.c_int), # Единый выбор азимута и снимок состояния.
|
|
} # Эти объявления описывают ABI, а не копию алгоритма.
|
|
for name, (arguments, result) in signatures.items(): # Все отсутствующие символы выявляются при загрузке расширения.
|
|
function = getattr(self.lib, "setp_deif_" + name) # Названия совпадают с публичным заголовком templates.
|
|
function.argtypes, function.restype = arguments, result # ctypes не должен угадывать размеры указателей и целых.
|
|
setattr(self, name, function) # Короткие имена оставляют порты моделей читаемыми.
|
|
if self.version() != 1: # Несовместимый ABI не используется с предположением о layout.
|
|
raise RuntimeError("Нужна общая библиотека DEIF ABI 1") # Сообщение указывает на необходимость пересборки нативного ядра.
|
|
|
|
def selector_bytes(self, field, node, instance=1, dam=False): # Возвращает готовый C-селектор для настроек UI.
|
|
output = (C.c_uint8 * 4)() # Размер мультиплексора задан публичным контрактом.
|
|
if not self.selector(field, node, instance, bool(dam), output): # Проверка диапазонов находится в C.
|
|
raise ValueError("DEIF: неверный Node-ID, объект или экземпляр") # Недопустимая привязка не сохраняется в настройках.
|
|
return bytes(output) # Порт преобразует только тип контейнера.
|
|
|
|
def inspect_frame(self, identifier, data, extended=False, rtr=False): # Передаёт целый CAN-кадр общему декодеру.
|
|
if not 0 <= identifier <= 0x1FFFFFFF or len(data) > 8: # Проверяет представимость на границе ABI до сужения Python-чисел.
|
|
return -1, [0] * 12 # Переполнение нельзя превратить в другой допустимый кадр.
|
|
output = (C.c_int32 * 12)() # Индексы метаданных определены в контракте C-декодера.
|
|
code = self.inspect(identifier, bytes(data), len(data), int(bool(extended)) | (int(bool(rtr)) << 1), output) # Флаги относятся к типу CAN-кадра, не к содержимому протокола.
|
|
return code, list(output) # Локализованный текст формируется поверх готовых полей C.
|
|
|
|
def make_frame(self, field, node, value, identifier, mode="sam", instance=1): # Возвращает кадр существующего транспортного API.
|
|
from .can_transport import build_frame # Пакет транспорта не импортируется до фактической сборки кадра.
|
|
if mode not in ("sam", "dam") or type(instance) is not int or not 0 <= instance <= 4294967295 or type(value) is not int or not -2147483648 <= value <= 2147483647 or type(node) is not int or not 0 <= node <= 127 or type(identifier) is not int or not 0 <= identifier <= 0x1FFFFFFF: # Порт проверяет только типы и представимость ABI.
|
|
raise ValueError("DEIF: неверный Node-ID, режим, CAN ID или значение") # Значения не усекаются до вызова C.
|
|
output = Frame() # Память выходного CAN-кадра принадлежит Python.
|
|
if not self.make(field, node, instance, value, identifier, mode == "dam", C.byref(output)): # Wire-байты и границы протокола определяются исключительно C.
|
|
raise ValueError("DEIF: Node-ID, RPDO, экземпляр или значение вне диапазона") # Причина отклонения остаётся видимой в интерфейсе.
|
|
return build_frame(output.can_id, bytes(output.data[:output.dlc]), ide=False) # Транспорт AA55/адаптер получает уже готовые данные STD.
|
|
|
|
|
|
_native = None # Общая библиотека загружается один раз на процесс.
|
|
def get_deif_native(): # Ленивое получение не требует Qt и пригодно для CLI.
|
|
global _native # Экземпляр хранит сигнатуры, состояния приборов остаются раздельными.
|
|
if _native is None: # Первая реальная операция DEIF проверяет наличие нового нативного ядра.
|
|
_native = NativeDeif() # Отсутствие DLL или ABI не скрывается Python-реализацией протокола.
|
|
return _native # Все модели используют один и тот же проверенный C-код.
|