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)]])