]> sigrok.org Git - libsigrokdecode.git/blame - decoders/enc28j60/pd.py
enc28j60: Factor out self.putc().
[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 = []
fbf652db
UH
83 self.cmd_ss = None
84 self.cmd_es = None
a7df1ee4
JL
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
72db471e
UH
92 def putc(self, data):
93 self.put(self.cmd_ss, self.cmd_es, self.ann, data)
94
a7df1ee4
JL
95 def _process_command(self):
96 if len(self.mosi) == 0:
97 self.active = False
98 return
99
100 header = self.mosi[0]
101 opcode = header & OPCODE_MASK
102
103 if opcode not in OPCODE_HANDLERS:
104 self._put_command_warning("Unknown opcode.")
105 self.active = False
106 return
107
108 getattr(self, OPCODE_HANDLERS[opcode])()
109
110 self.active = False
111
112 def _get_register_name(self, reg_addr):
113 if (self.bsel0 is None) or (self.bsel1 is None):
114 # We don't know the bank we're in yet.
115 return None
116 else:
117 bank = (self.bsel1 << 1) + self.bsel0
118 return REGS[bank][reg_addr]
119
120 def _put_register_header(self):
121 reg_addr = self.mosi[0] & REG_ADDR_MASK
122 reg_name = self._get_register_name(reg_addr)
123
fbf652db
UH
124 ss, es = self.cmd_ss, self.ranges[1][0]
125
a7df1ee4
JL
126 if reg_name is None:
127 # We don't know the bank we're in yet.
fbf652db 128 self.put(ss, es, self.ann, [
a7df1ee4
JL
129 ANN_REG_ADDR,
130 [
131 'Reg Bank ? Addr 0x{0:02X}'.format(reg_addr),
132 '?:{0:02X}'.format(reg_addr),
133 ]])
fbf652db 134 self.put(ss, es, self.ann, [
a7df1ee4
JL
135 ANN_WARNING,
136 [
137 'Warning: Register bank not known yet.',
138 'Warning',
139 ]])
140 else:
fbf652db 141 self.put(ss, es, self.ann, [
a7df1ee4
JL
142 ANN_REG_ADDR,
143 [
144 'Reg {0}'.format(reg_name),
145 '{0}'.format(reg_name),
146 ]])
147
148 if (reg_name == '-') or (reg_name == 'Reserved'):
fbf652db 149 self.put(ss, es, self.ann, [
a7df1ee4
JL
150 ANN_WARNING,
151 [
152 'Warning: Invalid register accessed.',
153 'Warning',
154 ]])
155
156 def _put_data_byte(self, data, byte_index, binary=False):
fbf652db 157 ss = self.ranges[byte_index][0]
a7df1ee4 158 if byte_index == len(self.mosi) - 1:
fbf652db 159 es = self.cmd_es
a7df1ee4 160 else:
fbf652db 161 es = self.ranges[byte_index + 1][0]
a7df1ee4
JL
162
163 if binary:
fbf652db 164 self.put(ss, es, self.ann, [
a7df1ee4
JL
165 ANN_DATA,
166 [
167 'Data 0b{0:08b}'.format(data),
168 '{0:08b}'.format(data),
169 ]])
170 else:
fbf652db 171 self.put(ss, es, self.ann, [
a7df1ee4
JL
172 ANN_DATA,
173 [
174 'Data 0x{0:02X}'.format(data),
175 '{0:02X}'.format(data),
176 ]])
177
178 def _put_command_warning(self, reason):
72db471e 179 self.putc([
a7df1ee4
JL
180 ANN_WARNING,
181 [
182 'Warning: {0}'.format(reason),
183 'Warning',
184 ]])
185
186 def _process_rcr(self):
72db471e 187 self.putc([ANN_RCR, ['Read Control Register', 'RCR']])
a7df1ee4
JL
188
189 if (len(self.mosi) != 2) and (len(self.mosi) != 3):
190 self._put_command_warning('Invalid command length.')
191 return
192
193 self._put_register_header()
194
195 reg_name = self._get_register_name(self.mosi[0] & REG_ADDR_MASK)
196 if reg_name is None:
197 # We can't tell if we're accessing MAC/MII registers or not
198 # Let's trust the user in this case.
199 pass
200 else:
201 if (reg_name[0] == 'M') and (len(self.mosi) != 3):
202 self._put_command_warning('Attempting to read a MAC/MII '
203 + 'register without using the dummy byte.')
204 return
205
206 if (reg_name[0] != 'M') and (len(self.mosi) != 2):
207 self._put_command_warning('Attempting to read a non-MAC/MII '
208 + 'register using the dummy byte.')
209 return
210
211 if len(self.mosi) == 2:
212 self._put_data_byte(self.miso[1], 1)
213 else:
fbf652db
UH
214 ss, es = self.ranges[1][0], self.ranges[2][0]
215 self.put(ss, es, self.ann, [
a7df1ee4
JL
216 ANN_DATA,
217 [
218 'Dummy Byte',
219 'Dummy',
220 ]])
221 self._put_data_byte(self.miso[2], 2)
222
223 def _process_rbm(self):
224 if self.mosi[0] != 0b00111010:
225 self._put_command_warning('Invalid header byte.')
226 return
227
72db471e 228 self.putc([
a7df1ee4
JL
229 ANN_RBM,
230 [
231 'Read Buffer Memory: Length {0}'.format(
232 len(self.mosi) - 1),
233 'RBM',
234 ]])
235
236 for i in range(1, len(self.miso)):
237 self._put_data_byte(self.miso[i], i)
238
239 def _process_wcr(self):
72db471e 240 self.putc([ANN_WCR, ['Write Control Register', 'WCR']])
a7df1ee4
JL
241
242 if len(self.mosi) != 2:
243 self._put_command_warning('Invalid command length.')
244 return
245
246 self._put_register_header()
247 self._put_data_byte(self.mosi[1], 1)
248
249 if self.mosi[0] & REG_ADDR_MASK == REG_ADDR_ECON1:
250 self.bsel0 = (self.mosi[1] & BIT_ECON1_BSEL0) >> 0
251 self.bsel1 = (self.mosi[1] & BIT_ECON1_BSEL1) >> 1
252
253 def _process_wbm(self):
254 if self.mosi[0] != 0b01111010:
255 self._put_command_warning('Invalid header byte.')
256 return
257
72db471e 258 self.putc([
a7df1ee4
JL
259 ANN_WBM,
260 [
261 'Write Buffer Memory: Length {0}'.format(
262 len(self.mosi) - 1),
263 'WBM',
264 ]])
265
266 for i in range(1, len(self.mosi)):
267 self._put_data_byte(self.mosi[i], i)
268
269 def _process_bfc(self):
72db471e 270 self.putc([ANN_BFC, ['Bit Field Clear', 'BFC']])
a7df1ee4
JL
271
272 if len(self.mosi) != 2:
273 self._put_command_warning('Invalid command length.')
274 return
275
276 self._put_register_header()
277 self._put_data_byte(self.mosi[1], 1, True)
278
279 if self.mosi[0] & REG_ADDR_MASK == REG_ADDR_ECON1:
280 if self.mosi[1] & BIT_ECON1_BSEL0:
281 self.bsel0 = 0
282 if self.mosi[1] & BIT_ECON1_BSEL1:
283 self.bsel1 = 0
284
285 def _process_bfs(self):
72db471e 286 self.putc([ANN_BFS, ['Bit Field Set', 'BFS']])
a7df1ee4
JL
287
288 if len(self.mosi) != 2:
289 self._put_command_warning('Invalid command length.')
290 return
291
292 self._put_register_header()
293 self._put_data_byte(self.mosi[1], 1, True)
294
295 if self.mosi[0] & REG_ADDR_MASK == REG_ADDR_ECON1:
296 if self.mosi[1] & BIT_ECON1_BSEL0:
297 self.bsel0 = 1
298 if self.mosi[1] & BIT_ECON1_BSEL1:
299 self.bsel1 = 1
300
301 def _process_src(self):
72db471e 302 self.putc([ANN_SRC, ['System Reset Command', 'SRC']])
a7df1ee4
JL
303
304 if len(self.mosi) != 1:
305 self._put_command_warning('Invalid command length.')
306 return
307
308 self.bsel0 = 0
309 self.bsel1 = 0
310
311 def decode(self, ss, es, data):
312 ptype, data1, data2 = data
313
314 if ptype == 'CS-CHANGE':
315 new_cs = data2
316
317 if new_cs == 0:
318 self.active = True
fbf652db 319 self.cmd_ss = ss
a7df1ee4
JL
320 self.mosi = []
321 self.miso = []
322 self.ranges = []
323 elif new_cs == 1:
324 if self.active:
fbf652db 325 self.cmd_es = es
a7df1ee4
JL
326 self._process_command()
327 elif ptype == 'DATA':
328 mosi, miso = data1, data2
329
330 self.mosi.append(mosi)
331 self.miso.append(miso)
332 self.ranges.append((ss, es))