Files
templates/tools/dsview/decoders/pm35_uart/pd.py

83 lines
4.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)