Добавить общее ядро DEIF, эмуляцию приборов и переносимые панели Python/Qt. Расширить загрузчики F2812 и F28335, обновление Flash и профиль STM Invertor. Добавить альтернативный МНК Eigen, модели неисправностей и диагностику сигналов. Обновить справочники устройств, проекты CCS и регрессионные проверки.
29 lines
5.0 KiB
Python
29 lines
5.0 KiB
Python
import ctypes # Привязка передаёт готовые слова общему C-кодеку без повторения wire-формата на Python.
|
|
from .native import _load_library # Стандартный поиск сохраняет существующий механизм доставки SETProtocol.
|
|
class StmInvertorCodec: # Один экземпляр владеет только сигнатурами функций общей библиотеки.
|
|
def __init__(self, library=None): # Явная DLL позволяет новой панели не заменять библиотеку работающего приложения.
|
|
self.lib = library if library is not None else _load_library() # Нет Python fallback при отсутствии нового C-кодека.
|
|
self.lib.set_invertor_gas_limit.argtypes = [ctypes.c_uint] # Тип сообщения передаётся без вычисления геометрии карты в Python.
|
|
self.lib.set_invertor_gas_limit.restype = ctypes.c_uint # Границы определяются профилем C из Templates.
|
|
self.lib.set_invertor_gas_build.argtypes = [ctypes.c_uint, ctypes.c_uint, ctypes.POINTER(ctypes.c_uint16), ctypes.c_uint, ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint8)] # Типы совпадают с публичным C ABI общего адаптера.
|
|
self.lib.set_invertor_gas_build.restype = ctypes.c_int # C возвращает фактический DLC либо отрицательную ошибку.
|
|
self.lib.set_invertor_gas_decode.argtypes = [ctypes.c_uint32, ctypes.c_uint, ctypes.POINTER(ctypes.c_uint8), ctypes.c_uint, ctypes.POINTER(ctypes.c_uint), ctypes.POINTER(ctypes.c_uint16)] # Декодер проверяет ID, тип, направление, длину и маску.
|
|
self.lib.set_invertor_gas_decode.restype = ctypes.c_int # Число принятых wire-слов приходит только из C.
|
|
def limit(self, message_type): # Интерфейс не хранит отдельную копию константы 250 или 750.
|
|
return int(self.lib.set_invertor_gas_limit(message_type)) # Передаём актуальную границу виджету адреса.
|
|
def build(self, message_type, address, words=()): # Пустой набор слов означает чтение DLC0 в обоих протоколах.
|
|
if not 0 <= address <= 0xFFFF or len(words) > 4 or any(not 0 <= word <= 0xFFFF for word in words): # Проверяем представимость Python-чисел перед сужением до типов ABI.
|
|
raise ValueError('Адрес или значение вне диапазона ABI') # Не допускаем тихого усечения и циклического переноса ctypes.
|
|
source = (ctypes.c_uint16 * len(words))(*words) if words else None # Значения остаются словами, endian выбирает общий кодек.
|
|
identifier = ctypes.c_uint32(); data = (ctypes.c_uint8 * 8)() # Локальные буферы имеют размеры Classic CAN и не переживают вызов.
|
|
length = self.lib.set_invertor_gas_build(message_type, address, source, len(words), ctypes.byref(identifier), data) # Ни CAN ID, ни маска не строятся здесь вручную.
|
|
if length < 0: # C отклоняет неверную геометрию, длину блока и маску.
|
|
raise ValueError('GAS: неверный адрес, длина блока или маска Word0') # Пользователь видит причину отказа до передачи на шину.
|
|
return identifier.value, bytes(data[:length]) # Транспорт получает полностью готовые ID и октеты.
|
|
def decode(self, identifier, flags, payload): # Входной кадр проверяется до публикации значений интерфейсу.
|
|
if not 0 <= identifier <= 0x1FFFFFFF or len(payload) > 8: # Не допускаем сужения большого CAN ID и переполнения временного буфера.
|
|
return None # Кадры другого транспорта не считаются ответом инвертора.
|
|
data = (ctypes.c_uint8 * 8)(*payload); metadata = (ctypes.c_uint * 2)(); words = (ctypes.c_uint16 * 4)() # ABI работает с фиксированными массивами без указателей на объекты Python.
|
|
count = self.lib.set_invertor_gas_decode(identifier, flags, data, len(payload), metadata, words) # Wire-разбор остаётся единственной C-реализацией.
|
|
return (metadata[0], metadata[1], tuple(words[:count])) if count > 0 else None # Недопустимый кадр не изменяет отображённые значения.
|