]> sigrok.org Git - libsigrokdecode.git/blame - decoders/usb_signalling/pd.py
license: remove FSF postal address from boiler plate license text
[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):
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
1647db06 151 self.bits = None
13e81308 152 self.state = 'INIT'
2dc6d41c 153
f372d597 154 def start(self):
c515eed7 155 self.out_python = self.register(srd.OUTPUT_PYTHON)
be465111 156 self.out_ann = self.register(srd.OUTPUT_ANN)
f372d597
BV
157
158 def metadata(self, key, value):
159 if key == srd.SRD_CONF_SAMPLERATE:
160 self.samplerate = value
519092e3
SB
161 self.signalling = self.options['signalling']
162 if self.signalling != 'automatic':
163 self.update_bitrate()
164
165 def update_bitrate(self):
166 self.bitrate = bitrates[self.signalling]
167 self.bitwidth = float(self.samplerate) / float(self.bitrate)
2dc6d41c 168
d1970f14 169 def putpx(self, data):
6fbab493
SB
170 s = self.samplenum_edge
171 self.put(s, s, self.out_python, data)
7d4b5fac
UH
172
173 def putx(self, data):
6fbab493
SB
174 s = self.samplenum_edge
175 self.put(s, s, self.out_ann, data)
7d4b5fac 176
fdd5ee5e 177 def putpm(self, data):
6fbab493
SB
178 e = self.samplenum_edge
179 self.put(self.ss_block, e, self.out_python, data)
fdd5ee5e
UH
180
181 def putm(self, data):
6fbab493
SB
182 e = self.samplenum_edge
183 self.put(self.ss_block, e, self.out_ann, data)
fdd5ee5e 184
d1970f14 185 def putpb(self, data):
6fbab493
SB
186 s, e = self.samplenum_lastedge, self.samplenum_edge
187 self.put(s, e, self.out_python, data)
d1970f14
UH
188
189 def putb(self, data):
6fbab493
SB
190 s, e = self.samplenum_lastedge, self.samplenum_edge
191 self.put(s, e, self.out_ann, data)
d1970f14
UH
192
193 def set_new_target_samplenum(self):
a241cfb6
SB
194 self.samplepos += self.bitwidth;
195 self.samplenum_target = int(self.samplepos)
6fbab493 196 self.samplenum_lastedge = self.samplenum_edge
a241cfb6 197 self.samplenum_edge = int(self.samplepos - (self.bitwidth / 2))
d1970f14
UH
198
199 def wait_for_sop(self, sym):
200 # Wait for a Start of Packet (SOP), i.e. a J->K symbol change.
13e81308 201 if sym != 'K' or self.oldsym != 'J':
d1970f14 202 return
033d6221 203 self.consecutive_ones = 0
502acfc2 204 self.bits = ''
519092e3 205 self.update_bitrate()
ce780be2 206 self.samplepos = self.samplenum - (self.bitwidth / 2) + 0.5
d1970f14
UH
207 self.set_new_target_samplenum()
208 self.putpx(['SOP', None])
85c03d60 209 self.putx([4, ['SOP', 'S']])
d1970f14
UH
210 self.state = 'GET BIT'
211
bef4949d 212 def handle_bit(self, b):
033d6221
SB
213 if self.consecutive_ones == 6:
214 if b == '0':
215 # Stuff bit.
216 self.putpb(['STUFF BIT', None])
217 self.putb([7, ['Stuff bit: 0', 'SB: 0', '0']])
218 self.consecutive_ones = 0
219 else:
220 self.putpb(['ERR', None])
221 self.putb([8, ['Bit stuff error', 'BS ERR', 'B']])
222 self.state = 'IDLE'
d1970f14 223 else:
9059125f 224 # Normal bit (not a stuff bit).
a56b8fe1 225 self.putpb(['BIT', b])
85c03d60 226 self.putb([6, ['%s' % b]])
d1970f14
UH
227 if b == '1':
228 self.consecutive_ones += 1
229 else:
230 self.consecutive_ones = 0
231
232 def get_eop(self, sym):
233 # EOP: SE0 for >= 1 bittime (usually 2 bittimes), then J.
6fbab493 234 self.set_new_target_samplenum()
d1970f14 235 self.putpb(['SYM', sym])
56cc44ff 236 self.putb(sym_annotation[sym])
d1970f14 237 self.oldsym = sym
bef4949d
SB
238 if sym == 'SE0':
239 pass
240 elif sym == 'J':
9059125f 241 # Got an EOP.
fdd5ee5e 242 self.putpm(['EOP', None])
85c03d60 243 self.putm([5, ['EOP', 'E']])
9821622a 244 self.state = 'WAIT IDLE'
0f274b53
SB
245 else:
246 self.putpm(['ERR', None])
247 self.putm([8, ['EOP Error', 'EErr', 'E']])
248 self.state = 'IDLE'
d1970f14
UH
249
250 def get_bit(self, sym):
6fbab493 251 self.set_new_target_samplenum()
1647db06
SB
252 b = '0' if self.oldsym != sym else '1'
253 self.oldsym = sym
d1970f14 254 if sym == 'SE0':
bef4949d 255 # Start of an EOP. Change state, save edge
d1970f14 256 self.state = 'GET EOP'
6fbab493 257 self.ss_block = self.samplenum_lastedge
bef4949d 258 else:
bef4949d 259 self.handle_bit(b)
d1970f14 260 self.putpb(['SYM', sym])
56cc44ff 261 self.putb(sym_annotation[sym])
1647db06
SB
262 if len(self.bits) <= 16:
263 self.bits += b
264 if len(self.bits) == 16 and self.bits == '0000000100111100':
265 # Sync and low-speed PREamble seen
266 self.putpx(['EOP', None])
267 self.state = 'IDLE'
268 self.signalling = 'low-speed-rp'
269 self.update_bitrate()
270 self.oldsym = 'J'
271 if b == '0':
519092e3 272 edgesym = symbols[self.signalling][tuple(self.edgepins)]
64b45b20
UH
273 if edgesym not in ('SE0', 'SE1'):
274 if edgesym == sym:
a241cfb6
SB
275 self.bitwidth = self.bitwidth - (0.001 * self.bitwidth)
276 self.samplepos = self.samplepos - (0.01 * self.bitwidth)
277 else:
278 self.bitwidth = self.bitwidth + (0.001 * self.bitwidth)
279 self.samplepos = self.samplepos + (0.01 * self.bitwidth)
d1970f14 280
13e81308
SB
281 def handle_idle(self, sym):
282 self.samplenum_edge = self.samplenum
283 se0_length = float(self.samplenum - self.samplenum_lastedge) / self.samplerate
284 if se0_length > 2.5e-6: # 2.5us
285 self.putpb(['RESET', None])
286 self.putb([10, ['Reset', 'Res', 'R']])
519092e3
SB
287 self.signalling = self.options['signalling']
288 elif se0_length > 1.2e-6 and self.signalling == 'low-speed':
13e81308
SB
289 self.putpb(['KEEP ALIVE', None])
290 self.putb([9, ['Keep-alive', 'KA', 'A']])
519092e3
SB
291
292 if sym == 'FS_J':
293 self.signalling = 'full-speed'
294 self.update_bitrate()
295 elif sym == 'LS_J':
296 self.signalling = 'low-speed'
297 self.update_bitrate()
831d893d 298 self.oldsym = 'J'
13e81308
SB
299 self.state = 'IDLE'
300
2dc6d41c 301 def decode(self, ss, es, data):
21cda951
UH
302 if not self.samplerate:
303 raise SamplerateError('Cannot decode without samplerate.')
2fcd7c22 304 for (self.samplenum, pins) in data:
d1970f14
UH
305 # State machine.
306 if self.state == 'IDLE':
307 # Ignore identical samples early on (for performance reasons).
308 if self.oldpins == pins:
309 continue
310 self.oldpins = pins
519092e3 311 sym = symbols[self.signalling][tuple(pins)]
13e81308
SB
312 if sym == 'SE0':
313 self.samplenum_lastedge = self.samplenum
314 self.state = 'WAIT IDLE'
315 else:
316 self.wait_for_sop(sym)
a241cfb6 317 self.edgepins = pins
d1970f14
UH
318 elif self.state in ('GET BIT', 'GET EOP'):
319 # Wait until we're in the middle of the desired bit.
a241cfb6
SB
320 if self.samplenum == self.samplenum_edge:
321 self.edgepins = pins
d1970f14
UH
322 if self.samplenum < self.samplenum_target:
323 continue
519092e3 324 sym = symbols[self.signalling][tuple(pins)]
d1970f14
UH
325 if self.state == 'GET BIT':
326 self.get_bit(sym)
327 elif self.state == 'GET EOP':
328 self.get_eop(sym)
831d893d 329 self.oldpins = pins
13e81308 330 elif self.state == 'WAIT IDLE':
831d893d 331 if tuple(pins) == (0, 0):
13e81308 332 continue
13e81308 333 if self.samplenum - self.samplenum_lastedge > 1:
519092e3 334 sym = symbols[self.options['signalling']][tuple(pins)]
13e81308
SB
335 self.handle_idle(sym)
336 else:
519092e3 337 sym = symbols[self.signalling][tuple(pins)]
13e81308
SB
338 self.wait_for_sop(sym)
339 self.oldpins = pins
340 self.edgepins = pins
341 elif self.state == 'INIT':
342 sym = symbols[self.options['signalling']][tuple(pins)]
343 self.handle_idle(sym)
344 self.oldpins = pins