]> sigrok.org Git - libsigrokdecode.git/blob - decoders/avr_isp/pd.py
avr_isp: move "unknown command" to warning, drop empty 'bits' row
[libsigrokdecode.git] / decoders / avr_isp / pd.py
1 ##
2 ## This file is part of the libsigrokdecode project.
3 ##
4 ## Copyright (C) 2012-2014 Uwe Hermann <uwe@hermann-uwe.de>
5 ##
6 ## This program is free software; you can redistribute it and/or modify
7 ## it under the terms of the GNU General Public License as published by
8 ## the Free Software Foundation; either version 2 of the License, or
9 ## (at your option) any later version.
10 ##
11 ## This program is distributed in the hope that it will be useful,
12 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 ## GNU General Public License for more details.
15 ##
16 ## You should have received a copy of the GNU General Public License
17 ## along with this program; if not, see <http://www.gnu.org/licenses/>.
18 ##
19
20 import sigrokdecode as srd
21 from .parts import *
22
23 class Ann:
24     PE, RSB0, RSB1, RSB2, CE, RFB, RHFB, REFB, \
25     WARN, DEV, = range(10)
26
27 VENDOR_CODE_ATMEL = 0x1e
28
29 class Decoder(srd.Decoder):
30     api_version = 3
31     id = 'avr_isp'
32     name = 'AVR ISP'
33     longname = 'AVR In-System Programming'
34     desc = 'Atmel AVR In-System Programming (ISP) protocol.'
35     license = 'gplv2+'
36     inputs = ['spi']
37     outputs = []
38     tags = ['Debug/trace']
39     annotations = (
40         ('pe', 'Programming enable'),
41         ('rsb0', 'Read signature byte 0'),
42         ('rsb1', 'Read signature byte 1'),
43         ('rsb2', 'Read signature byte 2'),
44         ('ce', 'Chip erase'),
45         ('rfb', 'Read fuse bits'),
46         ('rhfb', 'Read high fuse bits'),
47         ('refb', 'Read extended fuse bits'),
48         ('warning', 'Warning'),
49         ('dev', 'Device'),
50     )
51     annotation_rows = (
52         ('commands', 'Commands', (Ann.PE, Ann.RSB0, Ann.RSB1, Ann.RSB2,
53             Ann.CE, Ann.RFB, Ann.RHFB, Ann.REFB,)),
54         ('warnings', 'Warnings', (Ann.WARN,)),
55         ('devs', 'Devices', (Ann.DEV,)),
56     )
57
58     def __init__(self):
59         self.reset()
60
61     def reset(self):
62         self.state = 'IDLE'
63         self.mosi_bytes, self.miso_bytes = [], []
64         self.ss_cmd, self.es_cmd = 0, 0
65         self.xx, self.yy, self.zz, self.mm = 0, 0, 0, 0
66         self.ss_device = None
67
68     def start(self):
69         self.out_ann = self.register(srd.OUTPUT_ANN)
70
71     def putx(self, data):
72         self.put(self.ss_cmd, self.es_cmd, self.out_ann, data)
73
74     def handle_cmd_programming_enable(self, cmd, ret):
75         # Programming enable.
76         # Note: The chip doesn't send any ACK for 'Programming enable'.
77         self.putx([Ann.PE, ['Programming enable']])
78
79         # Sanity check on reply.
80         if ret[1:4] != [0xac, 0x53, cmd[2]]:
81             self.putx([Ann.WARN, ['Warning: Unexpected bytes in reply!']])
82
83     def handle_cmd_read_signature_byte_0x00(self, cmd, ret):
84         # Signature byte 0x00: vendor code.
85         self.vendor_code = ret[3]
86         v = vendor_code[self.vendor_code]
87         self.putx([Ann.RSB0, ['Vendor code: 0x%02x (%s)' % (ret[3], v)]])
88
89         # Store for later.
90         self.xx = cmd[1] # Same as ret[2].
91         self.yy = cmd[3]
92         self.zz = ret[0]
93
94         # Sanity check on reply.
95         if ret[1] != 0x30 or ret[2] != cmd[1]:
96             self.putx([Ann.WARN, ['Warning: Unexpected bytes in reply!']])
97
98         # Sanity check for the vendor code.
99         if self.vendor_code != VENDOR_CODE_ATMEL:
100             self.putx([Ann.WARN, ['Warning: Vendor code was not 0x1e (Atmel)!']])
101
102     def handle_cmd_read_signature_byte_0x01(self, cmd, ret):
103         # Signature byte 0x01: part family and memory size.
104         self.part_fam_flash_size = ret[3]
105         self.putx([Ann.RSB1, ['Part family / memory size: 0x%02x' % ret[3]]])
106
107         # Store for later.
108         self.mm = cmd[3]
109         self.ss_device = self.ss_cmd
110
111         # Sanity check on reply.
112         if ret[1] != 0x30 or ret[2] != cmd[1] or ret[0] != self.yy:
113             self.putx([Ann.WARN, ['Warning: Unexpected bytes in reply!']])
114
115     def handle_cmd_read_signature_byte_0x02(self, cmd, ret):
116         # Signature byte 0x02: part number.
117         self.part_number = ret[3]
118         self.putx([Ann.RSB2, ['Part number: 0x%02x' % ret[3]]])
119
120         p = part[(self.part_fam_flash_size, self.part_number)]
121         data = [Ann.DEV, ['Device: Atmel %s' % p]]
122         self.put(self.ss_device, self.es_cmd, self.out_ann, data)
123
124         # Sanity check on reply.
125         if ret[1] != 0x30 or ret[2] != self.xx or ret[0] != self.mm:
126             self.putx([Ann.WARN, ['Warning: Unexpected bytes in reply!']])
127
128         self.xx, self.yy, self.zz, self.mm = 0, 0, 0, 0
129
130     def handle_cmd_chip_erase(self, cmd, ret):
131         # Chip erase (erases both flash an EEPROM).
132         # Upon successful chip erase, the lock bits will also be erased.
133         # The only way to end a Chip Erase cycle is to release RESET#.
134         self.putx([Ann.CE, ['Chip erase']])
135
136         # TODO: Check/handle RESET#.
137
138         # Sanity check on reply.
139         bit = (ret[2] & (1 << 7)) >> 7
140         if ret[1] != 0xac or bit != 1 or ret[3] != cmd[2]:
141             self.putx([Ann.WARN, ['Warning: Unexpected bytes in reply!']])
142
143     def handle_cmd_read_fuse_bits(self, cmd, ret):
144         # Read fuse bits.
145         self.putx([Ann.RFB, ['Read fuse bits: 0x%02x' % ret[3]]])
146
147         # TODO: Decode fuse bits.
148         # TODO: Sanity check on reply.
149
150     def handle_cmd_read_fuse_high_bits(self, cmd, ret):
151         # Read fuse high bits.
152         self.putx([Ann.RHFB, ['Read fuse high bits: 0x%02x' % ret[3]]])
153
154         # TODO: Decode fuse bits.
155         # TODO: Sanity check on reply.
156
157     def handle_cmd_read_extended_fuse_bits(self, cmd, ret):
158         # Read extended fuse bits.
159         self.putx([Ann.REFB, ['Read extended fuse bits: 0x%02x' % ret[3]]])
160
161         # TODO: Decode fuse bits.
162         # TODO: Sanity check on reply.
163
164     def handle_command(self, cmd, ret):
165         if cmd[:2] == [0xac, 0x53]:
166             self.handle_cmd_programming_enable(cmd, ret)
167         elif cmd[0] == 0xac and (cmd[1] & (1 << 7)) == (1 << 7):
168             self.handle_cmd_chip_erase(cmd, ret)
169         elif cmd[:3] == [0x50, 0x00, 0x00]:
170             self.handle_cmd_read_fuse_bits(cmd, ret)
171         elif cmd[:3] == [0x58, 0x08, 0x00]:
172             self.handle_cmd_read_fuse_high_bits(cmd, ret)
173         elif cmd[:3] == [0x50, 0x08, 0x00]:
174             self.handle_cmd_read_extended_fuse_bits(cmd, ret)
175         elif cmd[0] == 0x30 and cmd[2] == 0x00:
176             self.handle_cmd_read_signature_byte_0x00(cmd, ret)
177         elif cmd[0] == 0x30 and cmd[2] == 0x01:
178             self.handle_cmd_read_signature_byte_0x01(cmd, ret)
179         elif cmd[0] == 0x30 and cmd[2] == 0x02:
180             self.handle_cmd_read_signature_byte_0x02(cmd, ret)
181         else:
182             c = '%02x %02x %02x %02x' % tuple(cmd)
183             r = '%02x %02x %02x %02x' % tuple(ret)
184             self.putx([Ann.WARN, ['Unknown command: %s (reply: %s)!' % (c, r)]])
185
186     def decode(self, ss, es, data):
187         ptype, mosi, miso = data
188
189         # For now, only use DATA and BITS packets.
190         if ptype not in ('DATA', 'BITS'):
191             return
192
193         # Store the individual bit values and ss/es numbers. The next packet
194         # is guaranteed to be a 'DATA' packet belonging to this 'BITS' one.
195         if ptype == 'BITS':
196             self.miso_bits, self.mosi_bits = miso, mosi
197             return
198
199         self.ss, self.es = ss, es
200
201         if len(self.mosi_bytes) == 0:
202             self.ss_cmd = ss
203
204         # Append new bytes.
205         self.mosi_bytes.append(mosi)
206         self.miso_bytes.append(miso)
207
208         # All commands consist of 4 bytes.
209         if len(self.mosi_bytes) < 4:
210             return
211
212         self.es_cmd = es
213
214         self.handle_command(self.mosi_bytes, self.miso_bytes)
215
216         self.mosi_bytes = []
217         self.miso_bytes = []