]>
Commit | Line | Data |
---|---|---|
e2bc7a1e BL |
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 | |
88df2c9a UH |
8 | ## the Free Software Foundation; either version 2 of the License, or |
9 | ## (at your option) any later version. | |
e2bc7a1e BL |
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 | |
4539e9ca | 17 | ## along with this program; if not, see <http://www.gnu.org/licenses/>. |
e2bc7a1e BL |
18 | ## |
19 | ||
20 | import sigrokdecode as srd | |
21 | ||
22 | class SamplerateError(Exception): | |
23 | pass | |
24 | ||
25 | class Decoder(srd.Decoder): | |
c551f324 | 26 | api_version = 3 |
e2bc7a1e BL |
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 | ||
92b7b49f | 68 | def __init__(self): |
10aeb8ea GS |
69 | self.reset() |
70 | ||
71 | def reset(self): | |
e2bc7a1e | 72 | self.samplerate = None |
e2bc7a1e BL |
73 | self.last_samplenum = None |
74 | self.lastlast_samplenum = None | |
75 | self.state = 'START_GAP' | |
76 | self.bits_pos = [[0 for col in range(3)] for row in range(70)] | |
77 | self.br_string = ['RF/8', 'RF/16', 'RF/32', 'RF/40', | |
78 | 'RF/50', 'RF/64', 'RF/100', 'RF/128'] | |
79 | self.mod_str1 = ['Direct', 'Manchester', 'Biphase', 'Reserved'] | |
80 | self.mod_str2 = ['Direct', 'PSK1', 'PSK2', 'PSK3', 'FSK1', 'FSK2', | |
81 | 'FSK1a', 'FSK2a'] | |
82 | self.pskcf_str = ['RF/2', 'RF/4', 'RF/8', 'Reserved'] | |
83 | self.em4100_decode1_partial = 0 | |
84 | ||
85 | def metadata(self, key, value): | |
86 | if key == srd.SRD_CONF_SAMPLERATE: | |
87 | self.samplerate = value | |
88 | self.field_clock = self.samplerate / self.options['coilfreq'] | |
89 | self.wzmax = self.options['w_zero_max'] * self.field_clock | |
90 | self.wzmin = self.options['w_zero_min'] * self.field_clock | |
91 | self.womax = self.options['w_one_max'] * self.field_clock | |
92 | self.womin = self.options['w_one_min'] * self.field_clock | |
93 | self.startgap = self.options['start_gap'] * self.field_clock | |
94 | self.writegap = self.options['w_gap'] * self.field_clock | |
95 | self.nogap = 64 * self.field_clock | |
96 | ||
97 | def start(self): | |
98 | self.out_ann = self.register(srd.OUTPUT_ANN) | |
99 | ||
100 | def decode_config(self, idx): | |
101 | safer_key = self.bits_pos[idx][0]<<3 | self.bits_pos[idx+1][0]<<2 | \ | |
102 | self.bits_pos[idx+2][0]<<1 | self.bits_pos[idx+3][0] | |
103 | self.put(self.bits_pos[idx][1], self.bits_pos[idx+3][2], self.out_ann, | |
104 | [10, ['Safer Key' + ': %X' % safer_key,'%X' % safer_key]]) | |
105 | bitrate = self.bits_pos[idx+11][0]<<2 | self.bits_pos[idx+12][0]<<1 | \ | |
106 | self.bits_pos[idx+13][0] | |
107 | self.put(self.bits_pos[idx+11][1], self.bits_pos[idx+13][2], | |
108 | self.out_ann, [10, ['Data Bit Rate: ' + \ | |
109 | self.br_string[bitrate], self.br_string[bitrate]]]) | |
110 | modulation1 = self.bits_pos[idx+15][0]<<1 | self.bits_pos[idx+16][0] | |
111 | modulation2 = self.bits_pos[idx+17][0]<<2 | \ | |
112 | self.bits_pos[idx+18][0]<<1 | self.bits_pos[idx+19][0] | |
113 | if modulation1 == 0: | |
114 | mod_string = self.mod_str2[modulation2] | |
115 | else: | |
116 | mod_string = self.mod_str1[modulation1] | |
117 | self.put(self.bits_pos[idx+15][1], self.bits_pos[idx+19][2], | |
118 | self.out_ann, [10, ['Modulation: ' + mod_string, mod_string]]) | |
119 | psk_cf = self.bits_pos[idx+20][0]<<1 | self.bits_pos[idx+21][0] | |
120 | self.put(self.bits_pos[idx+20][1], self.bits_pos[idx+21][2], | |
121 | self.out_ann, [10, ['PSK-CF: ' + self.pskcf_str[psk_cf], | |
122 | self.pskcf_str[psk_cf]]]) | |
123 | self.put(self.bits_pos[idx+22][1], self.bits_pos[idx+22][2], | |
124 | self.out_ann, [10, ['AOR' + ': %d' % \ | |
125 | (self.bits_pos[idx+22][0]),'%d' % (self.bits_pos[idx+22][0])]]) | |
126 | maxblock = self.bits_pos[idx+24][0]<<2 | self.bits_pos[idx+25][0]<<1 | \ | |
127 | self.bits_pos[idx+26][0] | |
128 | self.put(self.bits_pos[idx+24][1], self.bits_pos[idx+26][2], | |
129 | self.out_ann, [10, ['Max-Block' + ': %d' % maxblock, | |
130 | '%d' % maxblock]]) | |
131 | self.put(self.bits_pos[idx+27][1], self.bits_pos[idx+27][2], | |
132 | self.out_ann, [10, ['PWD' + ': %d' % \ | |
133 | (self.bits_pos[idx+27][0]),'%d' % (self.bits_pos[idx+27][0])]]) | |
134 | self.put(self.bits_pos[idx+28][1], self.bits_pos[idx+28][2], | |
135 | self.out_ann, [10, ['ST-sequence terminator' + ': %d' % \ | |
136 | (self.bits_pos[idx+28][0]),'%d' % (self.bits_pos[idx+28][0])]]) | |
137 | self.put(self.bits_pos[idx+31][1], self.bits_pos[idx+31][2], | |
138 | self.out_ann, [10, ['POR delay' + ': %d' % \ | |
139 | (self.bits_pos[idx+31][0]),'%d' % (self.bits_pos[idx+31][0])]]) | |
140 | ||
141 | def put4bits(self, idx): | |
142 | bits = self.bits_pos[idx][0]<<3 | self.bits_pos[idx+1][0]<<2 | \ | |
143 | self.bits_pos[idx+2][0]<<1 | self.bits_pos[idx+3][0] | |
144 | self.put(self.bits_pos[idx][1], self.bits_pos[idx+3][2], self.out_ann, | |
145 | [10, ['%X' % bits]]) | |
146 | ||
147 | def em4100_decode1(self, idx): | |
148 | self.put(self.bits_pos[idx][1], self.bits_pos[idx+8][2], self.out_ann, | |
149 | [10, ['EM4100 header', 'EM header', 'Header', 'H']]) | |
150 | self.put4bits(idx+9) | |
151 | self.put4bits(idx+14) | |
152 | self.put4bits(idx+19) | |
153 | self.put4bits(idx+24) | |
154 | self.em4100_decode1_partial = self.bits_pos[idx+29][0]<<3 | \ | |
155 | self.bits_pos[idx+30][0]<<2 | self.bits_pos[idx+31][0]<<1 | |
156 | self.put(self.bits_pos[idx+29][1], self.bits_pos[idx+31][2], | |
157 | self.out_ann, [10, ['Partial nibble']]) | |
158 | ||
159 | def em4100_decode2(self, idx): | |
160 | if self.em4100_decode1_partial != 0: | |
161 | bits = self.em4100_decode1_partial + self.bits_pos[idx][0] | |
162 | self.put(self.bits_pos[idx][1], self.bits_pos[idx][2], | |
163 | self.out_ann, [10, ['%X' % bits]]) | |
164 | self.em4100_decode1_partial = 0 | |
165 | else: | |
166 | self.put(self.bits_pos[idx][1], self.bits_pos[idx][2], | |
167 | self.out_ann, [10, ['Partial nibble']]) | |
168 | ||
169 | self.put4bits(idx+2) | |
170 | self.put4bits(idx+7) | |
171 | self.put4bits(idx+12) | |
172 | self.put4bits(idx+17) | |
173 | self.put4bits(idx+22) | |
174 | self.put(self.bits_pos[idx+27][1], self.bits_pos[idx+31][2], | |
175 | self.out_ann, [10, ['EM4100 trailer']]) | |
176 | ||
177 | def get_32_bits(self, idx): | |
178 | retval = 0 | |
179 | for i in range(0, 32): | |
180 | retval <<= 1 | |
181 | retval |= self.bits_pos[i+idx][0] | |
182 | return retval | |
183 | ||
184 | def get_3_bits(self, idx): | |
185 | retval = self.bits_pos[idx][0]<<2 | self.bits_pos[idx+1][0]<<1 | \ | |
186 | self.bits_pos[idx+2][0] | |
187 | return retval | |
188 | ||
189 | def put_fields(self): | |
190 | if (self.bit_nr == 70): | |
191 | self.put(self.bits_pos[0][1], self.bits_pos[1][2], self.out_ann, | |
192 | [5, ['Opcode' + ': %d%d' % (self.bits_pos[0][0], | |
193 | self.bits_pos[1][0]), '%d%d' % (self.bits_pos[0][0], | |
194 | self.bits_pos[1][0])]]) | |
195 | password = self.get_32_bits(2) | |
196 | self.put(self.bits_pos[2][1], self.bits_pos[33][2], self.out_ann, | |
197 | [8, ['Password' + ': %X' % password, '%X' % password]]) | |
198 | self.put(self.bits_pos[34][1], self.bits_pos[34][2], self.out_ann, | |
199 | [6, ['Lock' + ': %X' % self.bits_pos[34][0], | |
200 | '%X' % self.bits_pos[34][0]]]) | |
201 | data = self.get_32_bits(35) | |
202 | self.put(self.bits_pos[35][1], self.bits_pos[66][2], self.out_ann, | |
203 | [7, ['Data' + ': %X' % data, '%X' % data]]) | |
204 | addr = self.get_3_bits(67) | |
205 | self.put(self.bits_pos[67][1], self.bits_pos[69][2], self.out_ann, | |
206 | [9, ['Addr' + ': %X' % addr, '%X' % addr]]) | |
207 | if addr == 0: | |
208 | self.decode_config(35) | |
209 | if addr == 7: | |
210 | self.put(self.bits_pos[35][1], self.bits_pos[66][2], | |
211 | self.out_ann, [10, ['Password' + ': %X' % data, | |
212 | '%X' % data]]) | |
213 | # If we are programming EM4100 data we can decode it halfway. | |
214 | if addr == 1 and self.options['em4100_decode'] == 'on': | |
215 | self.em4100_decode1(35) | |
216 | if addr == 2 and self.options['em4100_decode'] == 'on': | |
217 | self.em4100_decode2(35) | |
218 | ||
219 | if (self.bit_nr == 38): | |
220 | self.put(self.bits_pos[0][1], self.bits_pos[1][2], self.out_ann, | |
221 | [5, ['Opcode' + ': %d%d' % (self.bits_pos[0][0], | |
222 | self.bits_pos[1][0]), '%d%d' % (self.bits_pos[0][0], | |
223 | self.bits_pos[1][0])]]) | |
224 | self.put(self.bits_pos[2][1], self.bits_pos[2][2], self.out_ann, | |
225 | [6, ['Lock' + ': %X' % self.bits_pos[2][0], | |
226 | '%X' % self.bits_pos[2][0]]]) | |
227 | data = self.get_32_bits(3) | |
228 | self.put(self.bits_pos[3][1], self.bits_pos[34][2], self.out_ann, | |
229 | [7, ['Data' + ': %X' % data, '%X' % data]]) | |
230 | addr = self.get_3_bits(35) | |
231 | self.put(self.bits_pos[35][1], self.bits_pos[37][2], self.out_ann, | |
232 | [9, ['Addr' + ': %X' % addr, '%X' % addr]]) | |
233 | if addr == 0: | |
234 | self.decode_config(3) | |
235 | if addr == 7: | |
236 | self.put(self.bits_pos[3][1], self.bits_pos[34][2], | |
237 | self.out_ann, [10, ['Password' + ': %X' % data, | |
238 | '%X' % data]]) | |
239 | # If we are programming EM4100 data we can decode it halfway. | |
240 | if addr == 1 and self.options['em4100_decode'] == 'on': | |
241 | self.em4100_decode1(3) | |
242 | if addr == 2 and self.options['em4100_decode'] == 'on': | |
243 | self.em4100_decode2(3) | |
244 | ||
245 | if (self.bit_nr == 2): | |
246 | self.put(self.bits_pos[0][1], self.bits_pos[1][2], self.out_ann, | |
247 | [5, ['Opcode' + ': %d%d' % (self.bits_pos[0][0], | |
248 | self.bits_pos[1][0]), '%d%d' % (self.bits_pos[0][0], | |
249 | self.bits_pos[1][0])]]) | |
250 | self.bit_nr = 0 | |
251 | ||
252 | def add_bits_pos(self, bit, bit_start, bit_end): | |
253 | if self.bit_nr < 70: | |
254 | self.bits_pos[self.bit_nr][0] = bit | |
255 | self.bits_pos[self.bit_nr][1] = bit_start | |
256 | self.bits_pos[self.bit_nr][2] = bit_end | |
257 | self.bit_nr += 1 | |
258 | ||
c551f324 | 259 | def decode(self): |
e2bc7a1e BL |
260 | if not self.samplerate: |
261 | raise SamplerateError('Cannot decode without samplerate.') | |
e2bc7a1e | 262 | |
c551f324 GS |
263 | self.last_samplenum = 0 |
264 | self.lastlast_samplenum = 0 | |
265 | self.last_edge = 0 | |
266 | self.oldpl = 0 | |
267 | self.oldpp = 0 | |
268 | self.oldsamplenum = 0 | |
269 | self.last_bit_pos = 0 | |
270 | self.old_gap_start = 0 | |
271 | self.old_gap_end = 0 | |
272 | self.gap_detected = 0 | |
273 | self.bit_nr = 0 | |
e2bc7a1e | 274 | |
c551f324 GS |
275 | while True: |
276 | (pin,) = self.wait({0: 'e'}) | |
e2bc7a1e | 277 | |
c551f324 GS |
278 | pl = self.samplenum - self.oldsamplenum |
279 | pp = pin | |
280 | samples = self.samplenum - self.last_samplenum | |
e2bc7a1e | 281 | |
c551f324 GS |
282 | if self.state == 'WRITE_GAP': |
283 | if pl > self.writegap: | |
284 | self.gap_detected = 1 | |
285 | self.put(self.last_samplenum, self.samplenum, | |
286 | self.out_ann, [2, ['Write gap']]) | |
287 | if (self.last_samplenum-self.old_gap_end) > self.nogap: | |
288 | self.gap_detected = 0 | |
289 | self.state = 'START_GAP' | |
290 | self.put(self.old_gap_end, self.last_samplenum, | |
291 | self.out_ann, [3, ['Write mode exit']]) | |
292 | self.put_fields() | |
e2bc7a1e | 293 | |
c551f324 GS |
294 | if self.state == 'START_GAP': |
295 | if pl > self.startgap: | |
296 | self.gap_detected = 1 | |
297 | self.put(self.last_samplenum, self.samplenum, | |
298 | self.out_ann, [1, ['Start gap']]) | |
299 | self.state = 'WRITE_GAP' | |
e2bc7a1e | 300 | |
c551f324 GS |
301 | if self.gap_detected == 1: |
302 | self.gap_detected = 0 | |
303 | if (self.last_samplenum - self.old_gap_end) > self.wzmin \ | |
304 | and (self.last_samplenum - self.old_gap_end) < self.wzmax: | |
305 | self.put(self.old_gap_end, self.last_samplenum, | |
306 | self.out_ann, [0, ['0']]) | |
307 | self.put(self.old_gap_end, self.last_samplenum, | |
308 | self.out_ann, [4, ['Bit']]) | |
309 | self.add_bits_pos(0, self.old_gap_end, | |
310 | self.last_samplenum) | |
311 | if (self.last_samplenum - self.old_gap_end) > self.womin \ | |
312 | and (self.last_samplenum - self.old_gap_end) < self.womax: | |
313 | self.put(self.old_gap_end, self.last_samplenum, | |
314 | self.out_ann, [0, ['1']]) | |
315 | self.put(self.old_gap_end, self.last_samplenum, | |
316 | self.out_ann, [4, ['Bit']]) | |
317 | self.add_bits_pos(1, self.old_gap_end, self.last_samplenum) | |
e2bc7a1e | 318 | |
c551f324 GS |
319 | self.old_gap_start = self.last_samplenum |
320 | self.old_gap_end = self.samplenum | |
e2bc7a1e | 321 | |
c551f324 GS |
322 | self.oldpl = pl |
323 | self.oldpp = pp | |
324 | self.oldsamplenum = self.samplenum | |
325 | self.last_samplenum = self.samplenum |