]> sigrok.org Git - libsigrokdecode.git/blob - decoders/em4100/pd.py
Add RFID EM4100 protocol decoding
[libsigrokdecode.git] / decoders / em4100 / pd.py
1 ##
2 ## This file is part of the libsigrokdecode project.
3 ##
4 ## Copyright (C) 2015 Benjamin Larsson <benjamin@southpole.se>
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 data 2 of the License, or
9 ## (at your option) any later data.
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, write to the Free Software
18 ## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19 ##
20
21 import sigrokdecode as srd
22
23 class SamplerateError(Exception):
24     pass
25
26 class Decoder(srd.Decoder):
27     api_version = 2
28     id = 'em4100'
29     name = 'EM4100'
30     longname = 'RFID EM4100'
31     desc = 'EM4100 100-150kHz RFID protocol.'
32     license = 'gplv2+'
33     inputs = ['logic']
34     outputs = ['em4100']
35     channels = (
36         {'id': 'data', 'name': 'Data', 'desc': 'Data line'},
37     )
38     options = (
39         {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-high',
40             'values': ('active-low', 'active-high')},
41         {'id': 'datarate' , 'desc': 'Data rate', 'default': '64',
42             'values': ('64', '32', '16')},
43 #        {'id': 'coding', 'desc': 'Bit coding', 'default': 'biphase',
44 #            'values': ('biphase', 'manchester', 'psk')},
45         {'id': 'coilfreq', 'desc': 'Coil frequency', 'default': '125000'},
46     )
47     annotations = (
48         ('headerbit', 'Header bit'),
49         ('databit', 'Version bit'),
50         ('rowparity', 'Row Parity'),
51         ('databit', 'Data bit'),
52         ('colparity', 'Column Parity'),
53         ('stopbit', 'Stop bit'),
54         ('rowparity_check', 'Row Parity Check'),
55     )
56     annotation_rows = (
57         ('bits', 'Bits', (0,)),
58         ('fields', 'Fields', (1, 2, 4, 7)),
59         ('value', 'Value', (3, 5, 6, 8)),
60     )
61
62     def __init__(self, **kwargs):
63         self.samplerate = None
64         self.oldpin = None
65         self.last_samplenum = None
66         self.lastlast_samplenum = None
67         self.last_edge = 0
68         self.bit_width = 0
69         self.halfbit_limit = 0
70         self.oldpp = 0
71         self.oldpl = 0
72         self.oldsamplenum = 0
73         self.last_bit_pos = 0
74         self.first_start = 0
75         self.first_one = 0
76         self.state = 'HEADER'
77         self.data = 0
78         self.data_bits = 0
79         self.data_start = 0
80         self.data_parity = 0
81         self.payload_cnt = 0
82         self.data_col_parity = [0, 0, 0, 0, 0, 0]
83         self.col_parity = [0, 0, 0, 0, 0, 0]
84
85     def metadata(self, key, value):
86         if key == srd.SRD_CONF_SAMPLERATE:
87             self.samplerate = value
88         self.bit_width = (self.samplerate / (int(self.options['coilfreq']))) * int(self.options['datarate'])
89         self.halfbit_limit = self.bit_width/2 + self.bit_width/4
90         self.polarity = 0 if self.options['polarity'] == 'active-low' else 1
91
92     def start(self):
93         self.out_ann = self.register(srd.OUTPUT_ANN)
94
95     def add_bit(self, bit, bit_start, bit_stop):
96         if self.state == 'HEADER':
97             if bit == 1:
98                 if self.first_one > 0:
99                     self.first_one += 1
100                 if self.first_one == 9:
101                     self.put(int(self.first_start), int(bit_stop), self.out_ann,
102                              [1, ['Header', 'Head', 'He', 'H']])
103                     self.first_one = 0
104                     self.state = 'PAYLOAD'
105                     return
106                 if self.first_one == 0:
107                     self.first_one = 1
108                     self.first_start = bit_start
109
110             if bit == 0:
111                 self.first_one = 0
112             return
113
114         if self.state == 'PAYLOAD':
115             self.payload_cnt += 1
116             if self.data_bits == 0:
117                 self.data_start = bit_start
118                 self.data = 0
119                 self.data_parity = 0
120             self.data_bits += 1
121             if self.data_bits == 5:
122                 self.put(int(self.data_start), int(bit_start), self.out_ann,
123                          [2, ['Data', 'Da', 'D']])
124                 self.put(int(bit_start), int(bit_stop), self.out_ann,
125                          [4, ['Parity', 'Par', 'Pa', 'P']])
126                 self.put(int(self.data_start), int(bit_start), self.out_ann,
127                          [3, [str("%X" % self.data)]])
128                 if self.data_parity == bit:
129                     p_string = ['OK', 'O']
130                 else:
131                     p_string = ['ERROR', 'ERR', 'ER', 'E']
132                 self.put(int(bit_start), int(bit_stop), self.out_ann,
133                          [6, p_string])
134                 self.data_bits = 0
135                 if self.payload_cnt == 50:
136                     self.state = 'TRAILER'
137                     self.payload_cnt = 0
138
139             self.data_parity ^= bit
140             self.data_col_parity[self.data_bits] ^= bit
141             self.data = (self.data << 1) | bit
142             return
143
144         if self.state == 'TRAILER':
145             self.payload_cnt += 1
146             if self.data_bits == 0:
147                 self.data_start = bit_start
148                 self.data = 0
149                 self.data_parity = 0
150             self.data_bits += 1
151             self.col_parity[self.data_bits] = bit
152
153             if self.data_bits == 5:
154                 p_string = ['ERROR', 'ERR', 'ER', 'E']
155                 if self.data_col_parity[1] == self.col_parity[1]:
156                     if self.data_col_parity[2] == self.col_parity[2]:
157                         if self.data_col_parity[3] == self.col_parity[3]:
158                             if self.data_col_parity[4] == self.col_parity[4]:
159                                 p_string = ['OK', 'O']
160
161                 self.put(int(self.data_start), int(bit_start), self.out_ann,
162                          [4, ['Column parity', 'Col par', 'CP', 'P']])
163                 self.put(int(bit_start), int(bit_stop), self.out_ann,
164                          [4, ['Stop bit', 'St bi', 'SB', 'S']])
165                 self.put(int(self.data_start), int(bit_start), self.out_ann,
166                          [6, p_string])
167
168                 self.data_bits = 0
169                 if self.payload_cnt == 5:
170                     self.state = 'HEADER'
171                     self.payload_cnt = 0
172                     self.data_col_parity = [0, 0, 0, 0, 0, 0]
173                     self.col_parity = [0, 0, 0, 0, 0, 0]
174
175     def putbit(self, bit, bit_start, bit_stop):
176         self.put(int(bit_start), int(bit_stop), self.out_ann,
177                  [0, [str(bit)]])
178         self.add_bit(bit, bit_start, bit_stop)
179
180     def manchester_decode(self, samplenum, pl, pp, pin):
181         bit_start = 0
182         bit_stop = 0
183         bit = self.oldpin ^ self.polarity
184         if pl > self.halfbit_limit:
185             samples = samplenum - self.oldsamplenum
186             t = samples / self.samplerate
187
188             if self.oldpl > self.halfbit_limit:
189                 bit_start = int(self.oldsamplenum - self.oldpl/2)
190                 bit_stop = int(samplenum - pl/2)
191                 self.putbit(bit, bit_start, bit_stop)
192             if self.oldpl <= self.halfbit_limit:
193                 bit_start = int(self.oldsamplenum - self.oldpl)
194                 bit_stop = int(samplenum - pl/2)
195                 self.putbit(bit, bit_start, bit_stop)
196             self.last_bit_pos = int(samplenum - pl/2)
197
198         if pl < self.halfbit_limit:
199             samples = samplenum - self.oldsamplenum
200             t = samples / self.samplerate
201
202             if self.oldpl > self.halfbit_limit:
203                 bit_start = self.oldsamplenum - self.oldpl/2
204                 bit_stop = int(samplenum)
205                 self.putbit(bit, bit_start, bit_stop)
206                 self.last_bit_pos = int(samplenum)
207             if self.oldpl <= self.halfbit_limit:
208                 if self.last_bit_pos <= self.oldsamplenum - self.oldpl:
209                     bit_start = self.oldsamplenum - self.oldpl
210                     bit_stop = int(samplenum)
211                     self.putbit(bit, bit_start, bit_stop)
212                     self.last_bit_pos = int(samplenum)
213
214     def decode(self, ss, es, data):
215         if not self.samplerate:
216             raise SamplerateError('Cannot decode without samplerate.')
217         for (samplenum, (pin,)) in data:
218             # Ignore identical samples early on (for performance reasons).
219             if self.oldpin == pin:
220                 continue
221
222             if self.oldpin is None:
223                 self.oldpin = pin
224                 self.last_samplenum = samplenum
225                 self.lastlast_samplenum = samplenum
226                 self.last_edge = samplenum
227                 self.oldpl = 0
228                 self.oldpp = 0
229                 self.oldsamplenum = 0
230                 self.last_bit_pos = 0
231                 continue
232
233             if self.oldpin != pin:
234                 pl = samplenum - self.oldsamplenum
235                 pp = pin
236
237                 self.manchester_decode(samplenum, pl, pp, pin)
238
239                 self.oldpl = pl
240                 self.oldpp = pp
241                 self.oldsamplenum = samplenum
242                 self.oldpin = pin