]> sigrok.org Git - libsigrokdecode.git/blame - decoders/usb_signalling/pd.py
decoders: Various cosmetic/consistency/typo fixes.
[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
4539e9ca 18## along with this program; if not, see <http://www.gnu.org/licenses/>.
2dc6d41c
UH
19##
20
2dc6d41c
UH
21import sigrokdecode as srd
22
a56b8fe1 23'''
c515eed7 24OUTPUT_PYTHON format:
a56b8fe1
UH
25
26Packet:
27[<ptype>, <pdata>]
28
29<ptype>, <pdata>:
30 - 'SOP', None
31 - 'SYM', <sym>
32 - 'BIT', <bit>
33 - 'STUFF BIT', None
34 - 'EOP', None
033d6221 35 - 'ERR', None
13e81308
SB
36 - 'KEEP ALIVE', None
37 - 'RESET', None
a56b8fe1
UH
38
39<sym>:
40 - 'J', 'K', 'SE0', or 'SE1'
41
42<bit>:
033d6221 43 - '0' or '1'
a56b8fe1 44 - Note: Symbols like SE0, SE1, and the J that's part of EOP don't yield 'BIT'.
a56b8fe1
UH
45'''
46
d1970f14 47# Low-/full-speed symbols.
2dc6d41c 48# Note: Low-speed J and K are inverted compared to the full-speed J and K!
7dc75721
UH
49symbols = {
50 'low-speed': {
2dc6d41c
UH
51 # (<dp>, <dm>): <symbol/state>
52 (0, 0): 'SE0',
53 (1, 0): 'K',
54 (0, 1): 'J',
55 (1, 1): 'SE1',
7dc75721
UH
56 },
57 'full-speed': {
2dc6d41c
UH
58 # (<dp>, <dm>): <symbol/state>
59 (0, 0): 'SE0',
60 (1, 0): 'J',
61 (0, 1): 'K',
62 (1, 1): 'SE1',
7dc75721 63 },
519092e3
SB
64 'automatic': {
65 # (<dp>, <dm>): <symbol/state>
66 (0, 0): 'SE0',
67 (1, 0): 'FS_J',
68 (0, 1): 'LS_J',
69 (1, 1): 'SE1',
70 },
502acfc2
UH
71 # After a PREamble PID, the bus segment between Host and Hub uses LS
72 # signalling rate and FS signalling polarity (USB 2.0 spec, 11.8.4: "For
73 # both upstream and downstream low-speed data, the hub is responsible for
74 # inverting the polarity of the data before transmitting to/from a
75 # low-speed port.").
9821622a
SB
76 'low-speed-rp': {
77 # (<dp>, <dm>): <symbol/state>
78 (0, 0): 'SE0',
79 (1, 0): 'J',
80 (0, 1): 'K',
81 (1, 1): 'SE1',
82 },
2dc6d41c
UH
83}
84
5bb55598 85bitrates = {
502acfc2
UH
86 'low-speed': 1500000, # 1.5Mb/s (+/- 1.5%)
87 'low-speed-rp': 1500000, # 1.5Mb/s (+/- 1.5%)
5bb55598 88 'full-speed': 12000000, # 12Mb/s (+/- 0.25%)
519092e3 89 'automatic': None
5bb55598
UH
90}
91
56cc44ff
SB
92sym_annotation = {
93 'J': [0, ['J']],
94 'K': [1, ['K']],
95 'SE0': [2, ['SE0', '0']],
96 'SE1': [3, ['SE1', '1']],
85c03d60
UH
97}
98
21cda951
UH
99class SamplerateError(Exception):
100 pass
101
2dc6d41c 102class Decoder(srd.Decoder):
12c56703 103 api_version = 3
2dc6d41c
UH
104 id = 'usb_signalling'
105 name = 'USB signalling'
106 longname = 'Universal Serial Bus (LS/FS) signalling'
2787cf2a 107 desc = 'USB (low-speed/full-speed) signalling protocol.'
2dc6d41c
UH
108 license = 'gplv2+'
109 inputs = ['logic']
110 outputs = ['usb_signalling']
d6d8a8a4 111 tags = ['PC']
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):
10aeb8ea
GS
139 self.reset()
140
141 def reset(self):
f372d597 142 self.samplerate = None
d1970f14 143 self.oldsym = 'J' # The "idle" state is J.
fdd5ee5e 144 self.ss_block = None
2dc6d41c 145 self.samplenum = 0
5bb55598
UH
146 self.bitrate = None
147 self.bitwidth = None
a241cfb6 148 self.samplepos = None
d1970f14 149 self.samplenum_target = None
a241cfb6 150 self.samplenum_edge = None
6fbab493 151 self.samplenum_lastedge = 0
a241cfb6 152 self.edgepins = None
d1970f14 153 self.consecutive_ones = 0
1647db06 154 self.bits = None
12c56703 155 self.state = 'IDLE'
2dc6d41c 156
f372d597 157 def start(self):
c515eed7 158 self.out_python = self.register(srd.OUTPUT_PYTHON)
be465111 159 self.out_ann = self.register(srd.OUTPUT_ANN)
f372d597
BV
160
161 def metadata(self, key, value):
162 if key == srd.SRD_CONF_SAMPLERATE:
163 self.samplerate = value
519092e3
SB
164 self.signalling = self.options['signalling']
165 if self.signalling != 'automatic':
166 self.update_bitrate()
167
168 def update_bitrate(self):
169 self.bitrate = bitrates[self.signalling]
170 self.bitwidth = float(self.samplerate) / float(self.bitrate)
2dc6d41c 171
d1970f14 172 def putpx(self, data):
6fbab493
SB
173 s = self.samplenum_edge
174 self.put(s, s, self.out_python, data)
7d4b5fac
UH
175
176 def putx(self, data):
6fbab493
SB
177 s = self.samplenum_edge
178 self.put(s, s, self.out_ann, data)
7d4b5fac 179
fdd5ee5e 180 def putpm(self, data):
6fbab493
SB
181 e = self.samplenum_edge
182 self.put(self.ss_block, e, self.out_python, data)
fdd5ee5e
UH
183
184 def putm(self, data):
6fbab493
SB
185 e = self.samplenum_edge
186 self.put(self.ss_block, e, self.out_ann, data)
fdd5ee5e 187
d1970f14 188 def putpb(self, data):
6fbab493
SB
189 s, e = self.samplenum_lastedge, self.samplenum_edge
190 self.put(s, e, self.out_python, data)
d1970f14
UH
191
192 def putb(self, data):
6fbab493
SB
193 s, e = self.samplenum_lastedge, self.samplenum_edge
194 self.put(s, e, self.out_ann, data)
d1970f14
UH
195
196 def set_new_target_samplenum(self):
f78b814d 197 self.samplepos += self.bitwidth
a241cfb6 198 self.samplenum_target = int(self.samplepos)
6fbab493 199 self.samplenum_lastedge = self.samplenum_edge
a241cfb6 200 self.samplenum_edge = int(self.samplepos - (self.bitwidth / 2))
d1970f14
UH
201
202 def wait_for_sop(self, sym):
203 # Wait for a Start of Packet (SOP), i.e. a J->K symbol change.
13e81308 204 if sym != 'K' or self.oldsym != 'J':
d1970f14 205 return
033d6221 206 self.consecutive_ones = 0
502acfc2 207 self.bits = ''
519092e3 208 self.update_bitrate()
ce780be2 209 self.samplepos = self.samplenum - (self.bitwidth / 2) + 0.5
d1970f14
UH
210 self.set_new_target_samplenum()
211 self.putpx(['SOP', None])
85c03d60 212 self.putx([4, ['SOP', 'S']])
d1970f14
UH
213 self.state = 'GET BIT'
214
bef4949d 215 def handle_bit(self, b):
033d6221
SB
216 if self.consecutive_ones == 6:
217 if b == '0':
218 # Stuff bit.
219 self.putpb(['STUFF BIT', None])
220 self.putb([7, ['Stuff bit: 0', 'SB: 0', '0']])
221 self.consecutive_ones = 0
222 else:
223 self.putpb(['ERR', None])
224 self.putb([8, ['Bit stuff error', 'BS ERR', 'B']])
225 self.state = 'IDLE'
d1970f14 226 else:
9059125f 227 # Normal bit (not a stuff bit).
a56b8fe1 228 self.putpb(['BIT', b])
85c03d60 229 self.putb([6, ['%s' % b]])
d1970f14
UH
230 if b == '1':
231 self.consecutive_ones += 1
232 else:
233 self.consecutive_ones = 0
234
235 def get_eop(self, sym):
236 # EOP: SE0 for >= 1 bittime (usually 2 bittimes), then J.
6fbab493 237 self.set_new_target_samplenum()
d1970f14 238 self.putpb(['SYM', sym])
56cc44ff 239 self.putb(sym_annotation[sym])
d1970f14 240 self.oldsym = sym
bef4949d
SB
241 if sym == 'SE0':
242 pass
243 elif sym == 'J':
9059125f 244 # Got an EOP.
fdd5ee5e 245 self.putpm(['EOP', None])
85c03d60 246 self.putm([5, ['EOP', 'E']])
9821622a 247 self.state = 'WAIT IDLE'
0f274b53
SB
248 else:
249 self.putpm(['ERR', None])
250 self.putm([8, ['EOP Error', 'EErr', 'E']])
251 self.state = 'IDLE'
d1970f14
UH
252
253 def get_bit(self, sym):
6fbab493 254 self.set_new_target_samplenum()
1647db06
SB
255 b = '0' if self.oldsym != sym else '1'
256 self.oldsym = sym
d1970f14 257 if sym == 'SE0':
bef4949d 258 # Start of an EOP. Change state, save edge
d1970f14 259 self.state = 'GET EOP'
6fbab493 260 self.ss_block = self.samplenum_lastedge
bef4949d 261 else:
bef4949d 262 self.handle_bit(b)
d1970f14 263 self.putpb(['SYM', sym])
56cc44ff 264 self.putb(sym_annotation[sym])
1647db06
SB
265 if len(self.bits) <= 16:
266 self.bits += b
267 if len(self.bits) == 16 and self.bits == '0000000100111100':
268 # Sync and low-speed PREamble seen
269 self.putpx(['EOP', None])
270 self.state = 'IDLE'
271 self.signalling = 'low-speed-rp'
272 self.update_bitrate()
273 self.oldsym = 'J'
274 if b == '0':
519092e3 275 edgesym = symbols[self.signalling][tuple(self.edgepins)]
64b45b20
UH
276 if edgesym not in ('SE0', 'SE1'):
277 if edgesym == sym:
a241cfb6
SB
278 self.bitwidth = self.bitwidth - (0.001 * self.bitwidth)
279 self.samplepos = self.samplepos - (0.01 * self.bitwidth)
280 else:
281 self.bitwidth = self.bitwidth + (0.001 * self.bitwidth)
282 self.samplepos = self.samplepos + (0.01 * self.bitwidth)
d1970f14 283
13e81308
SB
284 def handle_idle(self, sym):
285 self.samplenum_edge = self.samplenum
286 se0_length = float(self.samplenum - self.samplenum_lastedge) / self.samplerate
287 if se0_length > 2.5e-6: # 2.5us
288 self.putpb(['RESET', None])
289 self.putb([10, ['Reset', 'Res', 'R']])
519092e3
SB
290 self.signalling = self.options['signalling']
291 elif se0_length > 1.2e-6 and self.signalling == 'low-speed':
13e81308
SB
292 self.putpb(['KEEP ALIVE', None])
293 self.putb([9, ['Keep-alive', 'KA', 'A']])
519092e3
SB
294
295 if sym == 'FS_J':
296 self.signalling = 'full-speed'
297 self.update_bitrate()
298 elif sym == 'LS_J':
299 self.signalling = 'low-speed'
300 self.update_bitrate()
831d893d 301 self.oldsym = 'J'
13e81308
SB
302 self.state = 'IDLE'
303
12c56703 304 def decode(self):
21cda951
UH
305 if not self.samplerate:
306 raise SamplerateError('Cannot decode without samplerate.')
12c56703
UH
307
308 # Seed internal state from the very first sample.
1b9ef18b 309 pins = self.wait()
12c56703
UH
310 sym = symbols[self.options['signalling']][pins]
311 self.handle_idle(sym)
312
313 while True:
d1970f14
UH
314 # State machine.
315 if self.state == 'IDLE':
12c56703
UH
316 # Wait for any edge on either DP and/or DM.
317 pins = self.wait([{0: 'e'}, {1: 'e'}])
318 sym = symbols[self.signalling][pins]
13e81308
SB
319 if sym == 'SE0':
320 self.samplenum_lastedge = self.samplenum
321 self.state = 'WAIT IDLE'
322 else:
323 self.wait_for_sop(sym)
a241cfb6 324 self.edgepins = pins
d1970f14
UH
325 elif self.state in ('GET BIT', 'GET EOP'):
326 # Wait until we're in the middle of the desired bit.
12c56703
UH
327 self.edgepins = self.wait([{'skip': self.samplenum_edge - self.samplenum}])
328 pins = self.wait([{'skip': self.samplenum_target - self.samplenum}])
329
330 sym = symbols[self.signalling][pins]
d1970f14
UH
331 if self.state == 'GET BIT':
332 self.get_bit(sym)
333 elif self.state == 'GET EOP':
334 self.get_eop(sym)
13e81308 335 elif self.state == 'WAIT IDLE':
c240da48 336 # Skip "all-low" input. Wait for high level on either DP or DM.
1b9ef18b 337 pins = self.wait()
c240da48
GS
338 while not pins[0] and not pins[1]:
339 pins = self.wait([{0: 'h'}, {1: 'h'}])
13e81308 340 if self.samplenum - self.samplenum_lastedge > 1:
12c56703 341 sym = symbols[self.options['signalling']][pins]
13e81308
SB
342 self.handle_idle(sym)
343 else:
12c56703 344 sym = symbols[self.signalling][pins]
13e81308 345 self.wait_for_sop(sym)
13e81308 346 self.edgepins = pins