Add DSLogic capture, signal conversion and DSView decoders
This commit is contained in:
82
tools/dsview/decoders/pm35_uart/pd.py
Normal file
82
tools/dsview/decoders/pm35_uart/pd.py
Normal file
@@ -0,0 +1,82 @@
|
||||
import sigrokdecode as srd
|
||||
from common.setgui_decoders.pm35_uart import PM35Parser
|
||||
|
||||
|
||||
class Decoder(srd.Decoder):
|
||||
api_version = 3
|
||||
id = 'pm35_uart'
|
||||
name = 'PM35 UART'
|
||||
longname = 'PM35 / TMS320F28335 terminal'
|
||||
desc = 'MODBUS 03/06 register traffic and CRC16.'
|
||||
license = 'gplv2+'
|
||||
inputs = ['uart']
|
||||
outputs = ['pm35']
|
||||
tags = ['Embedded/industrial']
|
||||
options = (
|
||||
{'id': 'rx_role', 'desc': 'RX carries', 'default': 'response', 'values': ('request', 'response', 'auto')},
|
||||
{'id': 'tx_role', 'desc': 'TX carries', 'default': 'request', 'values': ('request', 'response', 'auto')},
|
||||
{'id': 'baudrate', 'desc': 'UART baudrate (RTU gap detection)', 'default': 115200},
|
||||
{'id': 'bits_per_char', 'desc': 'Bits per UART character including start/stop/parity', 'default': 10},
|
||||
)
|
||||
annotations = (('frame', 'Frame'), ('error', 'Error'))
|
||||
annotation_rows = (('frames', 'Frames', (0,)), ('errors', 'Errors', (1,)))
|
||||
|
||||
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):
|
||||
if self.options['baudrate'] <= 0 or self.options['bits_per_char'] <= 0:
|
||||
raise ValueError('Baudrate and bits per character must be positive')
|
||||
self.out_ann = self.register(srd.OUTPUT_ANN)
|
||||
self.out_python = self.register(srd.OUTPUT_PYTHON)
|
||||
|
||||
def emit(self, events, direction):
|
||||
for ss, es, result, error in events:
|
||||
self.put(ss, es, self.out_ann, [1 if error else 0,
|
||||
[('RX', 'TX')[direction] + ' ' + (error or result['summary'])]])
|
||||
if result:
|
||||
result['direction'] = direction
|
||||
self.put(ss, es, self.out_python, ['FRAME', result])
|
||||
|
||||
def decode(self, ss, es, data):
|
||||
kind, direction, payload = data
|
||||
if direction not in (0, 1):
|
||||
return
|
||||
parser = self.parsers.setdefault(direction, PM35Parser(self.options[('rx_role', 'tx_role')[direction]]))
|
||||
if kind in ('INVALID STOPBIT', 'INVALID STARTBIT', 'PARITY ERROR', 'BREAK'):
|
||||
self.emit(parser.flush(), direction)
|
||||
self.put(ss, es, self.out_ann, [1, [kind]])
|
||||
return
|
||||
if kind != 'FRAME':
|
||||
return
|
||||
if not payload[1]:
|
||||
self.emit(parser.flush(), direction)
|
||||
self.put(ss, es, self.out_ann, [1, ['Invalid UART frame']])
|
||||
return
|
||||
# Граница MODBUS определяется паузой 3,5 символа. bits_per_char включает
|
||||
# все биты символа; эта настройка должна соответствовать базовому UART.
|
||||
if self.samplerate and direction in self.last:
|
||||
gap = self.samplerate * 3.5 * self.options['bits_per_char'] / self.options['baudrate']
|
||||
if ss - self.last[direction] >= gap:
|
||||
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, [1, ['Configure UART for 8 data bits']])
|
||||
return
|
||||
self.emit(parser.feed(payload[0], ss, es), direction)
|
||||
Reference in New Issue
Block a user