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