]> sigrok.org Git - libsigrokdecode.git/blame - decoders/enc28j60/pd.py
enc28j60: Clear 'outputs' (no OUTPUT_PYTHON support).
[libsigrokdecode.git] / decoders / enc28j60 / pd.py
CommitLineData
a7df1ee4
JL
1##
2## This file is part of the libsigrokdecode project.
3##
4## Copyright (C) 2019 Jiahao Li <reg@ljh.me>
5##
6## Permission is hereby granted, free of charge, to any person obtaining a copy
7## of this software and associated documentation files (the "Software"), to deal
8## in the Software without restriction, including without limitation the rights
9## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10## copies of the Software, and to permit persons to whom the Software is
11## furnished to do so, subject to the following conditions:
12##
13## The above copyright notice and this permission notice shall be included in all
14## copies or substantial portions of the Software.
15##
16## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22## SOFTWARE.
23
24import sigrokdecode as srd
de49d11e 25from .lists import *
a7df1ee4
JL
26
27OPCODE_MASK = 0b11100000
28REG_ADDR_MASK = 0b00011111
29
30OPCODE_HANDLERS = {
31 0b00000000: '_process_rcr',
32 0b00100000: '_process_rbm',
33 0b01000000: '_process_wcr',
34 0b01100000: '_process_wbm',
35 0b10000000: '_process_bfs',
36 0b10100000: '_process_bfc',
37 0b11100000: '_process_src',
38}
39
acc08e51
UH
40(ANN_RCR, ANN_RBM, ANN_WCR, ANN_WBM, ANN_BFS, ANN_BFC, ANN_SRC, ANN_DATA,
41ANN_REG_ADDR, ANN_WARNING) = range(10)
a7df1ee4
JL
42
43REG_ADDR_ECON1 = 0x1F
44BIT_ECON1_BSEL0 = 0b00000001
45BIT_ECON1_BSEL1 = 0b00000010
46
a7df1ee4
JL
47class Decoder(srd.Decoder):
48 api_version = 3
49 id = 'enc28j60'
50 name = 'ENC28J60'
51 longname = 'Microchip ENC28J60'
52 desc = 'Microchip ENC28J60 10Base-T Ethernet controller protocol.'
53 license = 'mit'
54 inputs = ['spi']
052be6a7 55 outputs = []
2df02753 56 tags = ['Embedded/industrial', 'Networking']
a7df1ee4
JL
57 annotations = (
58 ('rcr', 'Read Control Register'),
59 ('rbm', 'Read Buffer Memory'),
60 ('wcr', 'Write Control Register'),
61 ('wbm', 'Write Buffer Memory'),
62 ('bfs', 'Bit Field Set'),
63 ('bfc', 'Bit Field Clear'),
64 ('src', 'System Reset Command'),
65 ('data', 'Data'),
66 ('reg-addr', 'Register Address'),
67 ('warning', 'Warning'),
68 )
69 annotation_rows = (
70 ('commands', 'Commands',
71 (ANN_RCR, ANN_RBM, ANN_WCR, ANN_WBM, ANN_BFS, ANN_BFC, ANN_SRC)),
72 ('fields', 'Fields', (ANN_DATA, ANN_REG_ADDR)),
73 ('warnings', 'Warnings', (ANN_WARNING,)),
74 )
75
76 def __init__(self):
77 self.reset()
78
79 def reset(self):
80 self.mosi = []
81 self.miso = []
82 self.ranges = []
83 self.command_start = None
84 self.command_end = None
85 self.active = False
86 self.bsel0 = None
87 self.bsel1 = None
88
89 def start(self):
90 self.ann = self.register(srd.OUTPUT_ANN)
91
92 def _process_command(self):
93 if len(self.mosi) == 0:
94 self.active = False
95 return
96
97 header = self.mosi[0]
98 opcode = header & OPCODE_MASK
99
100 if opcode not in OPCODE_HANDLERS:
101 self._put_command_warning("Unknown opcode.")
102 self.active = False
103 return
104
105 getattr(self, OPCODE_HANDLERS[opcode])()
106
107 self.active = False
108
109 def _get_register_name(self, reg_addr):
110 if (self.bsel0 is None) or (self.bsel1 is None):
111 # We don't know the bank we're in yet.
112 return None
113 else:
114 bank = (self.bsel1 << 1) + self.bsel0
115 return REGS[bank][reg_addr]
116
117 def _put_register_header(self):
118 reg_addr = self.mosi[0] & REG_ADDR_MASK
119 reg_name = self._get_register_name(reg_addr)
120
121 if reg_name is None:
122 # We don't know the bank we're in yet.
123 self.put(self.command_start, self.ranges[1][0], self.ann, [
124 ANN_REG_ADDR,
125 [
126 'Reg Bank ? Addr 0x{0:02X}'.format(reg_addr),
127 '?:{0:02X}'.format(reg_addr),
128 ]])
129 self.put(self.command_start, self.ranges[1][0], self.ann, [
130 ANN_WARNING,
131 [
132 'Warning: Register bank not known yet.',
133 'Warning',
134 ]])
135 else:
136 self.put(self.command_start, self.ranges[1][0], self.ann, [
137 ANN_REG_ADDR,
138 [
139 'Reg {0}'.format(reg_name),
140 '{0}'.format(reg_name),
141 ]])
142
143 if (reg_name == '-') or (reg_name == 'Reserved'):
144 self.put(self.command_start, self.ranges[1][0], self.ann, [
145 ANN_WARNING,
146 [
147 'Warning: Invalid register accessed.',
148 'Warning',
149 ]])
150
151 def _put_data_byte(self, data, byte_index, binary=False):
152 if byte_index == len(self.mosi) - 1:
153 end_sample = self.command_end
154 else:
155 end_sample = self.ranges[byte_index + 1][0]
156
157 if binary:
158 self.put(self.ranges[byte_index][0], end_sample, self.ann, [
159 ANN_DATA,
160 [
161 'Data 0b{0:08b}'.format(data),
162 '{0:08b}'.format(data),
163 ]])
164 else:
165 self.put(self.ranges[byte_index][0], end_sample, self.ann, [
166 ANN_DATA,
167 [
168 'Data 0x{0:02X}'.format(data),
169 '{0:02X}'.format(data),
170 ]])
171
172 def _put_command_warning(self, reason):
173 self.put(self.command_start, self.command_end, self.ann, [
174 ANN_WARNING,
175 [
176 'Warning: {0}'.format(reason),
177 'Warning',
178 ]])
179
180 def _process_rcr(self):
181 self.put(self.command_start, self.command_end,
182 self.ann, [ANN_RCR, ['Read Control Register', 'RCR']])
183
184 if (len(self.mosi) != 2) and (len(self.mosi) != 3):
185 self._put_command_warning('Invalid command length.')
186 return
187
188 self._put_register_header()
189
190 reg_name = self._get_register_name(self.mosi[0] & REG_ADDR_MASK)
191 if reg_name is None:
192 # We can't tell if we're accessing MAC/MII registers or not
193 # Let's trust the user in this case.
194 pass
195 else:
196 if (reg_name[0] == 'M') and (len(self.mosi) != 3):
197 self._put_command_warning('Attempting to read a MAC/MII '
198 + 'register without using the dummy byte.')
199 return
200
201 if (reg_name[0] != 'M') and (len(self.mosi) != 2):
202 self._put_command_warning('Attempting to read a non-MAC/MII '
203 + 'register using the dummy byte.')
204 return
205
206 if len(self.mosi) == 2:
207 self._put_data_byte(self.miso[1], 1)
208 else:
209 self.put(self.ranges[1][0], self.ranges[2][0], self.ann, [
210 ANN_DATA,
211 [
212 'Dummy Byte',
213 'Dummy',
214 ]])
215 self._put_data_byte(self.miso[2], 2)
216
217 def _process_rbm(self):
218 if self.mosi[0] != 0b00111010:
219 self._put_command_warning('Invalid header byte.')
220 return
221
222 self.put(self.command_start, self.command_end, self.ann, [
223 ANN_RBM,
224 [
225 'Read Buffer Memory: Length {0}'.format(
226 len(self.mosi) - 1),
227 'RBM',
228 ]])
229
230 for i in range(1, len(self.miso)):
231 self._put_data_byte(self.miso[i], i)
232
233 def _process_wcr(self):
234 self.put(self.command_start, self.command_end,
235 self.ann, [ANN_WCR, ['Write Control Register', 'WCR']])
236
237 if len(self.mosi) != 2:
238 self._put_command_warning('Invalid command length.')
239 return
240
241 self._put_register_header()
242 self._put_data_byte(self.mosi[1], 1)
243
244 if self.mosi[0] & REG_ADDR_MASK == REG_ADDR_ECON1:
245 self.bsel0 = (self.mosi[1] & BIT_ECON1_BSEL0) >> 0
246 self.bsel1 = (self.mosi[1] & BIT_ECON1_BSEL1) >> 1
247
248 def _process_wbm(self):
249 if self.mosi[0] != 0b01111010:
250 self._put_command_warning('Invalid header byte.')
251 return
252
253 self.put(self.command_start, self.command_end, self.ann, [
254 ANN_WBM,
255 [
256 'Write Buffer Memory: Length {0}'.format(
257 len(self.mosi) - 1),
258 'WBM',
259 ]])
260
261 for i in range(1, len(self.mosi)):
262 self._put_data_byte(self.mosi[i], i)
263
264 def _process_bfc(self):
265 self.put(self.command_start, self.command_end,
266 self.ann, [ANN_BFC, ['Bit Field Clear', 'BFC']])
267
268 if len(self.mosi) != 2:
269 self._put_command_warning('Invalid command length.')
270 return
271
272 self._put_register_header()
273 self._put_data_byte(self.mosi[1], 1, True)
274
275 if self.mosi[0] & REG_ADDR_MASK == REG_ADDR_ECON1:
276 if self.mosi[1] & BIT_ECON1_BSEL0:
277 self.bsel0 = 0
278 if self.mosi[1] & BIT_ECON1_BSEL1:
279 self.bsel1 = 0
280
281 def _process_bfs(self):
282 self.put(self.command_start, self.command_end,
283 self.ann, [ANN_BFS, ['Bit Field Set', 'BFS']])
284
285 if len(self.mosi) != 2:
286 self._put_command_warning('Invalid command length.')
287 return
288
289 self._put_register_header()
290 self._put_data_byte(self.mosi[1], 1, True)
291
292 if self.mosi[0] & REG_ADDR_MASK == REG_ADDR_ECON1:
293 if self.mosi[1] & BIT_ECON1_BSEL0:
294 self.bsel0 = 1
295 if self.mosi[1] & BIT_ECON1_BSEL1:
296 self.bsel1 = 1
297
298 def _process_src(self):
299 self.put(self.command_start, self.command_end,
300 self.ann, [ANN_SRC, ['System Reset Command', 'SRC']])
301
302 if len(self.mosi) != 1:
303 self._put_command_warning('Invalid command length.')
304 return
305
306 self.bsel0 = 0
307 self.bsel1 = 0
308
309 def decode(self, ss, es, data):
310 ptype, data1, data2 = data
311
312 if ptype == 'CS-CHANGE':
313 new_cs = data2
314
315 if new_cs == 0:
316 self.active = True
317 self.command_start = ss
318 self.mosi = []
319 self.miso = []
320 self.ranges = []
321 elif new_cs == 1:
322 if self.active:
323 self.command_end = es
324 self._process_command()
325 elif ptype == 'DATA':
326 mosi, miso = data1, data2
327
328 self.mosi.append(mosi)
329 self.miso.append(miso)
330 self.ranges.append((ss, es))