Добавить очереди операций PBUS/SBUS, общую консоль, настройки Candle и SLCAN, декодеры DSView и обработку плотных графиков. Обновить протокол Бальзам и проверки общих компонентов.
30 lines
4.4 KiB
Python
30 lines
4.4 KiB
Python
from collections import deque # Кольцевой буфер хранит только координаты одного максимального кадра.
|
||
from . import template_protocols # Подключает поставляемые пакеты templates в отдельном Python-процессе DSView.
|
||
from set_devices import tms_terminal as tms # Раскладки, CRC и потоковый поиск границ используются из действующего парсера терминала.
|
||
|
||
LAYOUTS = tuple(tms.PRESETS) + ('custom',) # Имена готовых раскладок совпадают с настройками терминала SETGUI.
|
||
|
||
class TmsStreamParser: # Адаптирует общий байтовый парсер к событиям с координатами sigrok.
|
||
def __init__(self, preset=tms.DEFAULT_PRESET, digit_bytes=38, analog_count=34, crc='MODBUS'): # Значения 38/34 соответствуют штатной раскладке message2.h.
|
||
selected = tms.PRESETS[preset] if preset != 'custom' else tms.Layout(digit_bytes, analog_count, crc) # Индивидуальная раскладка проверяется существующей моделью Layout.
|
||
self.layout = tms.Layout(selected.digit_bytes, selected.analog_count, crc) # CRC выбирается отдельно, поскольку в источниках есть MODBUS и CCITT-FALSE.
|
||
self.parser = tms.TmsParser(self.layout) # Поиск границ и подтверждение CRC выполняет общий парсер.
|
||
self.positions = deque(maxlen=self.layout.frame_size) # Число хранимых координат ограничено длиной одного кадра в байтах.
|
||
|
||
def flush(self): # Пауза либо ошибка UART запрещает объединять части разных посылок.
|
||
self.parser.reset() # Общий парсер отбрасывает недособранные байты и состояние синхронизации.
|
||
self.positions.clear() # Координаты старого хвоста также исключаются из следующего события.
|
||
return [] # Формат без сигнатуры не позволяет отличить неполный кадр от произвольного шума.
|
||
|
||
def feed(self, value, ss, es): # Один UART-байт приходит вместе с точными границами в отсчётах.
|
||
self.positions.append((ss, es)) # Последние frame_size позиций соответствуют окну поиска общего парсера.
|
||
events = [] # За один байт может завершиться один кадр фиксированной длины.
|
||
for record in self.parser.feed(bytes([value])): # Только CRC-подтверждённые записи выдаются прикладному слою.
|
||
fields = [('Команда', record.command), ('Адрес', str(record.address)), ('CRC', '%04X' % record.crc_frame)] # Служебные поля берутся из готовой модели TmsRecord.
|
||
fields += [(tms.analog_name(index), str(word)) for index, word in enumerate(record.analogs)] # Имена аналогов и знаковые int16 совпадают с терминалом SETGUI.
|
||
fields += [('Дискреты', ', '.join(record.set_bits()) or 'нет активных битов')] # Активные биты выдаются с исходной нумерацией байтов и битов.
|
||
result = dict(protocol='TMS UART', summary=record.summary, payload=record.raw[2:-3], raw=record.raw, fields=fields, analogs=record.analogs, digits=record.digits) # CRC и завершающий байт исключены из полезной нагрузки по контракту TMS_TO_TERMINAL.
|
||
events.append((self.positions[0][0], es, result, None)) # Начало подтверждённого окна сохраняется даже после пропущенного шума.
|
||
self.positions.clear() # Координаты завершённого кадра не удерживаются до следующей посылки.
|
||
return events # События имеют тот же контракт, что парсер SET UART.
|