]> sigrok.org Git - libsigrokdecode.git/blame - decoders/uart/pd.py
uart: Remove redundant "reached bit" checks
[libsigrokdecode.git] / decoders / uart / pd.py
CommitLineData
f44d2db2 1##
50bd5d25 2## This file is part of the libsigrokdecode project.
f44d2db2 3##
0bb7bcf3 4## Copyright (C) 2011-2014 Uwe Hermann <uwe@hermann-uwe.de>
f44d2db2
UH
5##
6## This program is free software; you can redistribute it and/or modify
7## it under the terms of the GNU General Public License as published by
8## the Free Software Foundation; either version 2 of the License, or
9## (at your option) any later version.
10##
11## This program is distributed in the hope that it will be useful,
12## but WITHOUT ANY WARRANTY; without even the implied warranty of
13## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14## GNU General Public License for more details.
15##
16## You should have received a copy of the GNU General Public License
4539e9ca 17## along with this program; if not, see <http://www.gnu.org/licenses/>.
f44d2db2
UH
18##
19
677d597b 20import sigrokdecode as srd
b5712ccb 21from math import floor, ceil
f44d2db2 22
4cace3b8 23'''
c515eed7 24OUTPUT_PYTHON format:
4cace3b8 25
bf69977d
UH
26Packet:
27[<ptype>, <rxtx>, <pdata>]
4cace3b8 28
bf69977d 29This is the list of <ptype>s and their respective <pdata> values:
4cace3b8 30 - 'STARTBIT': The data is the (integer) value of the start bit (0/1).
0c7d5a56
UH
31 - 'DATA': This is always a tuple containing two items:
32 - 1st item: the (integer) value of the UART data. Valid values
6ffd71c1 33 range from 0 to 511 (as the data can be up to 9 bits in size).
0c7d5a56 34 - 2nd item: the list of individual data bits and their ss/es numbers.
4cace3b8
UH
35 - 'PARITYBIT': The data is the (integer) value of the parity bit (0/1).
36 - 'STOPBIT': The data is the (integer) value of the stop bit (0 or 1).
37 - 'INVALID STARTBIT': The data is the (integer) value of the start bit (0/1).
38 - 'INVALID STOPBIT': The data is the (integer) value of the stop bit (0/1).
39 - 'PARITY ERROR': The data is a tuple with two entries. The first one is
40 the expected parity value, the second is the actual parity value.
41 - TODO: Frame error?
42
43The <rxtx> field is 0 for RX packets, 1 for TX packets.
44'''
45
97cca21f
UH
46# Used for differentiating between the two data directions.
47RX = 0
48TX = 1
49
f44d2db2
UH
50# Given a parity type to check (odd, even, zero, one), the value of the
51# parity bit, the value of the data, and the length of the data (5-9 bits,
52# usually 8 bits) return True if the parity is correct, False otherwise.
a7fc4c34 53# 'none' is _not_ allowed as value for 'parity_type'.
f44d2db2
UH
54def parity_ok(parity_type, parity_bit, data, num_data_bits):
55
56 # Handle easy cases first (parity bit is always 1 or 0).
a7fc4c34 57 if parity_type == 'zero':
f44d2db2 58 return parity_bit == 0
a7fc4c34 59 elif parity_type == 'one':
f44d2db2
UH
60 return parity_bit == 1
61
62 # Count number of 1 (high) bits in the data (and the parity bit itself!).
ac941bf9 63 ones = bin(data).count('1') + parity_bit
f44d2db2
UH
64
65 # Check for odd/even parity.
a7fc4c34 66 if parity_type == 'odd':
ac941bf9 67 return (ones % 2) == 1
a7fc4c34 68 elif parity_type == 'even':
ac941bf9 69 return (ones % 2) == 0
f44d2db2 70
21cda951
UH
71class SamplerateError(Exception):
72 pass
73
f04964c6
UH
74class ChannelError(Exception):
75 pass
76
677d597b 77class Decoder(srd.Decoder):
dcd3d626 78 api_version = 3
f44d2db2
UH
79 id = 'uart'
80 name = 'UART'
3d3da57d 81 longname = 'Universal Asynchronous Receiver/Transmitter'
a465436e 82 desc = 'Asynchronous, serial bus.'
f44d2db2
UH
83 license = 'gplv2+'
84 inputs = ['logic']
85 outputs = ['uart']
6a15597a 86 optional_channels = (
f44d2db2
UH
87 # Allow specifying only one of the signals, e.g. if only one data
88 # direction exists (or is relevant).
29ed0f4c
UH
89 {'id': 'rx', 'name': 'RX', 'desc': 'UART receive line'},
90 {'id': 'tx', 'name': 'TX', 'desc': 'UART transmit line'},
da9bcbd9 91 )
84c1c0b5
BV
92 options = (
93 {'id': 'baudrate', 'desc': 'Baud rate', 'default': 115200},
94 {'id': 'num_data_bits', 'desc': 'Data bits', 'default': 8,
95 'values': (5, 6, 7, 8, 9)},
96 {'id': 'parity_type', 'desc': 'Parity type', 'default': 'none',
97 'values': ('none', 'odd', 'even', 'zero', 'one')},
98 {'id': 'parity_check', 'desc': 'Check parity?', 'default': 'yes',
99 'values': ('yes', 'no')},
100 {'id': 'num_stop_bits', 'desc': 'Stop bits', 'default': 1.0,
101 'values': (0.0, 0.5, 1.0, 1.5)},
102 {'id': 'bit_order', 'desc': 'Bit order', 'default': 'lsb-first',
103 'values': ('lsb-first', 'msb-first')},
ea36c198 104 {'id': 'format', 'desc': 'Data format', 'default': 'hex',
84c1c0b5 105 'values': ('ascii', 'dec', 'hex', 'oct', 'bin')},
4eafeeef
DB
106 {'id': 'invert_rx', 'desc': 'Invert RX?', 'default': 'no',
107 'values': ('yes', 'no')},
108 {'id': 'invert_tx', 'desc': 'Invert TX?', 'default': 'no',
109 'values': ('yes', 'no')},
84c1c0b5 110 )
da9bcbd9
BV
111 annotations = (
112 ('rx-data', 'RX data'),
113 ('tx-data', 'TX data'),
114 ('rx-start', 'RX start bits'),
115 ('tx-start', 'TX start bits'),
116 ('rx-parity-ok', 'RX parity OK bits'),
117 ('tx-parity-ok', 'TX parity OK bits'),
118 ('rx-parity-err', 'RX parity error bits'),
119 ('tx-parity-err', 'TX parity error bits'),
120 ('rx-stop', 'RX stop bits'),
121 ('tx-stop', 'TX stop bits'),
122 ('rx-warnings', 'RX warnings'),
123 ('tx-warnings', 'TX warnings'),
124 ('rx-data-bits', 'RX data bits'),
125 ('tx-data-bits', 'TX data bits'),
126 )
2ce20a91 127 annotation_rows = (
4e3b276a 128 ('rx-data', 'RX', (0, 2, 4, 6, 8)),
4aedd5b8 129 ('rx-data-bits', 'RX bits', (12,)),
4e3b276a 130 ('rx-warnings', 'RX warnings', (10,)),
4aedd5b8
UH
131 ('tx-data', 'TX', (1, 3, 5, 7, 9)),
132 ('tx-data-bits', 'TX bits', (13,)),
4e3b276a 133 ('tx-warnings', 'TX warnings', (11,)),
2ce20a91 134 )
0bb7bcf3
UH
135 binary = (
136 ('rx', 'RX dump'),
137 ('tx', 'TX dump'),
138 ('rxtx', 'RX/TX dump'),
139 )
96a044da 140 idle_state = ['WAIT FOR START BIT', 'WAIT FOR START BIT']
f44d2db2 141
97cca21f 142 def putx(self, rxtx, data):
b5712ccb
PA
143 s, halfbit = self.startsample[rxtx], self.bit_width / 2.0
144 self.put(s - floor(halfbit), self.samplenum + ceil(halfbit), self.out_ann, data)
15ac6604 145
4aedd5b8 146 def putpx(self, rxtx, data):
b5712ccb
PA
147 s, halfbit = self.startsample[rxtx], self.bit_width / 2.0
148 self.put(s - floor(halfbit), self.samplenum + ceil(halfbit), self.out_python, data)
4aedd5b8 149
15ac6604 150 def putg(self, data):
b5712ccb
PA
151 s, halfbit = self.samplenum, self.bit_width / 2.0
152 self.put(s - floor(halfbit), s + ceil(halfbit), self.out_ann, data)
15ac6604
UH
153
154 def putp(self, data):
b5712ccb
PA
155 s, halfbit = self.samplenum, self.bit_width / 2.0
156 self.put(s - floor(halfbit), s + ceil(halfbit), self.out_python, data)
97cca21f 157
0bb7bcf3 158 def putbin(self, rxtx, data):
b5712ccb 159 s, halfbit = self.startsample[rxtx], self.bit_width / 2.0
2f370328 160 self.put(s - floor(halfbit), self.samplenum + ceil(halfbit), self.out_binary, data)
0bb7bcf3 161
92b7b49f 162 def __init__(self):
f372d597 163 self.samplerate = None
f44d2db2 164 self.samplenum = 0
97cca21f
UH
165 self.frame_start = [-1, -1]
166 self.startbit = [-1, -1]
167 self.cur_data_bit = [0, 0]
e9a3c933 168 self.datavalue = [0, 0]
1ccef461 169 self.paritybit = [-1, -1]
97cca21f
UH
170 self.stopbit1 = [-1, -1]
171 self.startsample = [-1, -1]
2b716038 172 self.state = ['WAIT FOR START BIT', 'WAIT FOR START BIT']
4aedd5b8 173 self.databits = [[], []]
f44d2db2 174
f372d597 175 def start(self):
c515eed7 176 self.out_python = self.register(srd.OUTPUT_PYTHON)
2f370328 177 self.out_binary = self.register(srd.OUTPUT_BINARY)
be465111 178 self.out_ann = self.register(srd.OUTPUT_ANN)
98b89139 179 self.bw = (self.options['num_data_bits'] + 7) // 8
f44d2db2 180
f372d597
BV
181 def metadata(self, key, value):
182 if key == srd.SRD_CONF_SAMPLERATE:
35b380b1 183 self.samplerate = value
f372d597
BV
184 # The width of one UART bit in number of samples.
185 self.bit_width = float(self.samplerate) / float(self.options['baudrate'])
f44d2db2 186
dcd3d626
GS
187 def get_sample_point(self, rxtx, bitnum):
188 """Determine absolute sample number of a bit slot's sample point."""
f44d2db2
UH
189 # bitpos is the samplenumber which is in the middle of the
190 # specified UART bit (0 = start bit, 1..x = data, x+1 = parity bit
191 # (if used) or the first stop bit, and so on).
b5712ccb
PA
192 # The samples within bit are 0, 1, ..., (bit_width - 1), therefore
193 # index of the middle sample within bit window is (bit_width - 1) / 2.
194 bitpos = self.frame_start[rxtx] + (self.bit_width - 1) / 2.0
f44d2db2 195 bitpos += bitnum * self.bit_width
dcd3d626
GS
196 return bitpos
197
dcd3d626 198 def wait_for_start_bit(self, rxtx, signal):
f44d2db2 199 # Save the sample number where the start bit begins.
97cca21f 200 self.frame_start[rxtx] = self.samplenum
f44d2db2 201
2b716038 202 self.state[rxtx] = 'GET START BIT'
f44d2db2 203
97cca21f 204 def get_start_bit(self, rxtx, signal):
97cca21f 205 self.startbit[rxtx] = signal
f44d2db2 206
711d0602
GS
207 # The startbit must be 0. If not, we report an error and wait
208 # for the next start bit (assuming this one was spurious).
97cca21f 209 if self.startbit[rxtx] != 0:
15ac6604 210 self.putp(['INVALID STARTBIT', rxtx, self.startbit[rxtx]])
76a4498f 211 self.putg([rxtx + 10, ['Frame error', 'Frame err', 'FE']])
711d0602
GS
212 self.state[rxtx] = 'WAIT FOR START BIT'
213 return
f44d2db2 214
97cca21f 215 self.cur_data_bit[rxtx] = 0
e9a3c933 216 self.datavalue[rxtx] = 0
97cca21f 217 self.startsample[rxtx] = -1
f44d2db2 218
2b716038 219 self.state[rxtx] = 'GET DATA BITS'
f44d2db2 220
15ac6604 221 self.putp(['STARTBIT', rxtx, self.startbit[rxtx]])
2ce20a91 222 self.putg([rxtx + 2, ['Start bit', 'Start', 'S']])
f44d2db2 223
97cca21f 224 def get_data_bits(self, rxtx, signal):
15ac6604 225 # Save the sample number of the middle of the first data bit.
97cca21f
UH
226 if self.startsample[rxtx] == -1:
227 self.startsample[rxtx] = self.samplenum
f44d2db2
UH
228
229 # Get the next data bit in LSB-first or MSB-first fashion.
a7fc4c34 230 if self.options['bit_order'] == 'lsb-first':
e9a3c933
GS
231 self.datavalue[rxtx] >>= 1
232 self.datavalue[rxtx] |= \
fd4aa8aa 233 (signal << (self.options['num_data_bits'] - 1))
22fc7ace 234 else:
e9a3c933
GS
235 self.datavalue[rxtx] <<= 1
236 self.datavalue[rxtx] |= (signal << 0)
f44d2db2 237
4aedd5b8
UH
238 self.putg([rxtx + 12, ['%d' % signal]])
239
240 # Store individual data bits and their start/end samplenumbers.
241 s, halfbit = self.samplenum, int(self.bit_width / 2)
242 self.databits[rxtx].append([signal, s - halfbit, s + halfbit])
243
f44d2db2 244 # Return here, unless we already received all data bits.
5e3c79fd
GS
245 self.cur_data_bit[rxtx] += 1
246 if self.cur_data_bit[rxtx] < self.options['num_data_bits']:
1bb57ab8 247 return
f44d2db2 248
1078af01
GS
249 # Skip to either reception of the parity bit, or reception of
250 # the STOP bits if parity is not applicable.
2b716038 251 self.state[rxtx] = 'GET PARITY BIT'
1078af01
GS
252 if self.options['parity_type'] == 'none':
253 self.state[rxtx] = 'GET STOP BITS'
f44d2db2 254
7cf698c5 255 self.putpx(rxtx, ['DATA', rxtx,
e9a3c933 256 (self.datavalue[rxtx], self.databits[rxtx])])
f44d2db2 257
6ffd71c1
GS
258 b = self.datavalue[rxtx]
259 formatted = self.format_value(b)
260 if formatted is not None:
261 self.putx(rxtx, [rxtx, [formatted]])
f44d2db2 262
98b89139
UH
263 bdata = b.to_bytes(self.bw, byteorder='big')
264 self.putbin(rxtx, [rxtx, bdata])
265 self.putbin(rxtx, [2, bdata])
0bb7bcf3 266
c1fc50b1 267 self.databits[rxtx] = []
4aedd5b8 268
6ffd71c1
GS
269 def format_value(self, v):
270 # Format value 'v' according to configured options.
271 # Reflects the user selected kind of representation, as well as
272 # the number of data bits in the UART frames.
273
274 fmt, bits = self.options['format'], self.options['num_data_bits']
275
276 # Assume "is printable" for values from 32 to including 126,
277 # below 32 is "control" and thus not printable, above 127 is
278 # "not ASCII" in its strict sense, 127 (DEL) is not printable,
279 # fall back to hex representation for non-printables.
280 if fmt == 'ascii':
281 if v in range(32, 126 + 1):
282 return chr(v)
283 hexfmt = "[{:02X}]" if bits <= 8 else "[{:03X}]"
284 return hexfmt.format(v)
285
286 # Mere number to text conversion without prefix and padding
287 # for the "decimal" output format.
288 if fmt == 'dec':
289 return "{:d}".format(v)
290
291 # Padding with leading zeroes for hex/oct/bin formats, but
292 # without a prefix for density -- since the format is user
293 # specified, there is no ambiguity.
294 if fmt == 'hex':
295 digits = (bits + 4 - 1) // 4
296 fmtchar = "X"
297 elif fmt == 'oct':
298 digits = (bits + 3 - 1) // 3
299 fmtchar = "o"
300 elif fmt == 'bin':
301 digits = bits
302 fmtchar = "b"
303 else:
304 fmtchar = None
305 if fmtchar is not None:
306 fmt = "{{:0{:d}{:s}}}".format(digits, fmtchar)
307 return fmt.format(v)
308
309 return None
310
97cca21f 311 def get_parity_bit(self, rxtx, signal):
97cca21f 312 self.paritybit[rxtx] = signal
f44d2db2 313
2b716038 314 self.state[rxtx] = 'GET STOP BITS'
f44d2db2 315
ac941bf9 316 if parity_ok(self.options['parity_type'], self.paritybit[rxtx],
e9a3c933 317 self.datavalue[rxtx], self.options['num_data_bits']):
15ac6604 318 self.putp(['PARITYBIT', rxtx, self.paritybit[rxtx]])
2ce20a91 319 self.putg([rxtx + 4, ['Parity bit', 'Parity', 'P']])
f44d2db2 320 else:
61132abd 321 # TODO: Return expected/actual parity values.
15ac6604 322 self.putp(['PARITY ERROR', rxtx, (0, 1)]) # FIXME: Dummy tuple...
4e3b276a 323 self.putg([rxtx + 6, ['Parity error', 'Parity err', 'PE']])
f44d2db2
UH
324
325 # TODO: Currently only supports 1 stop bit.
97cca21f 326 def get_stop_bits(self, rxtx, signal):
97cca21f 327 self.stopbit1[rxtx] = signal
f44d2db2 328
5cc4b6a0 329 # Stop bits must be 1. If not, we report an error.
97cca21f 330 if self.stopbit1[rxtx] != 1:
15ac6604 331 self.putp(['INVALID STOPBIT', rxtx, self.stopbit1[rxtx]])
76a4498f 332 self.putg([rxtx + 10, ['Frame error', 'Frame err', 'FE']])
5cc4b6a0 333 # TODO: Abort? Ignore the frame? Other?
f44d2db2 334
2b716038 335 self.state[rxtx] = 'WAIT FOR START BIT'
f44d2db2 336
15ac6604 337 self.putp(['STOPBIT', rxtx, self.stopbit1[rxtx]])
2ce20a91 338 self.putg([rxtx + 4, ['Stop bit', 'Stop', 'T']])
f44d2db2 339
dcd3d626
GS
340 def get_wait_cond(self, rxtx, inv):
341 """
342 Determine Decoder.wait() condition for specified UART line.
343
344 Returns condititions that are suitable for Decoder.wait(). Those
345 conditions either match the falling edge of the START bit, or
346 the sample point of the next bit time.
347 """
348
349 state = self.state[rxtx]
350 if state == 'WAIT FOR START BIT':
351 return {rxtx: 'r' if inv else 'f'}
352 if state == 'GET START BIT':
353 bitnum = 0
354 elif state == 'GET DATA BITS':
355 bitnum = 1 + self.cur_data_bit[rxtx]
356 elif state == 'GET PARITY BIT':
357 bitnum = 1 + self.options['num_data_bits']
358 elif state == 'GET STOP BITS':
359 bitnum = 1 + self.options['num_data_bits']
360 bitnum += 0 if self.options['parity_type'] == 'none' else 1
361 want_num = self.get_sample_point(rxtx, bitnum)
362 # want_num = int(want_num + 0.5)
363 want_num = ceil(want_num)
364 cond = {'skip': want_num - self.samplenum}
365 return cond
366
0de2810f
GS
367 def inspect_sample(self, rxtx, signal, inv):
368 """Inspect a sample returned by .wait() for the specified UART line."""
369
370 if inv:
371 signal = not signal
372
373 state = self.state[rxtx]
374 if state == 'WAIT FOR START BIT':
375 self.wait_for_start_bit(rxtx, signal)
376 elif state == 'GET START BIT':
377 self.get_start_bit(rxtx, signal)
378 elif state == 'GET DATA BITS':
379 self.get_data_bits(rxtx, signal)
380 elif state == 'GET PARITY BIT':
381 self.get_parity_bit(rxtx, signal)
382 elif state == 'GET STOP BITS':
383 self.get_stop_bits(rxtx, signal)
384
dcd3d626 385 def decode(self):
21cda951
UH
386 if not self.samplerate:
387 raise SamplerateError('Cannot decode without samplerate.')
2fcd7c22 388
dcd3d626
GS
389 has_pin = [self.has_channel(ch) for ch in (RX, TX)]
390 if has_pin == [False, False]:
391 raise ChannelError('Either TX or RX (or both) pins required.')
392
393 opt = self.options
394 inv = [opt['invert_rx'] == 'yes', opt['invert_tx'] == 'yes']
7d62e5b3 395 cond_idx = [None] * len(has_pin)
dcd3d626
GS
396
397 while True:
398 conds = []
399 if has_pin[RX]:
7d62e5b3 400 cond_idx[RX] = len(conds)
dcd3d626
GS
401 conds.append(self.get_wait_cond(RX, inv[RX]))
402 if has_pin[TX]:
7d62e5b3 403 cond_idx[TX] = len(conds)
dcd3d626
GS
404 conds.append(self.get_wait_cond(TX, inv[TX]))
405 (rx, tx) = self.wait(conds)
7d62e5b3 406 if cond_idx[RX] is not None and self.matched[cond_idx[RX]]:
0de2810f 407 self.inspect_sample(RX, rx, inv[RX])
7d62e5b3 408 if cond_idx[TX] is not None and self.matched[cond_idx[TX]]:
0de2810f 409 self.inspect_sample(TX, tx, inv[TX])