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