]> sigrok.org Git - libsigrokdecode.git/blob - decoders/t55xx/pd.py
a3c40bbc10e6dffe70aaa9643b4603b799daee6c
[libsigrokdecode.git] / decoders / t55xx / 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 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 SamplerateError(Exception):
23     pass
24
25 class Decoder(srd.Decoder):
26     api_version = 2
27     id = 't55xx'
28     name = 'T55xx'
29     longname = 'RFID T55xx'
30     desc = 'T55xx 100-150kHz RFID protocol.'
31     license = 'gplv2+'
32     inputs = ['logic']
33     outputs = ['t55xx']
34     channels = (
35         {'id': 'data', 'name': 'Data', 'desc': 'Data line'},
36     )
37     options = (
38         {'id': 'coilfreq', 'desc': 'Coil frequency', 'default': 125000},
39         {'id': 'start_gap', 'desc': 'Start gap min', 'default': 20},
40         {'id': 'w_gap', 'desc': 'Write gap min', 'default': 20},
41         {'id': 'w_one_min', 'desc': 'Write one min', 'default': 48},
42         {'id': 'w_one_max', 'desc': 'Write one max', 'default': 63},
43         {'id': 'w_zero_min', 'desc': 'Write zero min', 'default': 16},
44         {'id': 'w_zero_max', 'desc': 'Write zero max', 'default': 31},
45         {'id': 'em4100_decode', 'desc': 'EM4100 decode', 'default': 'on',
46             'values': ('on', 'off')},
47     )
48     annotations = (
49         ('bit_value', 'Bit value'),
50         ('start_gap', 'Start gap'),
51         ('write_gap', 'Write gap'),
52         ('write_mode_exit', 'Write mode exit'),
53         ('bit', 'Bit'),
54         ('opcode', 'Opcode'),
55         ('lock', 'Lock'),
56         ('data', 'Data'),
57         ('password', 'Password'),
58         ('address', 'Address'),
59         ('bitrate', 'Bitrate'),
60     )
61     annotation_rows = (
62         ('bits', 'Bits', (0,)),
63         ('structure', 'Structure', (1, 2, 3, 4)),
64         ('fields', 'Fields', (5, 6, 7, 8, 9)),
65         ('decode', 'Decode', (10,)),
66     )
67
68     def __init__(self):
69         self.samplerate = None
70         self.oldpin = None
71         self.last_samplenum = None
72         self.lastlast_samplenum = None
73         self.state = 'START_GAP'
74         self.bits_pos = [[0 for col in range(3)] for row in range(70)]
75         self.br_string = ['RF/8', 'RF/16', 'RF/32', 'RF/40',
76                           'RF/50', 'RF/64', 'RF/100', 'RF/128']
77         self.mod_str1 = ['Direct', 'Manchester', 'Biphase', 'Reserved']
78         self.mod_str2 = ['Direct', 'PSK1', 'PSK2', 'PSK3', 'FSK1', 'FSK2',
79                          'FSK1a', 'FSK2a']
80         self.pskcf_str = ['RF/2', 'RF/4', 'RF/8', 'Reserved']
81         self.em4100_decode1_partial = 0
82
83     def metadata(self, key, value):
84         if key == srd.SRD_CONF_SAMPLERATE:
85             self.samplerate = value
86         self.field_clock = self.samplerate / self.options['coilfreq']
87         self.wzmax = self.options['w_zero_max'] * self.field_clock
88         self.wzmin = self.options['w_zero_min'] * self.field_clock
89         self.womax = self.options['w_one_max'] * self.field_clock
90         self.womin = self.options['w_one_min'] * self.field_clock
91         self.startgap = self.options['start_gap'] * self.field_clock
92         self.writegap = self.options['w_gap'] * self.field_clock
93         self.nogap = 64 * self.field_clock
94
95     def start(self):
96         self.out_ann = self.register(srd.OUTPUT_ANN)
97
98     def decode_config(self, idx):
99         safer_key = self.bits_pos[idx][0]<<3 | self.bits_pos[idx+1][0]<<2 | \
100                     self.bits_pos[idx+2][0]<<1 | self.bits_pos[idx+3][0]
101         self.put(self.bits_pos[idx][1], self.bits_pos[idx+3][2], self.out_ann,
102                  [10, ['Safer Key' + ': %X' % safer_key,'%X' % safer_key]])
103         bitrate = self.bits_pos[idx+11][0]<<2 | self.bits_pos[idx+12][0]<<1 | \
104                   self.bits_pos[idx+13][0]
105         self.put(self.bits_pos[idx+11][1], self.bits_pos[idx+13][2],
106                  self.out_ann, [10, ['Data Bit Rate: ' + \
107                  self.br_string[bitrate], self.br_string[bitrate]]])
108         modulation1 = self.bits_pos[idx+15][0]<<1 | self.bits_pos[idx+16][0]
109         modulation2 = self.bits_pos[idx+17][0]<<2 | \
110                       self.bits_pos[idx+18][0]<<1 | self.bits_pos[idx+19][0]
111         if modulation1 == 0:
112             mod_string = self.mod_str2[modulation2]
113         else:
114             mod_string = self.mod_str1[modulation1]
115         self.put(self.bits_pos[idx+15][1], self.bits_pos[idx+19][2],
116                  self.out_ann, [10, ['Modulation: ' + mod_string, mod_string]])
117         psk_cf = self.bits_pos[idx+20][0]<<1 | self.bits_pos[idx+21][0]
118         self.put(self.bits_pos[idx+20][1], self.bits_pos[idx+21][2],
119                  self.out_ann, [10, ['PSK-CF: ' + self.pskcf_str[psk_cf],
120                  self.pskcf_str[psk_cf]]])
121         self.put(self.bits_pos[idx+22][1], self.bits_pos[idx+22][2],
122                  self.out_ann, [10, ['AOR' + ': %d' % \
123                  (self.bits_pos[idx+22][0]),'%d' % (self.bits_pos[idx+22][0])]])
124         maxblock = self.bits_pos[idx+24][0]<<2 | self.bits_pos[idx+25][0]<<1 | \
125                    self.bits_pos[idx+26][0]
126         self.put(self.bits_pos[idx+24][1], self.bits_pos[idx+26][2],
127                  self.out_ann, [10, ['Max-Block' + ': %d' % maxblock,
128                  '%d' % maxblock]])
129         self.put(self.bits_pos[idx+27][1], self.bits_pos[idx+27][2],
130                  self.out_ann, [10, ['PWD' + ': %d' % \
131                  (self.bits_pos[idx+27][0]),'%d' % (self.bits_pos[idx+27][0])]])
132         self.put(self.bits_pos[idx+28][1], self.bits_pos[idx+28][2],
133                  self.out_ann, [10, ['ST-sequence terminator' + ': %d' % \
134                  (self.bits_pos[idx+28][0]),'%d' % (self.bits_pos[idx+28][0])]])
135         self.put(self.bits_pos[idx+31][1], self.bits_pos[idx+31][2],
136                  self.out_ann, [10, ['POR delay' + ': %d' % \
137                  (self.bits_pos[idx+31][0]),'%d' % (self.bits_pos[idx+31][0])]])
138
139     def put4bits(self, idx):
140         bits = self.bits_pos[idx][0]<<3 | self.bits_pos[idx+1][0]<<2 | \
141                self.bits_pos[idx+2][0]<<1 | self.bits_pos[idx+3][0]
142         self.put(self.bits_pos[idx][1], self.bits_pos[idx+3][2], self.out_ann,
143                  [10, ['%X' % bits]])
144
145     def em4100_decode1(self, idx):
146         self.put(self.bits_pos[idx][1], self.bits_pos[idx+8][2], self.out_ann,
147                  [10, ['EM4100 header', 'EM header', 'Header', 'H']])
148         self.put4bits(idx+9)
149         self.put4bits(idx+14)
150         self.put4bits(idx+19)
151         self.put4bits(idx+24)
152         self.em4100_decode1_partial = self.bits_pos[idx+29][0]<<3 | \
153             self.bits_pos[idx+30][0]<<2 | self.bits_pos[idx+31][0]<<1
154         self.put(self.bits_pos[idx+29][1], self.bits_pos[idx+31][2],
155                  self.out_ann, [10, ['Partial nibble']])
156
157     def em4100_decode2(self, idx):
158         if self.em4100_decode1_partial != 0:
159             bits = self.em4100_decode1_partial + self.bits_pos[idx][0]
160             self.put(self.bits_pos[idx][1], self.bits_pos[idx][2],
161                      self.out_ann, [10, ['%X' % bits]])
162             self.em4100_decode1_partial = 0
163         else:
164             self.put(self.bits_pos[idx][1], self.bits_pos[idx][2],
165                      self.out_ann, [10, ['Partial nibble']])
166
167         self.put4bits(idx+2)
168         self.put4bits(idx+7)
169         self.put4bits(idx+12)
170         self.put4bits(idx+17)
171         self.put4bits(idx+22)
172         self.put(self.bits_pos[idx+27][1], self.bits_pos[idx+31][2],
173                  self.out_ann, [10, ['EM4100 trailer']])
174
175     def get_32_bits(self, idx):
176         retval = 0
177         for i in range(0, 32):
178             retval <<= 1
179             retval |= self.bits_pos[i+idx][0]
180         return retval
181
182     def get_3_bits(self, idx):
183         retval = self.bits_pos[idx][0]<<2 | self.bits_pos[idx+1][0]<<1 | \
184                  self.bits_pos[idx+2][0]
185         return retval
186
187     def put_fields(self):
188         if (self.bit_nr == 70):
189             self.put(self.bits_pos[0][1], self.bits_pos[1][2], self.out_ann,
190                      [5, ['Opcode' + ': %d%d' % (self.bits_pos[0][0],
191                      self.bits_pos[1][0]), '%d%d' % (self.bits_pos[0][0],
192                      self.bits_pos[1][0])]])
193             password = self.get_32_bits(2)
194             self.put(self.bits_pos[2][1], self.bits_pos[33][2], self.out_ann,
195                      [8, ['Password' + ': %X' % password, '%X' % password]])
196             self.put(self.bits_pos[34][1], self.bits_pos[34][2], self.out_ann,
197                      [6, ['Lock' + ': %X' % self.bits_pos[34][0],
198                      '%X' % self.bits_pos[34][0]]])
199             data = self.get_32_bits(35)
200             self.put(self.bits_pos[35][1], self.bits_pos[66][2], self.out_ann,
201                      [7, ['Data' + ': %X' % data, '%X' % data]])
202             addr = self.get_3_bits(67)
203             self.put(self.bits_pos[67][1], self.bits_pos[69][2], self.out_ann,
204                      [9, ['Addr' + ': %X' % addr, '%X' % addr]])
205             if addr == 0:
206                 self.decode_config(35)
207             if addr == 7:
208                 self.put(self.bits_pos[35][1], self.bits_pos[66][2],
209                          self.out_ann, [10, ['Password' + ': %X' % data,
210                          '%X' % data]])
211             # If we are programming EM4100 data we can decode it halfway.
212             if addr == 1 and self.options['em4100_decode'] == 'on':
213                 self.em4100_decode1(35)
214             if addr == 2 and self.options['em4100_decode'] == 'on':
215                 self.em4100_decode2(35)
216
217         if (self.bit_nr == 38):
218             self.put(self.bits_pos[0][1], self.bits_pos[1][2], self.out_ann,
219                      [5, ['Opcode' + ': %d%d' % (self.bits_pos[0][0],
220                      self.bits_pos[1][0]), '%d%d' % (self.bits_pos[0][0],
221                      self.bits_pos[1][0])]])
222             self.put(self.bits_pos[2][1], self.bits_pos[2][2], self.out_ann,
223                      [6, ['Lock' + ': %X' % self.bits_pos[2][0],
224                      '%X' % self.bits_pos[2][0]]])
225             data = self.get_32_bits(3)
226             self.put(self.bits_pos[3][1], self.bits_pos[34][2], self.out_ann,
227                      [7, ['Data' + ': %X' % data, '%X' % data]])
228             addr = self.get_3_bits(35)
229             self.put(self.bits_pos[35][1], self.bits_pos[37][2], self.out_ann,
230                      [9, ['Addr' + ': %X' % addr, '%X' % addr]])
231             if addr == 0:
232                 self.decode_config(3)
233             if addr == 7:
234                 self.put(self.bits_pos[3][1], self.bits_pos[34][2],
235                          self.out_ann, [10, ['Password' + ': %X' % data,
236                          '%X' % data]])
237             # If we are programming EM4100 data we can decode it halfway.
238             if addr == 1 and self.options['em4100_decode'] == 'on':
239                 self.em4100_decode1(3)
240             if addr == 2 and self.options['em4100_decode'] == 'on':
241                 self.em4100_decode2(3)
242
243         if (self.bit_nr == 2):
244             self.put(self.bits_pos[0][1], self.bits_pos[1][2], self.out_ann,
245                      [5, ['Opcode' + ': %d%d' % (self.bits_pos[0][0],
246                      self.bits_pos[1][0]), '%d%d' % (self.bits_pos[0][0],
247                      self.bits_pos[1][0])]])
248         self.bit_nr = 0
249
250     def add_bits_pos(self, bit, bit_start, bit_end):
251         if self.bit_nr < 70:
252             self.bits_pos[self.bit_nr][0] = bit
253             self.bits_pos[self.bit_nr][1] = bit_start
254             self.bits_pos[self.bit_nr][2] = bit_end
255             self.bit_nr += 1
256
257     def decode(self, ss, es, data):
258         if not self.samplerate:
259             raise SamplerateError('Cannot decode without samplerate.')
260         for (self.samplenum, (pin,)) in data:
261             # Ignore identical samples early on (for performance reasons).
262             if self.oldpin == pin:
263                 continue
264
265             if self.oldpin is None:
266                 self.oldpin = pin
267                 self.last_samplenum = self.samplenum
268                 self.lastlast_samplenum = self.samplenum
269                 self.last_edge = self.samplenum
270                 self.oldpl = 0
271                 self.oldpp = 0
272                 self.oldsamplenum = 0
273                 self.last_bit_pos = 0
274
275                 self.old_gap_start = 0
276                 self.old_gap_end = 0
277                 self.gap_detected = 0
278                 self.bit_nr = 0
279                 continue
280
281             if self.oldpin != pin:
282                 pl = self.samplenum - self.oldsamplenum
283                 pp = pin
284                 samples = self.samplenum - self.last_samplenum
285
286                 if self.state == 'WRITE_GAP':
287                     if pl > self.writegap:
288                         self.gap_detected = 1
289                         self.put(self.last_samplenum, self.samplenum,
290                                  self.out_ann, [2, ['Write gap']])
291                     if (self.last_samplenum-self.old_gap_end) > self.nogap:
292                         self.gap_detected = 0
293                         self.state = 'START_GAP'
294                         self.put(self.old_gap_end, self.last_samplenum,
295                                  self.out_ann, [3, ['Write mode exit']])
296                         self.put_fields()
297
298                 if self.state == 'START_GAP':
299                     if pl > self.startgap:
300                         self.gap_detected = 1
301                         self.put(self.last_samplenum, self.samplenum,
302                                  self.out_ann, [1, ['Start gap']])
303                         self.state = 'WRITE_GAP'
304
305                 if self.gap_detected == 1:
306                     self.gap_detected = 0
307                     if (self.last_samplenum - self.old_gap_end) > self.wzmin \
308                             and (self.last_samplenum - self.old_gap_end) < self.wzmax:
309                         self.put(self.old_gap_end, self.last_samplenum,
310                                  self.out_ann, [0, ['0']])
311                         self.put(self.old_gap_end, self.last_samplenum,
312                                  self.out_ann, [4, ['Bit']])
313                         self.add_bits_pos(0, self.old_gap_end,
314                                           self.last_samplenum)
315                     if (self.last_samplenum - self.old_gap_end) > self.womin \
316                             and (self.last_samplenum - self.old_gap_end) < self.womax:
317                         self.put(self.old_gap_end, self.last_samplenum,
318                                  self.out_ann, [0, ['1']])
319                         self.put(self.old_gap_end, self.last_samplenum,
320                                  self.out_ann, [4, ['Bit']])
321                         self.add_bits_pos(1, self.old_gap_end, self.last_samplenum)
322
323                     self.old_gap_start = self.last_samplenum
324                     self.old_gap_end = self.samplenum
325
326                 self.oldpl = pl
327                 self.oldpp = pp
328                 self.oldsamplenum = self.samplenum
329                 self.last_samplenum = self.samplenum
330                 self.oldpin = pin