Add DSLogic capture, signal conversion and DSView decoders

This commit is contained in:
2026-09-27 01:45:08 +03:00
parent cc22c803d1
commit 513e79b127
44 changed files with 5982 additions and 36 deletions

View File

@@ -0,0 +1 @@
from .pd import Decoder

View File

@@ -0,0 +1,89 @@
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)