]> sigrok.org Git - libsigrokdecode.git/blame - decoders/usb_signalling/pd.py
usb_signalling: Move another edge detection to common backend code
[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'
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
a241cfb6 148 self.edgepins = None
d1970f14 149 self.consecutive_ones = 0
1647db06 150 self.bits = None
12c56703 151 self.state = 'IDLE'
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
502acfc2 203 self.bits = ''
519092e3 204 self.update_bitrate()
ce780be2 205 self.samplepos = self.samplenum - (self.bitwidth / 2) + 0.5
d1970f14
UH
206 self.set_new_target_samplenum()
207 self.putpx(['SOP', None])
85c03d60 208 self.putx([4, ['SOP', 'S']])
d1970f14
UH
209 self.state = 'GET BIT'
210
bef4949d 211 def handle_bit(self, b):
033d6221
SB
212 if self.consecutive_ones == 6:
213 if b == '0':
214 # Stuff bit.
215 self.putpb(['STUFF BIT', None])
216 self.putb([7, ['Stuff bit: 0', 'SB: 0', '0']])
217 self.consecutive_ones = 0
218 else:
219 self.putpb(['ERR', None])
220 self.putb([8, ['Bit stuff error', 'BS ERR', 'B']])
221 self.state = 'IDLE'
d1970f14 222 else:
9059125f 223 # Normal bit (not a stuff bit).
a56b8fe1 224 self.putpb(['BIT', b])
85c03d60 225 self.putb([6, ['%s' % b]])
d1970f14
UH
226 if b == '1':
227 self.consecutive_ones += 1
228 else:
229 self.consecutive_ones = 0
230
231 def get_eop(self, sym):
232 # EOP: SE0 for >= 1 bittime (usually 2 bittimes), then J.
6fbab493 233 self.set_new_target_samplenum()
d1970f14 234 self.putpb(['SYM', sym])
56cc44ff 235 self.putb(sym_annotation[sym])
d1970f14 236 self.oldsym = sym
bef4949d
SB
237 if sym == 'SE0':
238 pass
239 elif sym == 'J':
9059125f 240 # Got an EOP.
fdd5ee5e 241 self.putpm(['EOP', None])
85c03d60 242 self.putm([5, ['EOP', 'E']])
9821622a 243 self.state = 'WAIT IDLE'
0f274b53
SB
244 else:
245 self.putpm(['ERR', None])
246 self.putm([8, ['EOP Error', 'EErr', 'E']])
247 self.state = 'IDLE'
d1970f14
UH
248
249 def get_bit(self, sym):
6fbab493 250 self.set_new_target_samplenum()
1647db06
SB
251 b = '0' if self.oldsym != sym else '1'
252 self.oldsym = sym
d1970f14 253 if sym == 'SE0':
bef4949d 254 # Start of an EOP. Change state, save edge
d1970f14 255 self.state = 'GET EOP'
6fbab493 256 self.ss_block = self.samplenum_lastedge
bef4949d 257 else:
bef4949d 258 self.handle_bit(b)
d1970f14 259 self.putpb(['SYM', sym])
56cc44ff 260 self.putb(sym_annotation[sym])
1647db06
SB
261 if len(self.bits) <= 16:
262 self.bits += b
263 if len(self.bits) == 16 and self.bits == '0000000100111100':
264 # Sync and low-speed PREamble seen
265 self.putpx(['EOP', None])
266 self.state = 'IDLE'
267 self.signalling = 'low-speed-rp'
268 self.update_bitrate()
269 self.oldsym = 'J'
270 if b == '0':
519092e3 271 edgesym = symbols[self.signalling][tuple(self.edgepins)]
64b45b20
UH
272 if edgesym not in ('SE0', 'SE1'):
273 if edgesym == sym:
a241cfb6
SB
274 self.bitwidth = self.bitwidth - (0.001 * self.bitwidth)
275 self.samplepos = self.samplepos - (0.01 * self.bitwidth)
276 else:
277 self.bitwidth = self.bitwidth + (0.001 * self.bitwidth)
278 self.samplepos = self.samplepos + (0.01 * self.bitwidth)
d1970f14 279
13e81308
SB
280 def handle_idle(self, sym):
281 self.samplenum_edge = self.samplenum
282 se0_length = float(self.samplenum - self.samplenum_lastedge) / self.samplerate
283 if se0_length > 2.5e-6: # 2.5us
284 self.putpb(['RESET', None])
285 self.putb([10, ['Reset', 'Res', 'R']])
519092e3
SB
286 self.signalling = self.options['signalling']
287 elif se0_length > 1.2e-6 and self.signalling == 'low-speed':
13e81308
SB
288 self.putpb(['KEEP ALIVE', None])
289 self.putb([9, ['Keep-alive', 'KA', 'A']])
519092e3
SB
290
291 if sym == 'FS_J':
292 self.signalling = 'full-speed'
293 self.update_bitrate()
294 elif sym == 'LS_J':
295 self.signalling = 'low-speed'
296 self.update_bitrate()
831d893d 297 self.oldsym = 'J'
13e81308
SB
298 self.state = 'IDLE'
299
12c56703 300 def decode(self):
21cda951
UH
301 if not self.samplerate:
302 raise SamplerateError('Cannot decode without samplerate.')
12c56703
UH
303
304 # Seed internal state from the very first sample.
305 pins = self.wait({'skip': 1})
306 sym = symbols[self.options['signalling']][pins]
307 self.handle_idle(sym)
308
309 while True:
d1970f14
UH
310 # State machine.
311 if self.state == 'IDLE':
12c56703
UH
312 # Wait for any edge on either DP and/or DM.
313 pins = self.wait([{0: 'e'}, {1: 'e'}])
314 sym = symbols[self.signalling][pins]
13e81308
SB
315 if sym == 'SE0':
316 self.samplenum_lastedge = self.samplenum
317 self.state = 'WAIT IDLE'
318 else:
319 self.wait_for_sop(sym)
a241cfb6 320 self.edgepins = pins
d1970f14
UH
321 elif self.state in ('GET BIT', 'GET EOP'):
322 # Wait until we're in the middle of the desired bit.
12c56703
UH
323 self.edgepins = self.wait([{'skip': self.samplenum_edge - self.samplenum}])
324 pins = self.wait([{'skip': self.samplenum_target - self.samplenum}])
325
326 sym = symbols[self.signalling][pins]
d1970f14
UH
327 if self.state == 'GET BIT':
328 self.get_bit(sym)
329 elif self.state == 'GET EOP':
330 self.get_eop(sym)
13e81308 331 elif self.state == 'WAIT IDLE':
c240da48 332 # Skip "all-low" input. Wait for high level on either DP or DM.
12c56703 333 pins = self.wait({'skip': 1})
c240da48
GS
334 while not pins[0] and not pins[1]:
335 pins = self.wait([{0: 'h'}, {1: 'h'}])
13e81308 336 if self.samplenum - self.samplenum_lastedge > 1:
12c56703 337 sym = symbols[self.options['signalling']][pins]
13e81308
SB
338 self.handle_idle(sym)
339 else:
12c56703 340 sym = symbols[self.signalling][pins]
13e81308 341 self.wait_for_sop(sym)
13e81308 342 self.edgepins = pins