]> sigrok.org Git - libsigrokdecode.git/blame - decoders/em4305/pd.py
decoders: Add/update tags for each PD.
[libsigrokdecode.git] / decoders / em4305 / pd.py
CommitLineData
ae2181cd
BL
1##
2## This file is part of the libsigrokdecode project.
3##
4## Copyright (C) 2016 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
4539e9ca 17## along with this program; if not, see <http://www.gnu.org/licenses/>.
ae2181cd
BL
18##
19
20import sigrokdecode as srd
21
22class SamplerateError(Exception):
23 pass
24
25class Decoder(srd.Decoder):
d47dd3d9 26 api_version = 3
ae2181cd
BL
27 id = 'em4305'
28 name = 'EM4305'
29 longname = 'RFID EM4205/EM4305'
30 desc = 'EM4205/EM4305 100-150kHz RFID protocol.'
31 license = 'gplv2+'
32 inputs = ['logic']
33 outputs = ['em4305']
d6d8a8a4 34 tags = ['IC', 'RFID']
ae2181cd
BL
35 channels = (
36 {'id': 'data', 'name': 'Data', 'desc': 'Data line'},
37 )
38 options = (
39 {'id': 'coilfreq', 'desc': 'Coil frequency', 'default': 125000},
40 {'id': 'first_field_stop', 'desc': 'First field stop min', 'default': 40},
41 {'id': 'w_gap', 'desc': 'Write gap min', 'default': 12},
42 {'id': 'w_one_max', 'desc': 'Write one max', 'default': 32},
43 {'id': 'w_zero_on_min', 'desc': 'Write zero on min', 'default': 15},
44 {'id': 'w_zero_off_max', 'desc': 'Write zero off max', 'default': 27},
45 {'id': 'em4100_decode', 'desc': 'EM4100 decode', 'default': 'on',
46 'values': ('on', 'off')},
47 )
48 annotations = (
49 ('bit_value', 'Bit value'),
50 ('first_field_stop', 'First field stop'),
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):
10aeb8ea
GS
69 self.reset()
70
71 def reset(self):
ae2181cd 72 self.samplerate = None
ae2181cd
BL
73 self.last_samplenum = None
74 self.state = 'FFS_SEARCH'
75 self.bits_pos = [[0 for col in range(3)] for row in range(70)]
76 self.br_string = ['RF/8', 'RF/16', 'Unused', 'RF/32', 'RF/40',
77 'Unused', 'Unused', 'RF/64',]
78 self.encoder = ['not used', 'Manchester', 'Bi-phase', 'not used']
79 self.delayed_on = ['No delay', 'Delayed on - BP/8', 'Delayed on - BP/4', 'No delay']
80 self.em4100_decode1_partial = 0
81 self.cmds = ['Invalid', 'Login', 'Write word', 'Invalid', 'Read word', 'Disable', 'Protect', 'Invalid']
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_off_max'] * self.field_clock
88 self.wzmin = self.options['w_zero_on_min'] * self.field_clock
89 self.womax = self.options['w_one_max'] * self.field_clock
90 self.ffs = self.options['first_field_stop'] * self.field_clock
91 self.writegap = self.options['w_gap'] * self.field_clock
92 self.nogap = 300 * self.field_clock
93
94 def start(self):
95 self.out_ann = self.register(srd.OUTPUT_ANN)
96
97 def decode_config(self, idx):
98 bitrate = self.get_3_bits(idx+2)
99 self.put(self.bits_pos[idx][1], self.bits_pos[idx+5][2],
100 self.out_ann, [10, ['Data rate: ' + \
101 self.br_string[bitrate], self.br_string[bitrate]]])
102 encoding = self.bits_pos[idx+6][0]<<0 | self.bits_pos[idx+7][0]<<1
103 self.put(self.bits_pos[idx+6][1], self.bits_pos[idx+10][2],
104 self.out_ann, [10, ['Encoder: ' + \
105 self.encoder[encoding], self.encoder[encoding]]])
106 self.put(self.bits_pos[idx+11][1], self.bits_pos[idx+12][2], self.out_ann,
107 [10, ['Zero bits', 'ZB']])
108 delay_on = self.bits_pos[idx+13][0]<<0 | self.bits_pos[idx+14][0]<<1
109 self.put(self.bits_pos[idx+13][1], self.bits_pos[idx+14][2],
110 self.out_ann, [10, ['Delayed on: ' + \
111 self.delayed_on[delay_on], self.delayed_on[delay_on]]])
112 lwr = self.bits_pos[idx+15][0]<<3 | self.bits_pos[idx+16][0]<<2 | \
113 self.bits_pos[idx+18][0]<<1 | self.bits_pos[idx+19][0]<<0
114 self.put(self.bits_pos[idx+15][1], self.bits_pos[idx+19][2],
115 self.out_ann, [10, ['Last default read word: %d' % lwr, 'LWR: %d' % lwr, '%d' % lwr]])
116 self.put(self.bits_pos[idx+20][1], self.bits_pos[idx+20][2],
117 self.out_ann, [10, ['Read login: %d' % self.bits_pos[idx+20][0], '%d' % self.bits_pos[idx+20][0]]])
118 self.put(self.bits_pos[idx+21][1], self.bits_pos[idx+21][2], self.out_ann,
119 [10, ['Zero bits', 'ZB']])
120 self.put(self.bits_pos[idx+22][1], self.bits_pos[idx+22][2],
121 self.out_ann, [10, ['Write login: %d' % self.bits_pos[idx+22][0], '%d' % self.bits_pos[idx+22][0]]])
122 self.put(self.bits_pos[idx+23][1], self.bits_pos[idx+24][2], self.out_ann,
123 [10, ['Zero bits', 'ZB']])
124 self.put(self.bits_pos[idx+25][1], self.bits_pos[idx+25][2],
125 self.out_ann, [10, ['Disable: %d' % self.bits_pos[idx+25][0], '%d' % self.bits_pos[idx+25][0]]])
126 self.put(self.bits_pos[idx+27][1], self.bits_pos[idx+27][2],
127 self.out_ann, [10, ['Reader talk first: %d' % self.bits_pos[idx+27][0], 'RTF: %d' % self.bits_pos[idx+27][0]]])
128 self.put(self.bits_pos[idx+28][1], self.bits_pos[idx+28][2], self.out_ann,
129 [10, ['Zero bits', 'ZB']])
130 self.put(self.bits_pos[idx+29][1], self.bits_pos[idx+29][2],
131 self.out_ann, [10, ['Pigeon mode: %d' % self.bits_pos[idx+29][0], '%d' % self.bits_pos[idx+29][0]]])
132 self.put(self.bits_pos[idx+30][1], self.bits_pos[idx+34][2],
133 self.out_ann, [10, ['Reserved', 'Res', 'R']])
134
135 def put4bits(self, idx):
136 bits = self.bits_pos[idx][0]<<3 | self.bits_pos[idx+1][0]<<2 | \
137 self.bits_pos[idx+2][0]<<1 | self.bits_pos[idx+3][0]
138 self.put(self.bits_pos[idx][1], self.bits_pos[idx+3][2], self.out_ann,
139 [10, ['%X' % bits]])
140
141 def em4100_decode1(self, idx):
142 self.put(self.bits_pos[idx][1], self.bits_pos[idx+9][2], self.out_ann,
143 [10, ['EM4100 header', 'EM header', 'Header', 'H']])
144 self.put4bits(idx+10)
145 bits = self.bits_pos[idx+15][0]<<3 | self.bits_pos[idx+16][0]<<2 | \
146 self.bits_pos[idx+18][0]<<1 | self.bits_pos[idx+19][0]<<0
147 self.put(self.bits_pos[idx+15][1], self.bits_pos[idx+19][2], self.out_ann,
148 [10, ['%X' % bits]])
149 self.put4bits(idx+21)
150 self.put4bits(idx+27)
151 self.em4100_decode1_partial = self.bits_pos[idx+32][0]<<3 | \
152 self.bits_pos[idx+33][0]<<2 | self.bits_pos[idx+34][0]<<1
153 self.put(self.bits_pos[idx+32][1], self.bits_pos[idx+34][2],
154 self.out_ann, [10, ['Partial nibble']])
155
156 def em4100_decode2(self, idx):
157 if self.em4100_decode1_partial != 0:
158 bits = self.em4100_decode1_partial + self.bits_pos[idx][0]
159 self.put(self.bits_pos[idx][1], self.bits_pos[idx][2],
160 self.out_ann, [10, ['%X' % bits]])
161 self.em4100_decode1_partial = 0
162 else:
163 self.put(self.bits_pos[idx][1], self.bits_pos[idx][2],
164 self.out_ann, [10, ['Partial nibble']])
165
166 self.put4bits(idx+2)
167 bits = self.bits_pos[idx+7][0]<<3 | self.bits_pos[idx+9][0]<<2 | \
168 self.bits_pos[idx+10][0]<<1 | self.bits_pos[idx+11][0]<<0
169 self.put(self.bits_pos[idx+7][1], self.bits_pos[idx+11][2], self.out_ann,
170 [10, ['%X' % bits]])
171 self.put4bits(idx+13)
172 self.put4bits(idx+19)
173 bits = self.bits_pos[idx+24][0]<<3 | self.bits_pos[idx+25][0]<<2 | \
174 self.bits_pos[idx+27][0]<<1 | self.bits_pos[idx+28][0]<<0
175 self.put(self.bits_pos[idx+24][1], self.bits_pos[idx+28][2], self.out_ann,
176 [10, ['%X' % bits]])
177 self.put(self.bits_pos[idx+30][1], self.bits_pos[idx+34][2],
178 self.out_ann, [10, ['EM4100 trailer']])
179
180 def get_32_bits(self, idx):
181 return self.get_8_bits(idx+27)<<24 | self.get_8_bits(idx+18)<<16 | \
182 self.get_8_bits(idx+9)<<8 | self.get_8_bits(idx)
183
184 def get_8_bits(self, idx):
185 retval = 0
186 for i in range(0, 8):
187 retval <<= 1
188 retval |= self.bits_pos[i+idx][0]
189 return retval
190
191 def get_3_bits(self, idx):
192 return self.bits_pos[idx][0]<<2 | self.bits_pos[idx+1][0]<<1 | \
193 self.bits_pos[idx+2][0]
194
195 def get_4_bits(self, idx):
196 return self.bits_pos[idx][0]<<0 | self.bits_pos[idx+1][0]<<1 | \
197 self.bits_pos[idx+2][0]<<2 | self.bits_pos[idx+3][0]<<3
198
199 def print_row_parity(self, idx, length):
200 parity = 0
201 for i in range(0, length):
202 parity += self.bits_pos[i+idx][0]
203 parity = parity & 0x1
204 if parity == self.bits_pos[idx+length][0]:
205 self.put(self.bits_pos[idx+length][1], self.bits_pos[idx+length][2], self.out_ann,
206 [5, ['Row parity OK', 'Parity OK', 'OK']])
207 else:
208 self.put(self.bits_pos[idx+length][1], self.bits_pos[idx+length][2], self.out_ann,
209 [5, ['Row parity failed', 'Parity failed', 'Fail']])
210
211 def print_col_parity(self, idx):
212 data_1 = self.get_8_bits(idx)
213 data_2 = self.get_8_bits(idx+9)
214 data_3 = self.get_8_bits(idx+9+9)
215 data_4 = self.get_8_bits(idx+9+9+9)
216 col_par = self.get_8_bits(idx+9+9+9+9)
217 col_par_calc = data_1^data_2^data_3^data_4
218
219 if col_par == col_par_calc:
220 self.put(self.bits_pos[idx+9+9+9+9][1], self.bits_pos[idx+9+9+9+9+7][2], self.out_ann,
221 [5, ['Column parity OK', 'Parity OK', 'OK']])
222 else:
223 self.put(self.bits_pos[idx+9+9+9+9][1], self.bits_pos[idx+9+9+9+9+7][2], self.out_ann,
224 [5, ['Column parity failed', 'Parity failed', 'Fail']])
225
226 def print_8bit_data(self, idx):
227 data = self.get_8_bits(idx)
228 self.put(self.bits_pos[idx][1], self.bits_pos[idx+7][2], self.out_ann,
229 [9, ['Data' + ': %X' % data, '%X' % data]])
230
231 def put_fields(self):
232 if self.bit_nr == 50:
233 self.put(self.bits_pos[0][1], self.bits_pos[0][2], self.out_ann,
234 [4, ['Logic zero']])
235 self.put(self.bits_pos[1][1], self.bits_pos[4][2], self.out_ann,
236 [4, ['Command', 'Cmd', 'C']])
237 self.put(self.bits_pos[5][1], self.bits_pos[49][2], self.out_ann,
238 [4, ['Password', 'Passwd', 'Pass', 'P']])
239 # Get command.
240 cmd = self.get_3_bits(1)
241 self.put(self.bits_pos[1][1], self.bits_pos[3][2], self.out_ann,
242 [5, [self.cmds[cmd]]])
243 self.print_row_parity(1, 3)
244
245 # Print data.
246 self.print_8bit_data(5)
247 self.print_row_parity(5, 8)
248 self.print_8bit_data(14)
249 self.print_row_parity(14, 8)
250 self.print_8bit_data(23)
251 self.print_row_parity(23, 8)
252 self.print_8bit_data(32)
253 self.print_row_parity(32, 8)
254 self.print_col_parity(5)
255 if self.bits_pos[49][0] == 0:
256 self.put(self.bits_pos[49][1], self.bits_pos[49][2], self.out_ann,
257 [5, ['Stop bit', 'Stop', 'SB']])
258 else:
259 self.put(self.bits_pos[49][1], self.bits_pos[49][2], self.out_ann,
260 [5, ['Stop bit error', 'Error']])
261
262 if cmd == 1:
263 password = self.get_32_bits(5)
264 self.put(self.bits_pos[12][1], self.bits_pos[46][2], self.out_ann,
265 [10, ['Login password: %X' % password]])
266
267 if self.bit_nr == 57:
268 self.put(self.bits_pos[0][1], self.bits_pos[0][2], self.out_ann,
269 [4, ['Logic zero', 'LZ']])
270 self.put(self.bits_pos[1][1], self.bits_pos[4][2], self.out_ann,
271 [4, ['Command', 'Cmd', 'C']])
272 self.put(self.bits_pos[5][1], self.bits_pos[11][2], self.out_ann,
273 [4, ['Address', 'Addr', 'A']])
274 self.put(self.bits_pos[12][1], self.bits_pos[56][2], self.out_ann,
275 [4, ['Data', 'Da', 'D']])
276
277 # Get command.
278 cmd = self.get_3_bits(1)
279 self.put(self.bits_pos[1][1], self.bits_pos[3][2], self.out_ann,
280 [5, [self.cmds[cmd]]])
281 self.print_row_parity(1, 3)
282
283 # Get address.
284 addr = self.get_4_bits(5)
285 self.put(self.bits_pos[5][1], self.bits_pos[8][2], self.out_ann,
286 [9, ['Addr' + ': %d' % addr, '%d' % addr]])
287 self.put(self.bits_pos[9][1], self.bits_pos[10][2], self.out_ann,
288 [5, ['Zero bits', 'ZB']])
289 self.print_row_parity(5, 6)
290 # Print data.
291 self.print_8bit_data(12)
292 self.print_row_parity(12, 8)
293 self.print_8bit_data(21)
294 self.print_row_parity(21, 8)
295 self.print_8bit_data(30)
296 self.print_row_parity(30, 8)
297 self.print_8bit_data(39)
298 self.print_row_parity(39, 8)
299 self.print_col_parity(12)
300 if self.bits_pos[56][0] == 0:
301 self.put(self.bits_pos[56][1], self.bits_pos[56][2], self.out_ann,
302 [5, ['Stop bit', 'Stop', 'SB']])
303 else:
304 self.put(self.bits_pos[56][1], self.bits_pos[56][2], self.out_ann,
305 [5, ['Stop bit error', 'Error']])
306
307 if addr == 4:
308 self.decode_config(12)
309
310 if addr == 2:
311 password = self.get_32_bits(12)
312 self.put(self.bits_pos[12][1], self.bits_pos[46][2], self.out_ann,
313 [10, ['Write password: %X' % password]])
314
315 # If we are programming EM4100 data we can decode it halfway.
316 if addr == 5 and self.options['em4100_decode'] == 'on':
317 self.em4100_decode1(12)
318 if addr == 6 and self.options['em4100_decode'] == 'on':
319 self.em4100_decode2(12)
320
321 self.bit_nr = 0
322
323 def add_bits_pos(self, bit, ss_bit, es_bit):
324 if self.bit_nr < 70:
325 self.bits_pos[self.bit_nr][0] = bit
326 self.bits_pos[self.bit_nr][1] = ss_bit
327 self.bits_pos[self.bit_nr][2] = es_bit
328 self.bit_nr += 1
329
d47dd3d9 330 def decode(self):
ae2181cd
BL
331 if not self.samplerate:
332 raise SamplerateError('Cannot decode without samplerate.')
d47dd3d9
GS
333
334 # Initialize internal state.
335 self.last_samplenum = self.samplenum
336 self.oldsamplenum = 0
337 self.old_gap_end = 0
338 self.gap_detected = 0
339 self.bit_nr = 0
340
341 while True:
342 # Ignore identical samples, only process edges.
343 (pin,) = self.wait({0: 'e'})
344
345 pl = self.samplenum - self.oldsamplenum
346 pp = pin
347 samples = self.samplenum - self.last_samplenum
348
349 if self.state == 'FFS_DETECTED':
350 if pl > self.writegap:
351 self.gap_detected = 1
352 if (self.last_samplenum - self.old_gap_end) > self.nogap:
ae2181cd 353 self.gap_detected = 0
ae2181cd 354 self.state = 'FFS_SEARCH'
d47dd3d9
GS
355 self.put(self.old_gap_end, self.last_samplenum,
356 self.out_ann, [3, ['Write mode exit']])
357 self.put_fields()
358
359 if self.state == 'FFS_SEARCH':
360 if pl > self.ffs:
361 self.gap_detected = 1
362 self.put(self.last_samplenum, self.samplenum,
363 self.out_ann, [1, ['First field stop', 'Field stop', 'FFS']])
364 self.state = 'FFS_DETECTED'
365
366 if self.gap_detected == 1:
367 self.gap_detected = 0
368 if (self.last_samplenum - self.old_gap_end) > self.wzmin \
369 and (self.last_samplenum - self.old_gap_end) < self.wzmax:
370 self.put(self.old_gap_end, self.samplenum,
371 self.out_ann, [0, ['0']])
372 self.add_bits_pos(0, self.old_gap_end, self.samplenum)
373 if (self.last_samplenum - self.old_gap_end) > self.womax \
374 and (self.last_samplenum-self.old_gap_end) < self.nogap:
375 # One or more 1 bits
376 one_bits = (int)((self.last_samplenum - self.old_gap_end) / self.womax)
377 for ox in range(0, one_bits):
378 bs = (int)(self.old_gap_end+ox*self.womax)
379 be = (int)(self.old_gap_end+ox*self.womax + self.womax)
380 self.put(bs, be, self.out_ann, [0, ['1']])
381 self.add_bits_pos(1, bs, be)
382 if (self.samplenum - self.last_samplenum) > self.wzmin \
383 and (self.samplenum - self.last_samplenum) < self.wzmax:
384 bs = (int)(self.old_gap_end+one_bits*self.womax)
385 self.put(bs, self.samplenum, self.out_ann, [0, ['0']])
386 self.add_bits_pos(0, bs, self.samplenum)
387
388 self.old_gap_end = self.samplenum
389
390 if self.state == 'SKIP':
391 self.state = 'FFS_SEARCH'
392
393 self.oldsamplenum = self.samplenum
394 self.last_samplenum = self.samplenum