]> sigrok.org Git - libsigrokdecode.git/blob - decoders/microwire/pd.py
decoders: Add/update tags for each PD.
[libsigrokdecode.git] / decoders / microwire / pd.py
1 ##
2 ## This file is part of the libsigrokdecode project.
3 ##
4 ## Copyright (C) 2017 Kevin Redon <kingkevin@cuvoodoo.info>
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 collections import namedtuple
22
23 '''
24 OUTPUT_PYTHON format:
25
26 Packet:
27 [namedtuple('ss': bit start sample number,
28   'es': bit end sample number,
29   'si': SI bit,
30   'so': SO bit,
31  ), ...]
32
33 Since address and word size are variable, a list of all bits in each packet
34 need to be output. Since Microwire is a synchronous protocol with separate
35 input and output lines (SI and SO) they are provided together, but because
36 Microwire is half-duplex only the SI or SO bits will be considered at once.
37 To be able to annotate correctly the instructions formed by the bit, the start
38 and end sample number of each bit (pair of SI/SO bit) are provided.
39 '''
40
41 PyPacket = namedtuple('PyPacket', 'ss es si so')
42 Packet = namedtuple('Packet', 'samplenum matched cs sk si so')
43
44 class Decoder(srd.Decoder):
45     api_version = 3
46     id = 'microwire'
47     name = 'Microwire'
48     longname = 'Microwire'
49     desc = '3-wire, half-duplex, synchronous serial bus.'
50     license = 'gplv2+'
51     inputs = ['logic']
52     outputs = ['microwire']
53     tags = ['Embedded/industrial']
54     channels = (
55         {'id': 'cs', 'name': 'CS', 'desc': 'Chip select'},
56         {'id': 'sk', 'name': 'SK', 'desc': 'Clock'},
57         {'id': 'si', 'name': 'SI', 'desc': 'Slave in'},
58         {'id': 'so', 'name': 'SO', 'desc': 'Slave out'},
59     )
60     annotations = (
61         ('start-bit', 'Start bit'),
62         ('si-bit', 'SI bit'),
63         ('so-bit', 'SO bit'),
64         ('status-check-ready', 'Status check ready'),
65         ('status-check-busy', 'Status check busy'),
66         ('warning', 'Warning'),
67     )
68     annotation_rows = (
69         ('si-bits', 'SI bits', (0, 1)),
70         ('so-bits', 'SO bits', (2,)),
71         ('status', 'Status', (3, 4)),
72         ('warnings', 'Warnings', (5,)),
73     )
74
75     def __init__(self):
76         self.reset()
77
78     def reset(self):
79         pass
80
81     def start(self):
82         self.out_python = self.register(srd.OUTPUT_PYTHON)
83         self.out_ann = self.register(srd.OUTPUT_ANN)
84
85     def decode(self):
86         while True:
87             # Wait for slave to be selected on rising CS.
88             cs, sk, si, so = self.wait({0: 'r'})
89             if sk:
90                 self.put(self.samplenum, self.samplenum, self.out_ann,
91                      [5, ['Clock should be low on start',
92                      'Clock high on start', 'Clock high', 'SK high']])
93                 sk = 0 # Enforce correct state for correct clock handling.
94                 # Because we don't know if this is bit communication or a
95                 # status check we have to collect the SI and SO values on SK
96                 # edges while the chip is selected and figure out afterwards.
97             packet = []
98             while cs:
99                 # Save change.
100                 packet.append(Packet(self.samplenum, self.matched, cs, sk, si, so))
101                 edge = 'r' if sk == 0 else 'f'
102                 cs, sk, si, so = self.wait([{0: 'l'}, {1: edge}, {3: 'e'}])
103             # Save last change.
104             packet.append(Packet(self.samplenum, self.matched, cs, sk, si, so))
105
106             # Figure out if this is a status check.
107             # Either there is no clock or no start bit (on first rising edge).
108             status_check = True
109             for change in packet:
110                 # Get first clock rising edge.
111                 if len(change.matched) > 1 and change.matched[1] and change.sk:
112                     if change.si:
113                         status_check = False
114                     break
115
116             # The packet is for a status check.
117             # SO low = busy, SO high = ready.
118             # The SO signal might be noisy in the beginning because it starts
119             # in high impedance.
120             if status_check:
121                 start_samplenum = packet[0].samplenum
122                 bit_so = packet[0].so
123                 # Check for SO edges.
124                 for change in packet:
125                     if len(change.matched) > 2 and change.matched[2]:
126                         if bit_so == 0 and change.so:
127                             # Rising edge Busy -> Ready.
128                             self.put(start_samplenum, change.samplenum,
129                                      self.out_ann, [4, ['Busy', 'B']])
130                         start_samplenum = change.samplenum
131                         bit_so = change.so
132                 # Put last state.
133                 if bit_so == 0:
134                     self.put(start_samplenum, packet[-1].samplenum,
135                              self.out_ann, [4, ['Busy', 'B']])
136                 else:
137                     self.put(start_samplenum, packet[-1].samplenum,
138                              self.out_ann, [3, ['Ready', 'R']])
139             else:
140                 # Bit communication.
141                 # Since the slave samples SI on clock rising edge we do the
142                 # same. Because the slave changes SO on clock rising edge we
143                 # sample on the falling edge.
144                 bit_start = 0 # Rising clock sample of bit start.
145                 bit_si = 0 # SI value at rising clock edge.
146                 bit_so = 0 # SO value at falling clock edge.
147                 start_bit = True # Start bit incoming (first bit).
148                 pydata = [] # Python output data.
149                 for change in packet:
150                     if len(change.matched) > 1 and change.matched[1]:
151                         # Clock edge.
152                         if change.sk: # Rising clock edge.
153                             if bit_start > 0: # Bit completed.
154                                 if start_bit:
155                                     if bit_si == 0: # Start bit missing.
156                                         self.put(bit_start, change.samplenum,
157                                                  self.out_ann,
158                                                  [5, ['Start bit not high',
159                                                  'Start bit low']])
160                                     else:
161                                         self.put(bit_start, change.samplenum,
162                                                  self.out_ann,
163                                                  [0, ['Start bit', 'S']])
164                                     start_bit = False
165                                 else:
166                                     self.put(bit_start, change.samplenum,
167                                              self.out_ann,
168                                              [1, ['SI bit: %d' % bit_si,
169                                                   'SI: %d' % bit_si,
170                                                   '%d' % bit_si]])
171                                     self.put(bit_start, change.samplenum,
172                                              self.out_ann,
173                                              [2, ['SO bit: %d' % bit_so,
174                                                   'SO: %d' % bit_so,
175                                                   '%d' % bit_so]])
176                                     pydata.append(PyPacket(bit_start,
177                                         change.samplenum, bit_si, bit_so))
178                             bit_start = change.samplenum
179                             bit_si = change.si
180                         else: # Falling clock edge.
181                             bit_so = change.so
182                     elif change.matched[0] and \
183                                     change.cs == 0 and change.sk == 0:
184                         # End of packet.
185                         self.put(bit_start, change.samplenum, self.out_ann,
186                                  [1, ['SI bit: %d' % bit_si,
187                                       'SI: %d' % bit_si, '%d' % bit_si]])
188                         self.put(bit_start, change.samplenum, self.out_ann,
189                                  [2, ['SO bit: %d' % bit_so,
190                                       'SO: %d' % bit_so, '%d' % bit_so]])
191                         pydata.append(PyPacket(bit_start, change.samplenum,
192                                       bit_si, bit_so))
193                 self.put(packet[0].samplenum, packet[len(packet) - 1].samplenum,
194                          self.out_python, pydata)