]> sigrok.org Git - libsigrokdecode.git/blame - decoders/usb_signalling/pd.py
usb*: Minor cosmetics.
[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 },
502acfc2
UH
72 # After a PREamble PID, the bus segment between Host and Hub uses LS
73 # signalling rate and FS signalling polarity (USB 2.0 spec, 11.8.4: "For
74 # both upstream and downstream low-speed data, the hub is responsible for
75 # inverting the polarity of the data before transmitting to/from a
76 # low-speed port.").
9821622a
SB
77 'low-speed-rp': {
78 # (<dp>, <dm>): <symbol/state>
79 (0, 0): 'SE0',
80 (1, 0): 'J',
81 (0, 1): 'K',
82 (1, 1): 'SE1',
83 },
2dc6d41c
UH
84}
85
5bb55598 86bitrates = {
502acfc2
UH
87 'low-speed': 1500000, # 1.5Mb/s (+/- 1.5%)
88 'low-speed-rp': 1500000, # 1.5Mb/s (+/- 1.5%)
5bb55598 89 'full-speed': 12000000, # 12Mb/s (+/- 0.25%)
519092e3 90 'automatic': None
5bb55598
UH
91}
92
56cc44ff
SB
93sym_annotation = {
94 'J': [0, ['J']],
95 'K': [1, ['K']],
96 'SE0': [2, ['SE0', '0']],
97 'SE1': [3, ['SE1', '1']],
85c03d60
UH
98}
99
21cda951
UH
100class SamplerateError(Exception):
101 pass
102
2dc6d41c 103class Decoder(srd.Decoder):
12851357 104 api_version = 2
2dc6d41c
UH
105 id = 'usb_signalling'
106 name = 'USB signalling'
107 longname = 'Universal Serial Bus (LS/FS) signalling'
9e1437a0 108 desc = 'USB (low-speed and full-speed) signalling protocol.'
2dc6d41c
UH
109 license = 'gplv2+'
110 inputs = ['logic']
111 outputs = ['usb_signalling']
6a15597a 112 channels = (
2dc6d41c
UH
113 {'id': 'dp', 'name': 'D+', 'desc': 'USB D+ signal'},
114 {'id': 'dm', 'name': 'D-', 'desc': 'USB D- signal'},
da9bcbd9 115 )
84c1c0b5
BV
116 options = (
117 {'id': 'signalling', 'desc': 'Signalling',
519092e3 118 'default': 'automatic', 'values': ('automatic', 'full-speed', 'low-speed')},
84c1c0b5 119 )
da9bcbd9 120 annotations = (
85c03d60
UH
121 ('sym-j', 'J symbol'),
122 ('sym-k', 'K symbol'),
123 ('sym-se0', 'SE0 symbol'),
124 ('sym-se1', 'SE1 symbol'),
da9bcbd9
BV
125 ('sop', 'Start of packet (SOP)'),
126 ('eop', 'End of packet (EOP)'),
127 ('bit', 'Bit'),
128 ('stuffbit', 'Stuff bit'),
033d6221 129 ('error', 'Error'),
13e81308
SB
130 ('keep-alive', 'Low-speed keep-alive'),
131 ('reset', 'Reset'),
da9bcbd9 132 )
066d6594 133 annotation_rows = (
13e81308 134 ('bits', 'Bits', (4, 5, 6, 7, 8, 9, 10)),
85c03d60 135 ('symbols', 'Symbols', (0, 1, 2, 3)),
066d6594 136 )
2dc6d41c
UH
137
138 def __init__(self):
f372d597 139 self.samplerate = None
d1970f14 140 self.oldsym = 'J' # The "idle" state is J.
fdd5ee5e 141 self.ss_block = None
2dc6d41c 142 self.samplenum = 0
5bb55598
UH
143 self.bitrate = None
144 self.bitwidth = None
a241cfb6 145 self.samplepos = None
d1970f14 146 self.samplenum_target = None
a241cfb6 147 self.samplenum_edge = None
6fbab493 148 self.samplenum_lastedge = 0
2fcd7c22 149 self.oldpins = None
a241cfb6 150 self.edgepins = None
d1970f14 151 self.consecutive_ones = 0
1647db06 152 self.bits = None
13e81308 153 self.state = 'INIT'
2dc6d41c 154
f372d597 155 def start(self):
c515eed7 156 self.out_python = self.register(srd.OUTPUT_PYTHON)
be465111 157 self.out_ann = self.register(srd.OUTPUT_ANN)
f372d597
BV
158
159 def metadata(self, key, value):
160 if key == srd.SRD_CONF_SAMPLERATE:
161 self.samplerate = value
519092e3
SB
162 self.signalling = self.options['signalling']
163 if self.signalling != 'automatic':
164 self.update_bitrate()
165
166 def update_bitrate(self):
167 self.bitrate = bitrates[self.signalling]
168 self.bitwidth = float(self.samplerate) / float(self.bitrate)
2dc6d41c 169
d1970f14 170 def putpx(self, data):
6fbab493
SB
171 s = self.samplenum_edge
172 self.put(s, s, self.out_python, data)
7d4b5fac
UH
173
174 def putx(self, data):
6fbab493
SB
175 s = self.samplenum_edge
176 self.put(s, s, self.out_ann, data)
7d4b5fac 177
fdd5ee5e 178 def putpm(self, data):
6fbab493
SB
179 e = self.samplenum_edge
180 self.put(self.ss_block, e, self.out_python, data)
fdd5ee5e
UH
181
182 def putm(self, data):
6fbab493
SB
183 e = self.samplenum_edge
184 self.put(self.ss_block, e, self.out_ann, data)
fdd5ee5e 185
d1970f14 186 def putpb(self, data):
6fbab493
SB
187 s, e = self.samplenum_lastedge, self.samplenum_edge
188 self.put(s, e, self.out_python, data)
d1970f14
UH
189
190 def putb(self, data):
6fbab493
SB
191 s, e = self.samplenum_lastedge, self.samplenum_edge
192 self.put(s, e, self.out_ann, data)
d1970f14
UH
193
194 def set_new_target_samplenum(self):
a241cfb6
SB
195 self.samplepos += self.bitwidth;
196 self.samplenum_target = int(self.samplepos)
6fbab493 197 self.samplenum_lastedge = self.samplenum_edge
a241cfb6 198 self.samplenum_edge = int(self.samplepos - (self.bitwidth / 2))
d1970f14
UH
199
200 def wait_for_sop(self, sym):
201 # Wait for a Start of Packet (SOP), i.e. a J->K symbol change.
13e81308 202 if sym != 'K' or self.oldsym != 'J':
d1970f14 203 return
033d6221 204 self.consecutive_ones = 0
502acfc2 205 self.bits = ''
519092e3 206 self.update_bitrate()
ce780be2 207 self.samplepos = self.samplenum - (self.bitwidth / 2) + 0.5
d1970f14
UH
208 self.set_new_target_samplenum()
209 self.putpx(['SOP', None])
85c03d60 210 self.putx([4, ['SOP', 'S']])
d1970f14
UH
211 self.state = 'GET BIT'
212
bef4949d 213 def handle_bit(self, b):
033d6221
SB
214 if self.consecutive_ones == 6:
215 if b == '0':
216 # Stuff bit.
217 self.putpb(['STUFF BIT', None])
218 self.putb([7, ['Stuff bit: 0', 'SB: 0', '0']])
219 self.consecutive_ones = 0
220 else:
221 self.putpb(['ERR', None])
222 self.putb([8, ['Bit stuff error', 'BS ERR', 'B']])
223 self.state = 'IDLE'
d1970f14 224 else:
9059125f 225 # Normal bit (not a stuff bit).
a56b8fe1 226 self.putpb(['BIT', b])
85c03d60 227 self.putb([6, ['%s' % b]])
d1970f14
UH
228 if b == '1':
229 self.consecutive_ones += 1
230 else:
231 self.consecutive_ones = 0
232
233 def get_eop(self, sym):
234 # EOP: SE0 for >= 1 bittime (usually 2 bittimes), then J.
6fbab493 235 self.set_new_target_samplenum()
d1970f14 236 self.putpb(['SYM', sym])
56cc44ff 237 self.putb(sym_annotation[sym])
d1970f14 238 self.oldsym = sym
bef4949d
SB
239 if sym == 'SE0':
240 pass
241 elif sym == 'J':
9059125f 242 # Got an EOP.
fdd5ee5e 243 self.putpm(['EOP', None])
85c03d60 244 self.putm([5, ['EOP', 'E']])
9821622a 245 self.state = 'WAIT IDLE'
0f274b53
SB
246 else:
247 self.putpm(['ERR', None])
248 self.putm([8, ['EOP Error', 'EErr', 'E']])
249 self.state = 'IDLE'
d1970f14
UH
250
251 def get_bit(self, sym):
6fbab493 252 self.set_new_target_samplenum()
1647db06
SB
253 b = '0' if self.oldsym != sym else '1'
254 self.oldsym = sym
d1970f14 255 if sym == 'SE0':
bef4949d 256 # Start of an EOP. Change state, save edge
d1970f14 257 self.state = 'GET EOP'
6fbab493 258 self.ss_block = self.samplenum_lastedge
bef4949d 259 else:
bef4949d 260 self.handle_bit(b)
d1970f14 261 self.putpb(['SYM', sym])
56cc44ff 262 self.putb(sym_annotation[sym])
1647db06
SB
263 if len(self.bits) <= 16:
264 self.bits += b
265 if len(self.bits) == 16 and self.bits == '0000000100111100':
266 # Sync and low-speed PREamble seen
267 self.putpx(['EOP', None])
268 self.state = 'IDLE'
269 self.signalling = 'low-speed-rp'
270 self.update_bitrate()
271 self.oldsym = 'J'
272 if b == '0':
519092e3 273 edgesym = symbols[self.signalling][tuple(self.edgepins)]
64b45b20
UH
274 if edgesym not in ('SE0', 'SE1'):
275 if edgesym == sym:
a241cfb6
SB
276 self.bitwidth = self.bitwidth - (0.001 * self.bitwidth)
277 self.samplepos = self.samplepos - (0.01 * self.bitwidth)
278 else:
279 self.bitwidth = self.bitwidth + (0.001 * self.bitwidth)
280 self.samplepos = self.samplepos + (0.01 * self.bitwidth)
d1970f14 281
13e81308
SB
282 def handle_idle(self, sym):
283 self.samplenum_edge = self.samplenum
284 se0_length = float(self.samplenum - self.samplenum_lastedge) / self.samplerate
285 if se0_length > 2.5e-6: # 2.5us
286 self.putpb(['RESET', None])
287 self.putb([10, ['Reset', 'Res', 'R']])
519092e3
SB
288 self.signalling = self.options['signalling']
289 elif se0_length > 1.2e-6 and self.signalling == 'low-speed':
13e81308
SB
290 self.putpb(['KEEP ALIVE', None])
291 self.putb([9, ['Keep-alive', 'KA', 'A']])
519092e3
SB
292
293 if sym == 'FS_J':
294 self.signalling = 'full-speed'
295 self.update_bitrate()
296 elif sym == 'LS_J':
297 self.signalling = 'low-speed'
298 self.update_bitrate()
831d893d 299 self.oldsym = 'J'
13e81308
SB
300 self.state = 'IDLE'
301
2dc6d41c 302 def decode(self, ss, es, data):
21cda951
UH
303 if not self.samplerate:
304 raise SamplerateError('Cannot decode without samplerate.')
2fcd7c22 305 for (self.samplenum, pins) in data:
d1970f14
UH
306 # State machine.
307 if self.state == 'IDLE':
308 # Ignore identical samples early on (for performance reasons).
309 if self.oldpins == pins:
310 continue
311 self.oldpins = pins
519092e3 312 sym = symbols[self.signalling][tuple(pins)]
13e81308
SB
313 if sym == 'SE0':
314 self.samplenum_lastedge = self.samplenum
315 self.state = 'WAIT IDLE'
316 else:
317 self.wait_for_sop(sym)
a241cfb6 318 self.edgepins = pins
d1970f14
UH
319 elif self.state in ('GET BIT', 'GET EOP'):
320 # Wait until we're in the middle of the desired bit.
a241cfb6
SB
321 if self.samplenum == self.samplenum_edge:
322 self.edgepins = pins
d1970f14
UH
323 if self.samplenum < self.samplenum_target:
324 continue
519092e3 325 sym = symbols[self.signalling][tuple(pins)]
d1970f14
UH
326 if self.state == 'GET BIT':
327 self.get_bit(sym)
328 elif self.state == 'GET EOP':
329 self.get_eop(sym)
831d893d 330 self.oldpins = pins
13e81308 331 elif self.state == 'WAIT IDLE':
831d893d 332 if tuple(pins) == (0, 0):
13e81308 333 continue
13e81308 334 if self.samplenum - self.samplenum_lastedge > 1:
519092e3 335 sym = symbols[self.options['signalling']][tuple(pins)]
13e81308
SB
336 self.handle_idle(sym)
337 else:
519092e3 338 sym = symbols[self.signalling][tuple(pins)]
13e81308
SB
339 self.wait_for_sop(sym)
340 self.oldpins = pins
341 self.edgepins = pins
342 elif self.state == 'INIT':
343 sym = symbols[self.options['signalling']][tuple(pins)]
344 self.handle_idle(sym)
345 self.oldpins = pins