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