import sigrokdecode as srd from common.setgui_decoders.set_uart import StreamParser class Decoder(srd.Decoder): api_version = 3 id = 'set_uart' name = 'SET UART' longname = 'SET v2 / SETGUI v1 / ProtoCAN bridge' desc = 'SET frames, fields and CRC over UART.' license = 'gplv2+' inputs = ['uart'] outputs = ['set'] tags = ['Embedded/industrial'] options = ( {'id': 'protocol', 'desc': 'Protocol', 'default': 'auto', 'values': ('auto', 'v2', 'v1', 'bridge')}, {'id': 'gap_ms', 'desc': 'Reset incomplete frame after gap (ms, 0 disables)', 'default': 100}, ) 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.parsers = {} self.last = {} 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 emit(self, events, direction): for ss, es, frame, error in events: prefix = ('RX', 'TX')[direction] + ' ' self.put(ss, es, self.out_ann, [2 if error else 0, [prefix + (error or frame['summary'])]]) if frame: if frame['protocol'] == 'ProtoCAN bridge' and frame['flags'] & 1 and not frame['flags'] & 10: # Imported only at decode time: both packages are installed together. from common.setgui_decoders.set_can import legacy try: application = legacy(frame['can_id'], frame['payload']) frame['application'] = application self.put(ss, es, self.out_ann, [0, [application['summary']]]) except ValueError as exc: self.put(ss, es, self.out_ann, [2, [str(exc)]]) frame['direction'] = direction self.put(ss, es, self.out_python, ['FRAME', frame]) if frame['payload']: self.put(ss, es, self.out_ann, [1, [prefix + ' '.join('%02X' % b for b in frame['payload'])]]) def decode(self, ss, es, data): kind, direction, payload = data if direction not in (0, 1): return # RX и TX имеют независимые парсеры: перемежающиеся байты двух направлений # нельзя объединять в один прикладной кадр. parser = self.parsers.setdefault(direction, StreamParser(self.options['protocol'])) if kind in ('INVALID STOPBIT', 'INVALID STARTBIT', 'PARITY ERROR', 'BREAK'): self.emit(parser.flush(), direction) self.put(ss, es, self.out_ann, [2, [kind]]) return if kind != 'FRAME': return if not payload[1]: self.emit(parser.flush(), direction) self.put(ss, es, self.out_ann, [2, ['Invalid UART frame']]) return gap = float(self.options['gap_ms']) if self.samplerate and gap > 0 and direction in self.last and ss - self.last[direction] > self.samplerate * gap / 1000: self.emit(parser.flush(), direction) self.last[direction] = es if not 0 <= payload[0] <= 255: self.emit(parser.flush(), direction) self.put(ss, es, self.out_ann, [2, ['Configure UART for 8 data bits']]) return self.emit(parser.feed(payload[0], ss, es), direction)