summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Gregory <andrew.gregory@gmail.com>2018-12-05 23:31:34 +0800
committerUwe Hermann <uwe@hermann-uwe.de>2019-06-30 22:45:22 +0200
commitd4364948d0356f0659e1777cf771ed5bfc1f2072 (patch)
tree88f82fe9cb72cca6c97d0f7ea6cdbb6043247beb
parent1c308e3d0f95fa484e1d89ca2d9cd01cb3293027 (diff)
downloadlibsigrokdecode-d4364948d0356f0659e1777cf771ed5bfc1f2072.tar.gz
libsigrokdecode-d4364948d0356f0659e1777cf771ed5bfc1f2072.zip
modbus: Make C->S and S->C configurable, add framegap option.
Change client->server and server->client to be separately configurable, allowing decoding at both the server (where client->server is RX and server->client is TX) and client (where client->server is TX and server->client is RX) ends of the link. It also allows monitoring of the bus on a single channel (where client->server and server->client are both RX (or TX)). When I tried to decode a bus capture, I found that when the transmitter was turned off it generated a false start bit, which in turn resulted in a false trailing byte from the UART decoder. This narrowed the inter-frame gap to the point where the Modbus decoder failed to recognise a new frame. The result was only the first frame of the capture decoded - all the rest of the frames failed to decode. I had to reduce the frame gap to allow subsequent frames to decode, and so made it a configurable option that defaults to the existing gap. Lastly, I fixed a call to puti() that incorrectly included the annotation prefix.
-rw-r--r--decoders/modbus/pd.py30
1 files changed, 16 insertions, 14 deletions
diff --git a/decoders/modbus/pd.py b/decoders/modbus/pd.py
index d5b39ca..d5cb811 100644
--- a/decoders/modbus/pd.py
+++ b/decoders/modbus/pd.py
@@ -22,6 +22,7 @@ from math import ceil
RX = 0
TX = 1
+rxtx_channels = ('RX', 'TX')
class No_more_data(Exception):
'''This exception is a signal that we should stop parsing an ADU as there
@@ -124,18 +125,18 @@ class Modbus_ADU:
self.annotation_prefix + 'error',
'Message too short or not finished')
self.hasError = True
- if self.hasError and self.parent.options['channel'] == 'RX':
- # If we are on RX mode (so client->server and server->client
- # messages can be seperated) we like to mark blocks containing
- # errors. We don't do this in TX mode, because then we interpret
- # each frame as both a client->server and server->client frame, and
+ if self.hasError and self.parent.options['scchannel'] != self.parent.options['cschannel']:
+ # If we are decoding different channels (so client->server and
+ # server->client messages can be separated) we like to mark blocks
+ # containing errors. We don't do this when decoding the same
+ # channel as both a client->server and server->client frame, and
# one of those is bound to contain an error, making highlighting
# frames useless.
self.parent.puta(data[0].start, data[-1].end,
'error-indication', 'Frame contains error')
if len(data) > 256:
try:
- self.puti(len(data) - 1, self.annotation_prefix + 'error',
+ self.puti(len(data) - 1, 'error',
'Modbus data frames are limited to 256 bytes')
except No_more_data:
pass
@@ -843,8 +844,11 @@ class Decoder(srd.Decoder):
('error-indicator', 'Errors in frame', (14,)),
)
options = (
- {'id': 'channel', 'desc': 'Server -> client channel', 'default': 'RX',
- 'values': ('RX', 'TX')},
+ {'id': 'scchannel', 'desc': 'Server -> client channel',
+ 'default': rxtx_channels[0], 'values': rxtx_channels},
+ {'id': 'cschannel', 'desc': 'Client -> server channel',
+ 'default': rxtx_channels[1], 'values': rxtx_channels},
+ {'id': 'framegap', 'desc': 'Inter-frame bit gap', 'default': '28'},
)
def __init__(self):
@@ -908,7 +912,7 @@ class Decoder(srd.Decoder):
# somewhere between seems fine.
# A character is 11 bits long, so (3.5 + 1.5)/2 * 11 ~= 28
# TODO: Display error for too short or too long.
- if (ss - ADU.last_read) <= self.bitlength * 28:
+ if (ss - ADU.last_read) <= self.bitlength * int(self.options['framegap']):
ADU.add_data(ss, es, data)
else:
# It's been too long since the last part of the ADU!
@@ -927,9 +931,7 @@ class Decoder(srd.Decoder):
# Decide what ADU(s) we need this packet to go to.
# Note that it's possible to go to both ADUs.
- if rxtx == TX:
- self.decode_adu(ss, es, data, 'Cs')
- if rxtx == TX and self.options['channel'] == 'TX':
- self.decode_adu(ss, es, data, 'Sc')
- if rxtx == RX and self.options['channel'] == 'RX':
+ if rxtx_channels[rxtx] == self.options['scchannel']:
self.decode_adu(ss, es, data, 'Sc')
+ if rxtx_channels[rxtx] == self.options['cschannel']:
+ self.decode_adu(ss, es, data, 'Cs')