]> sigrok.org Git - libsigrokdecode.git/blob - decoders/sle44xx/pd.py
sle44xx: rephrase annotation text construction
[libsigrokdecode.git] / decoders / sle44xx / pd.py
1 ##
2 ## This file is part of the libsigrokdecode project.
3 ##
4 ## Copyright (C) 2019 Federico Cerutti <federico@ceres-c.it>
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
22 class Pin:
23     RST, CLK, IO, = range(3)
24
25 class Ann:
26     BIT, ATR, CMD, DATA, RESET, = range(5)
27
28 class Bin:
29     SEND_DATA, = range(1)
30
31 # CMD: [annotation class index, annotation texts for zoom levels]
32 proto = {
33     'BIT':   [Ann.BIT,   '{bit}',],
34     'ATR':   [Ann.ATR,   'Answer To Reset: {data:02x}', 'ATR: {data:02x}', '{data:02x}',],
35     'CMD':   [Ann.CMD,   'Command: {data:02x}', 'Cmd: {data:02x}', '{data:02x}',],
36     'DATA':  [Ann.DATA,  'Data: {data:02x}', '{data:02x}',],
37     'RESET': [Ann.RESET, 'Reset', 'R',],
38 }
39
40 def lookup_proto_ann_txt(cmd, variables):
41     ann = proto.get(cmd, None)
42     if ann is None:
43         return None, []
44     cls, texts = ann[0], ann[1:]
45     texts = [t.format(**variables) for t in texts]
46     return cls, texts
47
48 class Decoder(srd.Decoder):
49     api_version = 3
50     id = 'sle44xx'
51     name = 'SLE 44xx'
52     longname = 'SLE44xx memory card'
53     desc = 'SLE 4418/28/32/42 memory card serial protocol'
54     license = 'gplv2+'
55     inputs = ['logic']
56     outputs = []
57     tags = ['Memory']
58     channels = (
59         {'id': 'rst', 'name': 'RST', 'desc': 'Reset line'},
60         {'id': 'clk', 'name': 'CLK', 'desc': 'Clock line'},
61         {'id': 'io', 'name': 'I/O', 'desc': 'I/O data line'},
62     )
63     annotations = (
64         ('bit', 'Bit'),
65         ('atr', 'ATR'),
66         ('cmd', 'Command'),
67         ('data', 'Data exchange'),
68         ('reset', 'Reset'),
69     )
70     annotation_rows = (
71         ('bits', 'Bits', (Ann.BIT,)),
72         ('fields', 'Fields', (Ann.ATR, Ann.CMD, Ann.DATA)),
73         ('interrupts', 'Interrupts', (Ann.RESET,)),
74     )
75     binary = (
76         ('send-data', 'Send data'),
77     )
78
79     def __init__(self):
80         self.reset()
81
82     def reset(self):
83         self.ss = self.es = self.ss_byte = -1
84         self.bitcount = 0
85         self.databyte = 0
86         self.bits = []
87         self.cmd = 'RESET'
88
89     def metadata(self, key, value):
90         if key == srd.SRD_CONF_SAMPLERATE:
91             self.samplerate = value
92
93     def start(self):
94         self.out_ann = self.register(srd.OUTPUT_ANN)
95         self.out_binary = self.register(srd.OUTPUT_BINARY)
96
97     def putx(self, data):
98         self.put(self.ss, self.es, self.out_ann, data)
99
100     def putb(self, data):
101         self.put(self.ss, self.es, self.out_binary, data)
102
103     def handle_reset(self, pins):
104         self.ss, self.es = self.samplenum, self.samplenum
105         self.cmd = 'RESET'
106         cls, texts = lookup_proto_ann_txt(self.cmd, {})
107         self.putx([cls, texts])
108         self.bitcount = self.databyte = 0
109         self.bits = []
110         self.cmd = 'ATR' # Next data bytes will be ATR
111
112     def handle_command(self, pins):
113         rst, clk, io = pins
114         self.ss, self.es = self.samplenum, self.samplenum
115         # If I/O is rising -> command START
116         # if I/O is falling -> command STOP and response data incoming
117         self.cmd = 'CMD' if (io == 0) else 'DATA'
118         self.bitcount = self.databyte = 0
119         self.bits = []
120
121     # Gather 8 bits of data
122     def handle_data(self, pins):
123         rst, clk, io = pins
124
125         # Data is transmitted LSB-first.
126         self.databyte |= (io << self.bitcount)
127
128         # Remember the start of the first data/address bit.
129         if self.bitcount == 0:
130             self.ss_byte = self.samplenum
131
132         # Store individual bits and their start/end samplenumbers.
133         # In the list, index 0 represents the LSB (SLE44xx transmits LSB-first).
134         self.bits.insert(0, [io, self.samplenum, self.samplenum])
135         if self.bitcount > 0:
136             self.bits[1][2] = self.samplenum
137         if self.bitcount == 7:
138             self.bitwidth = self.bits[1][2] - self.bits[2][2]
139             self.bits[0][2] += self.bitwidth
140
141         # Return if we haven't collected all 8 bits, yet.
142         if self.bitcount < 7:
143             self.bitcount += 1
144             return
145
146         self.ss, self.es = self.ss_byte, self.samplenum + self.bitwidth
147
148         self.putb([Bin.SEND_DATA, bytes([self.databyte])])
149
150         for bit_val, bit_ss, bit_es in self.bits:
151             cls, texts = lookup_proto_ann_txt('BIT', {'bit': bit_val})
152             self.put(bit_ss, bit_es, self.out_ann, [cls, texts])
153
154         cls, texts = lookup_proto_ann_txt(self.cmd, {'data': self.databyte})
155         self.putx([cls, texts])
156
157         # Done with this packet.
158         self.bitcount = self.databyte = 0
159         self.bits = []
160
161     def decode(self):
162         while True:
163             # Signal conditions tracked by the protocol decoder:
164             # - RESET condition (R): RST = rising
165             # - Incoming data (D): RST = low, CLK = rising.
166             # - Command mode START: CLK = high, I/O = falling.
167             # - Command mode STOP: CLK = high, I/O = rising.
168             (COND_RESET, COND_DATA, COND_CMD_START, COND_CMD_STOP,) = range(4)
169             conditions = [
170                 {Pin.RST: 'r'},
171                 {Pin.RST: 'l', Pin.CLK: 'r'},
172                 {Pin.CLK: 'h', Pin.IO: 'f'},
173                 {Pin.CLK: 'h', Pin.IO: 'r'},
174             ]
175             pins = self.wait(conditions)
176             if self.matched[COND_RESET]:
177                 self.handle_reset(pins)
178             elif self.matched[COND_DATA]:
179                 self.handle_data(pins)
180             elif self.matched[COND_CMD_START]:
181                 self.handle_command(pins)
182             elif self.matched[COND_CMD_STOP]:
183                 self.handle_command(pins)