]> sigrok.org Git - libsigrokdecode.git/blame - decoders/usb_signalling/pd.py
usb_signalling: fix SOP detection after an error condition
[libsigrokdecode.git] / decoders / usb_signalling / pd.py
CommitLineData
2dc6d41c 1##
50bd5d25 2## This file is part of the libsigrokdecode project.
2dc6d41c
UH
3##
4## Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
7d4b5fac 5## Copyright (C) 2012-2013 Uwe Hermann <uwe@hermann-uwe.de>
2dc6d41c
UH
6##
7## This program is free software; you can redistribute it and/or modify
8## it under the terms of the GNU General Public License as published by
9## the Free Software Foundation; either version 2 of the License, or
10## (at your option) any later version.
11##
12## This program is distributed in the hope that it will be useful,
13## but WITHOUT ANY WARRANTY; without even the implied warranty of
14## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15## GNU General Public License for more details.
16##
17## You should have received a copy of the GNU General Public License
18## along with this program; if not, write to the Free Software
19## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20##
21
2dc6d41c
UH
22import sigrokdecode as srd
23
a56b8fe1 24'''
c515eed7 25OUTPUT_PYTHON format:
a56b8fe1
UH
26
27Packet:
28[<ptype>, <pdata>]
29
30<ptype>, <pdata>:
31 - 'SOP', None
32 - 'SYM', <sym>
33 - 'BIT', <bit>
34 - 'STUFF BIT', None
35 - 'EOP', None
033d6221 36 - 'ERR', None
13e81308
SB
37 - 'KEEP ALIVE', None
38 - 'RESET', None
a56b8fe1
UH
39
40<sym>:
41 - 'J', 'K', 'SE0', or 'SE1'
42
43<bit>:
033d6221 44 - '0' or '1'
a56b8fe1 45 - Note: Symbols like SE0, SE1, and the J that's part of EOP don't yield 'BIT'.
a56b8fe1
UH
46'''
47
d1970f14 48# Low-/full-speed symbols.
2dc6d41c 49# Note: Low-speed J and K are inverted compared to the full-speed J and K!
7dc75721
UH
50symbols = {
51 'low-speed': {
2dc6d41c
UH
52 # (<dp>, <dm>): <symbol/state>
53 (0, 0): 'SE0',
54 (1, 0): 'K',
55 (0, 1): 'J',
56 (1, 1): 'SE1',
7dc75721
UH
57 },
58 'full-speed': {
2dc6d41c
UH
59 # (<dp>, <dm>): <symbol/state>
60 (0, 0): 'SE0',
61 (1, 0): 'J',
62 (0, 1): 'K',
63 (1, 1): 'SE1',
7dc75721 64 },
519092e3
SB
65 'automatic': {
66 # (<dp>, <dm>): <symbol/state>
67 (0, 0): 'SE0',
68 (1, 0): 'FS_J',
69 (0, 1): 'LS_J',
70 (1, 1): 'SE1',
71 },
2dc6d41c
UH
72}
73
5bb55598
UH
74bitrates = {
75 'low-speed': 1500000, # 1.5Mb/s (+/- 1.5%)
76 'full-speed': 12000000, # 12Mb/s (+/- 0.25%)
519092e3 77 'automatic': None
5bb55598
UH
78}
79
56cc44ff
SB
80sym_annotation = {
81 'J': [0, ['J']],
82 'K': [1, ['K']],
83 'SE0': [2, ['SE0', '0']],
84 'SE1': [3, ['SE1', '1']],
85c03d60
UH
85}
86
21cda951
UH
87class SamplerateError(Exception):
88 pass
89
2dc6d41c 90class Decoder(srd.Decoder):
12851357 91 api_version = 2
2dc6d41c
UH
92 id = 'usb_signalling'
93 name = 'USB signalling'
94 longname = 'Universal Serial Bus (LS/FS) signalling'
9e1437a0 95 desc = 'USB (low-speed and full-speed) signalling protocol.'
2dc6d41c
UH
96 license = 'gplv2+'
97 inputs = ['logic']
98 outputs = ['usb_signalling']
6a15597a 99 channels = (
2dc6d41c
UH
100 {'id': 'dp', 'name': 'D+', 'desc': 'USB D+ signal'},
101 {'id': 'dm', 'name': 'D-', 'desc': 'USB D- signal'},
da9bcbd9 102 )
84c1c0b5
BV
103 options = (
104 {'id': 'signalling', 'desc': 'Signalling',
519092e3 105 'default': 'automatic', 'values': ('automatic', 'full-speed', 'low-speed')},
84c1c0b5 106 )
da9bcbd9 107 annotations = (
85c03d60
UH
108 ('sym-j', 'J symbol'),
109 ('sym-k', 'K symbol'),
110 ('sym-se0', 'SE0 symbol'),
111 ('sym-se1', 'SE1 symbol'),
da9bcbd9
BV
112 ('sop', 'Start of packet (SOP)'),
113 ('eop', 'End of packet (EOP)'),
114 ('bit', 'Bit'),
115 ('stuffbit', 'Stuff bit'),
033d6221 116 ('error', 'Error'),
13e81308
SB
117 ('keep-alive', 'Low-speed keep-alive'),
118 ('reset', 'Reset'),
da9bcbd9 119 )
066d6594 120 annotation_rows = (
13e81308 121 ('bits', 'Bits', (4, 5, 6, 7, 8, 9, 10)),
85c03d60 122 ('symbols', 'Symbols', (0, 1, 2, 3)),
066d6594 123 )
2dc6d41c
UH
124
125 def __init__(self):
f372d597 126 self.samplerate = None
d1970f14 127 self.oldsym = 'J' # The "idle" state is J.
fdd5ee5e 128 self.ss_block = None
2dc6d41c 129 self.samplenum = 0
5bb55598
UH
130 self.bitrate = None
131 self.bitwidth = None
a241cfb6 132 self.samplepos = None
d1970f14 133 self.samplenum_target = None
a241cfb6 134 self.samplenum_edge = None
6fbab493 135 self.samplenum_lastedge = 0
2fcd7c22 136 self.oldpins = None
a241cfb6 137 self.edgepins = None
d1970f14 138 self.consecutive_ones = 0
13e81308 139 self.state = 'INIT'
2dc6d41c 140
f372d597 141 def start(self):
c515eed7 142 self.out_python = self.register(srd.OUTPUT_PYTHON)
be465111 143 self.out_ann = self.register(srd.OUTPUT_ANN)
f372d597
BV
144
145 def metadata(self, key, value):
146 if key == srd.SRD_CONF_SAMPLERATE:
147 self.samplerate = value
519092e3
SB
148 self.signalling = self.options['signalling']
149 if self.signalling != 'automatic':
150 self.update_bitrate()
151
152 def update_bitrate(self):
153 self.bitrate = bitrates[self.signalling]
154 self.bitwidth = float(self.samplerate) / float(self.bitrate)
2dc6d41c 155
d1970f14 156 def putpx(self, data):
6fbab493
SB
157 s = self.samplenum_edge
158 self.put(s, s, self.out_python, data)
7d4b5fac
UH
159
160 def putx(self, data):
6fbab493
SB
161 s = self.samplenum_edge
162 self.put(s, s, self.out_ann, data)
7d4b5fac 163
fdd5ee5e 164 def putpm(self, data):
6fbab493
SB
165 e = self.samplenum_edge
166 self.put(self.ss_block, e, self.out_python, data)
fdd5ee5e
UH
167
168 def putm(self, data):
6fbab493
SB
169 e = self.samplenum_edge
170 self.put(self.ss_block, e, self.out_ann, data)
fdd5ee5e 171
d1970f14 172 def putpb(self, data):
6fbab493
SB
173 s, e = self.samplenum_lastedge, self.samplenum_edge
174 self.put(s, e, self.out_python, data)
d1970f14
UH
175
176 def putb(self, data):
6fbab493
SB
177 s, e = self.samplenum_lastedge, self.samplenum_edge
178 self.put(s, e, self.out_ann, data)
d1970f14
UH
179
180 def set_new_target_samplenum(self):
a241cfb6
SB
181 self.samplepos += self.bitwidth;
182 self.samplenum_target = int(self.samplepos)
6fbab493 183 self.samplenum_lastedge = self.samplenum_edge
a241cfb6 184 self.samplenum_edge = int(self.samplepos - (self.bitwidth / 2))
d1970f14
UH
185
186 def wait_for_sop(self, sym):
187 # Wait for a Start of Packet (SOP), i.e. a J->K symbol change.
13e81308 188 if sym != 'K' or self.oldsym != 'J':
d1970f14 189 return
033d6221 190 self.consecutive_ones = 0
519092e3 191 self.update_bitrate()
ce780be2 192 self.samplepos = self.samplenum - (self.bitwidth / 2) + 0.5
d1970f14
UH
193 self.set_new_target_samplenum()
194 self.putpx(['SOP', None])
85c03d60 195 self.putx([4, ['SOP', 'S']])
d1970f14
UH
196 self.state = 'GET BIT'
197
bef4949d 198 def handle_bit(self, b):
033d6221
SB
199 if self.consecutive_ones == 6:
200 if b == '0':
201 # Stuff bit.
202 self.putpb(['STUFF BIT', None])
203 self.putb([7, ['Stuff bit: 0', 'SB: 0', '0']])
204 self.consecutive_ones = 0
205 else:
206 self.putpb(['ERR', None])
207 self.putb([8, ['Bit stuff error', 'BS ERR', 'B']])
208 self.state = 'IDLE'
d1970f14 209 else:
9059125f 210 # Normal bit (not a stuff bit).
a56b8fe1 211 self.putpb(['BIT', b])
85c03d60 212 self.putb([6, ['%s' % b]])
d1970f14
UH
213 if b == '1':
214 self.consecutive_ones += 1
215 else:
216 self.consecutive_ones = 0
217
218 def get_eop(self, sym):
219 # EOP: SE0 for >= 1 bittime (usually 2 bittimes), then J.
6fbab493 220 self.set_new_target_samplenum()
d1970f14 221 self.putpb(['SYM', sym])
56cc44ff 222 self.putb(sym_annotation[sym])
d1970f14 223 self.oldsym = sym
bef4949d
SB
224 if sym == 'SE0':
225 pass
226 elif sym == 'J':
9059125f 227 # Got an EOP.
fdd5ee5e 228 self.putpm(['EOP', None])
85c03d60 229 self.putm([5, ['EOP', 'E']])
bef4949d 230 self.state = 'IDLE'
0f274b53
SB
231 else:
232 self.putpm(['ERR', None])
233 self.putm([8, ['EOP Error', 'EErr', 'E']])
234 self.state = 'IDLE'
d1970f14
UH
235
236 def get_bit(self, sym):
6fbab493 237 self.set_new_target_samplenum()
d1970f14 238 if sym == 'SE0':
bef4949d 239 # Start of an EOP. Change state, save edge
d1970f14 240 self.state = 'GET EOP'
6fbab493 241 self.ss_block = self.samplenum_lastedge
bef4949d
SB
242 else:
243 b = '0' if self.oldsym != sym else '1'
244 self.handle_bit(b)
d1970f14 245 self.putpb(['SYM', sym])
56cc44ff 246 self.putb(sym_annotation[sym])
64b45b20 247 if self.oldsym != sym:
519092e3 248 edgesym = symbols[self.signalling][tuple(self.edgepins)]
64b45b20
UH
249 if edgesym not in ('SE0', 'SE1'):
250 if edgesym == sym:
a241cfb6
SB
251 self.bitwidth = self.bitwidth - (0.001 * self.bitwidth)
252 self.samplepos = self.samplepos - (0.01 * self.bitwidth)
253 else:
254 self.bitwidth = self.bitwidth + (0.001 * self.bitwidth)
255 self.samplepos = self.samplepos + (0.01 * self.bitwidth)
d1970f14
UH
256 self.oldsym = sym
257
13e81308
SB
258 def handle_idle(self, sym):
259 self.samplenum_edge = self.samplenum
260 se0_length = float(self.samplenum - self.samplenum_lastedge) / self.samplerate
261 if se0_length > 2.5e-6: # 2.5us
262 self.putpb(['RESET', None])
263 self.putb([10, ['Reset', 'Res', 'R']])
519092e3
SB
264 self.signalling = self.options['signalling']
265 elif se0_length > 1.2e-6 and self.signalling == 'low-speed':
13e81308
SB
266 self.putpb(['KEEP ALIVE', None])
267 self.putb([9, ['Keep-alive', 'KA', 'A']])
519092e3
SB
268
269 if sym == 'FS_J':
270 self.signalling = 'full-speed'
271 self.update_bitrate()
272 elif sym == 'LS_J':
273 self.signalling = 'low-speed'
274 self.update_bitrate()
831d893d 275 self.oldsym = 'J'
13e81308
SB
276 self.state = 'IDLE'
277
2dc6d41c 278 def decode(self, ss, es, data):
21cda951
UH
279 if not self.samplerate:
280 raise SamplerateError('Cannot decode without samplerate.')
2fcd7c22 281 for (self.samplenum, pins) in data:
d1970f14
UH
282 # State machine.
283 if self.state == 'IDLE':
284 # Ignore identical samples early on (for performance reasons).
285 if self.oldpins == pins:
286 continue
287 self.oldpins = pins
519092e3 288 sym = symbols[self.signalling][tuple(pins)]
13e81308
SB
289 if sym == 'SE0':
290 self.samplenum_lastedge = self.samplenum
291 self.state = 'WAIT IDLE'
292 else:
293 self.wait_for_sop(sym)
a241cfb6 294 self.edgepins = pins
d1970f14
UH
295 elif self.state in ('GET BIT', 'GET EOP'):
296 # Wait until we're in the middle of the desired bit.
a241cfb6
SB
297 if self.samplenum == self.samplenum_edge:
298 self.edgepins = pins
d1970f14
UH
299 if self.samplenum < self.samplenum_target:
300 continue
519092e3 301 sym = symbols[self.signalling][tuple(pins)]
d1970f14
UH
302 if self.state == 'GET BIT':
303 self.get_bit(sym)
304 elif self.state == 'GET EOP':
305 self.get_eop(sym)
831d893d 306 self.oldpins = pins
13e81308 307 elif self.state == 'WAIT IDLE':
831d893d 308 if tuple(pins) == (0, 0):
13e81308 309 continue
13e81308 310 if self.samplenum - self.samplenum_lastedge > 1:
519092e3 311 sym = symbols[self.options['signalling']][tuple(pins)]
13e81308
SB
312 self.handle_idle(sym)
313 else:
519092e3 314 sym = symbols[self.signalling][tuple(pins)]
13e81308
SB
315 self.wait_for_sop(sym)
316 self.oldpins = pins
317 self.edgepins = pins
318 elif self.state == 'INIT':
319 sym = symbols[self.options['signalling']][tuple(pins)]
320 self.handle_idle(sym)
321 self.oldpins = pins