72 lines
3.8 KiB
Python
72 lines
3.8 KiB
Python
# Сегментация SET v2 и интерпретация CAN-данных зависят от выбранного слоя. Адрес и номер
|
|
# сегмента должны проверяться до объединения данных; classic CAN-пакет ограничен восемью
|
|
# байтами. Этот адаптер переводит события libsigrokdecode в аннотации DSView; координаты
|
|
# выборок пересчитываются с учётом частоты захвата.
|
|
|
|
import sigrokdecode as srd
|
|
from common.setgui_decoders.set_can import Reassembler, legacy
|
|
|
|
|
|
class Decoder(srd.Decoder):
|
|
api_version = 3
|
|
id = 'set_can'
|
|
name = 'SET CAN'
|
|
longname = 'SET v2 CAN / ProtoCAN / Balsam'
|
|
desc = 'Application fields and segmented SET packets over classic CAN.'
|
|
license = 'gplv2+'
|
|
inputs = ['can']
|
|
outputs = ['set']
|
|
tags = ['Embedded/industrial']
|
|
options = ({'id': 'protocol', 'desc': 'CAN protocol (select explicitly)',
|
|
'default': 'protocan', 'values': ('protocan', 'set-v2', 'balsam')},)
|
|
annotations = (('frame', 'Frame'), ('payload', 'Payload'), ('error', 'Error'))
|
|
annotation_rows = (('frames', 'Frames', (0,)), ('payload', 'Payload', (1,)), ('errors', 'Errors', (2,)))
|
|
|
|
def __init__(self):
|
|
self.reset()
|
|
|
|
# Состояние принадлежит одному запуску декодера. Сброс не должен
|
|
# переносить незавершённый кадр или частоту из предыдущей записи.
|
|
def reset(self):
|
|
self.reassembler = Reassembler()
|
|
self.samplerate = None
|
|
|
|
# DSView передаёт время в номерах отсчётов. Частота нужна общему ядру
|
|
# для перевода тайм-аутов и измерений в физические единицы.
|
|
def metadata(self, key, value):
|
|
if key == srd.SRD_CONF_SAMPLERATE:
|
|
self.samplerate = value
|
|
|
|
# Выходы регистрируются в жизненном цикле sigrok, а не в конструкторе.
|
|
# Аннотации предназначены для дорожек, структурированные события — для стека.
|
|
def start(self):
|
|
self.out_ann = self.register(srd.OUTPUT_ANN)
|
|
self.out_python = self.register(srd.OUTPUT_PYTHON)
|
|
|
|
def decode(self, ss, es, data):
|
|
frame_type, ident, rtr, dlc, payload = data
|
|
if frame_type != 'extended' or rtr == 'remote':
|
|
return
|
|
mode = self.options['protocol']
|
|
if not 0 <= dlc <= 8 or len(payload) != dlc:
|
|
events = [(ss, es, None, 'Invalid classic CAN DLC')]
|
|
# Сегментированный SET v2 требует времени для тайм-аута сборки.
|
|
# Идентификатор, порядок сегментов и CRC проверяет общее ядро.
|
|
elif mode == 'set-v2':
|
|
if not self.samplerate:
|
|
raise ValueError('SET CAN requires samplerate for reassembly timeout')
|
|
events = self.reassembler.feed(ident, payload, ss, es, es * 1000.0 / self.samplerate)
|
|
else:
|
|
try:
|
|
result = legacy(ident, payload, mode)
|
|
events = [(ss, es, result, None)] if result else []
|
|
except ValueError as exc:
|
|
events = [(ss, es, None, str(exc))]
|
|
for start, end, result, error in events:
|
|
self.put(start, end, self.out_ann, [2 if error else 0, [error or result['summary']]])
|
|
if result:
|
|
result['can_id'] = ident
|
|
self.put(start, end, self.out_python, ['FRAME', result])
|
|
if events and payload:
|
|
self.put(ss, es, self.out_ann, [1, [' '.join('%02X' % b for b in payload)]])
|