Files
templates/python/set_devices/ump_logger_can.py

78 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CAN-представление запросов регистратора periph_28335. Идентификаторы запросов и ответов
# зависят от режима; обратное преобразование выполняется по этому контракту, а не по формату
# общего моста.
"""CAN-транспорт расширения регистратора periph_28335.
Служебные запросы идут на штатный RX ID платы 0xBA0000 + Mode - 1.
Ответы имеют отдельный ID 0xBA0020 + Mode - 1. Технологическая телеметрия
не принимается за ответ логгера. Данные кадра следуют порядку MDL, MDH
существующей прошивки; каждое слово передаётся старшим байтом вперёд.
"""
from dataclasses import dataclass, field
import struct
from set_devices.ump_logger import BASE, DATA, LIVE, EMU_CONTROL
MARKER = 0x1F00
MAX_WORDS = 124
def request_ids(mode):
if not 1 <= mode <= 16:
raise ValueError('Номер CAN-платы должен быть 1…16 (Mode прошивки)')
return 0xBA0000 + mode - 1, 0xBA0020 + mode - 1
def build_request(mode, token, function, address, value):
if not 1 <= token <= 255:
raise ValueError('Неверный номер CAN-запроса')
valid = ((function == 3 and ((address == BASE and value == 16) or
(address == DATA and value in (40, 80, 120, 42, 84)) or
(address == LIVE and value == MAX_WORDS) or (address == EMU_CONTROL and value == 4))) or
(function == 6 and ((BASE <= address <= BASE+3 and 0 <= value <= 65535) or
(address == EMU_CONTROL+2 and value in (0, 1)))))
if not valid:
raise ValueError('Недопустимый запрос CAN-логгера')
can_id, _ = request_ids(mode)
return can_id, struct.pack('>4H', address, value, MARKER, token << 8 | function)
@dataclass
class Response:
"""Собирает один снимок. Дубликаты допустимы, противоречащие — ошибка.
Номер фрагмента позволяет восстановить порядок при задержках адаптера.
До получения всех фрагментов снимок не передаётся в график/архив.
"""
mode: int
token: int
function: int
address: int
value: int
fragments: dict = field(default_factory=dict)
def feed(self, can_id, data):
if can_id != request_ids(self.mode)[1] or len(data) != 8:
return None
first, second, header, tag = struct.unpack('>4H', bytes(data))
if not MARKER <= header < MARKER + 62 or tag >> 8 != self.token:
return None
if tag & 255:
raise ValueError(f'Плата отклонила CAN-запрос логгера: ошибка {tag & 255}')
count = self.value if self.function == 3 else 2
index = header - MARKER
if index >= count // 2:
raise ValueError('Лишний фрагмент CAN-ответа логгера')
words = (first, second)
if index in self.fragments and self.fragments[index] != words:
raise ValueError('Противоречащие фрагменты CAN-ответа')
self.fragments[index] = words
if len(self.fragments) != count // 2:
return None
result = tuple(word for n in range(count // 2) for word in self.fragments[n])
if self.function == 6:
if result != (self.address, self.value):
raise ValueError('CAN-плата подтвердила другую запись')
return ()
return result