2 ## This file is part of the libsigrokdecode project.
4 ## Copyright (C) 2016 Benjamin Larsson <benjamin@southpole.se>
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.
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.
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
21 import sigrokdecode as srd
23 class SamplerateError(Exception):
26 class Decoder(srd.Decoder):
30 longname = 'RFID EM4205/EM4305'
31 desc = 'EM4205/EM4305 100-150kHz RFID protocol.'
36 {'id': 'data', 'name': 'Data', 'desc': 'Data line'},
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')},
49 ('bit_value', 'Bit value'),
50 ('first_field_stop', 'First field stop'),
51 ('write_gap', 'Write gap'),
52 ('write_mode_exit', 'Write mode exit'),
57 ('password', 'Password'),
58 ('address', 'Address'),
59 ('bitrate', 'Bitrate'),
62 ('bits', 'Bits', (0,)),
63 ('structure', 'Structure', (1, 2, 3, 4)),
64 ('fields', 'Fields', (5, 6, 7, 8, 9)),
65 ('decode', 'Decode', (10,)),
69 self.samplerate = None
71 self.last_samplenum = None
72 self.state = 'FFS_SEARCH'
73 self.bits_pos = [[0 for col in range(3)] for row in range(70)]
74 self.br_string = ['RF/8', 'RF/16', 'Unused', 'RF/32', 'RF/40',
75 'Unused', 'Unused', 'RF/64',]
76 self.encoder = ['not used', 'Manchester', 'Bi-phase', 'not used']
77 self.delayed_on = ['No delay', 'Delayed on - BP/8', 'Delayed on - BP/4', 'No delay']
78 self.em4100_decode1_partial = 0
79 self.cmds = ['Invalid', 'Login', 'Write word', 'Invalid', 'Read word', 'Disable', 'Protect', 'Invalid']
81 def metadata(self, key, value):
82 if key == srd.SRD_CONF_SAMPLERATE:
83 self.samplerate = value
84 self.field_clock = self.samplerate / self.options['coilfreq']
85 self.wzmax = self.options['w_zero_off_max'] * self.field_clock
86 self.wzmin = self.options['w_zero_on_min'] * self.field_clock
87 self.womax = self.options['w_one_max'] * self.field_clock
88 self.ffs = self.options['first_field_stop'] * self.field_clock
89 self.writegap = self.options['w_gap'] * self.field_clock
90 self.nogap = 300 * self.field_clock
93 self.out_ann = self.register(srd.OUTPUT_ANN)
95 def decode_config(self, idx):
96 bitrate = self.get_3_bits(idx+2)
97 self.put(self.bits_pos[idx][1], self.bits_pos[idx+5][2],
98 self.out_ann, [10, ['Data rate: ' + \
99 self.br_string[bitrate], self.br_string[bitrate]]])
100 encoding = self.bits_pos[idx+6][0]<<0 | self.bits_pos[idx+7][0]<<1
101 self.put(self.bits_pos[idx+6][1], self.bits_pos[idx+10][2],
102 self.out_ann, [10, ['Encoder: ' + \
103 self.encoder[encoding], self.encoder[encoding]]])
104 self.put(self.bits_pos[idx+11][1], self.bits_pos[idx+12][2], self.out_ann,
105 [10, ['Zero bits', 'ZB']])
106 delay_on = self.bits_pos[idx+13][0]<<0 | self.bits_pos[idx+14][0]<<1
107 self.put(self.bits_pos[idx+13][1], self.bits_pos[idx+14][2],
108 self.out_ann, [10, ['Delayed on: ' + \
109 self.delayed_on[delay_on], self.delayed_on[delay_on]]])
110 lwr = self.bits_pos[idx+15][0]<<3 | self.bits_pos[idx+16][0]<<2 | \
111 self.bits_pos[idx+18][0]<<1 | self.bits_pos[idx+19][0]<<0
112 self.put(self.bits_pos[idx+15][1], self.bits_pos[idx+19][2],
113 self.out_ann, [10, ['Last default read word: %d' % lwr, 'LWR: %d' % lwr, '%d' % lwr]])
114 self.put(self.bits_pos[idx+20][1], self.bits_pos[idx+20][2],
115 self.out_ann, [10, ['Read login: %d' % self.bits_pos[idx+20][0], '%d' % self.bits_pos[idx+20][0]]])
116 self.put(self.bits_pos[idx+21][1], self.bits_pos[idx+21][2], self.out_ann,
117 [10, ['Zero bits', 'ZB']])
118 self.put(self.bits_pos[idx+22][1], self.bits_pos[idx+22][2],
119 self.out_ann, [10, ['Write login: %d' % self.bits_pos[idx+22][0], '%d' % self.bits_pos[idx+22][0]]])
120 self.put(self.bits_pos[idx+23][1], self.bits_pos[idx+24][2], self.out_ann,
121 [10, ['Zero bits', 'ZB']])
122 self.put(self.bits_pos[idx+25][1], self.bits_pos[idx+25][2],
123 self.out_ann, [10, ['Disable: %d' % self.bits_pos[idx+25][0], '%d' % self.bits_pos[idx+25][0]]])
124 self.put(self.bits_pos[idx+27][1], self.bits_pos[idx+27][2],
125 self.out_ann, [10, ['Reader talk first: %d' % self.bits_pos[idx+27][0], 'RTF: %d' % self.bits_pos[idx+27][0]]])
126 self.put(self.bits_pos[idx+28][1], self.bits_pos[idx+28][2], self.out_ann,
127 [10, ['Zero bits', 'ZB']])
128 self.put(self.bits_pos[idx+29][1], self.bits_pos[idx+29][2],
129 self.out_ann, [10, ['Pigeon mode: %d' % self.bits_pos[idx+29][0], '%d' % self.bits_pos[idx+29][0]]])
130 self.put(self.bits_pos[idx+30][1], self.bits_pos[idx+34][2],
131 self.out_ann, [10, ['Reserved', 'Res', 'R']])
133 def put4bits(self, idx):
134 bits = self.bits_pos[idx][0]<<3 | self.bits_pos[idx+1][0]<<2 | \
135 self.bits_pos[idx+2][0]<<1 | self.bits_pos[idx+3][0]
136 self.put(self.bits_pos[idx][1], self.bits_pos[idx+3][2], self.out_ann,
139 def em4100_decode1(self, idx):
140 self.put(self.bits_pos[idx][1], self.bits_pos[idx+9][2], self.out_ann,
141 [10, ['EM4100 header', 'EM header', 'Header', 'H']])
142 self.put4bits(idx+10)
143 bits = self.bits_pos[idx+15][0]<<3 | self.bits_pos[idx+16][0]<<2 | \
144 self.bits_pos[idx+18][0]<<1 | self.bits_pos[idx+19][0]<<0
145 self.put(self.bits_pos[idx+15][1], self.bits_pos[idx+19][2], self.out_ann,
147 self.put4bits(idx+21)
148 self.put4bits(idx+27)
149 self.em4100_decode1_partial = self.bits_pos[idx+32][0]<<3 | \
150 self.bits_pos[idx+33][0]<<2 | self.bits_pos[idx+34][0]<<1
151 self.put(self.bits_pos[idx+32][1], self.bits_pos[idx+34][2],
152 self.out_ann, [10, ['Partial nibble']])
154 def em4100_decode2(self, idx):
155 if self.em4100_decode1_partial != 0:
156 bits = self.em4100_decode1_partial + self.bits_pos[idx][0]
157 self.put(self.bits_pos[idx][1], self.bits_pos[idx][2],
158 self.out_ann, [10, ['%X' % bits]])
159 self.em4100_decode1_partial = 0
161 self.put(self.bits_pos[idx][1], self.bits_pos[idx][2],
162 self.out_ann, [10, ['Partial nibble']])
165 bits = self.bits_pos[idx+7][0]<<3 | self.bits_pos[idx+9][0]<<2 | \
166 self.bits_pos[idx+10][0]<<1 | self.bits_pos[idx+11][0]<<0
167 self.put(self.bits_pos[idx+7][1], self.bits_pos[idx+11][2], self.out_ann,
169 self.put4bits(idx+13)
170 self.put4bits(idx+19)
171 bits = self.bits_pos[idx+24][0]<<3 | self.bits_pos[idx+25][0]<<2 | \
172 self.bits_pos[idx+27][0]<<1 | self.bits_pos[idx+28][0]<<0
173 self.put(self.bits_pos[idx+24][1], self.bits_pos[idx+28][2], self.out_ann,
175 self.put(self.bits_pos[idx+30][1], self.bits_pos[idx+34][2],
176 self.out_ann, [10, ['EM4100 trailer']])
178 def get_32_bits(self, idx):
179 return self.get_8_bits(idx+27)<<24 | self.get_8_bits(idx+18)<<16 | \
180 self.get_8_bits(idx+9)<<8 | self.get_8_bits(idx)
182 def get_8_bits(self, idx):
184 for i in range(0, 8):
186 retval |= self.bits_pos[i+idx][0]
189 def get_3_bits(self, idx):
190 return self.bits_pos[idx][0]<<2 | self.bits_pos[idx+1][0]<<1 | \
191 self.bits_pos[idx+2][0]
193 def get_4_bits(self, idx):
194 return self.bits_pos[idx][0]<<0 | self.bits_pos[idx+1][0]<<1 | \
195 self.bits_pos[idx+2][0]<<2 | self.bits_pos[idx+3][0]<<3
197 def print_row_parity(self, idx, length):
199 for i in range(0, length):
200 parity += self.bits_pos[i+idx][0]
201 parity = parity & 0x1
202 if parity == self.bits_pos[idx+length][0]:
203 self.put(self.bits_pos[idx+length][1], self.bits_pos[idx+length][2], self.out_ann,
204 [5, ['Row parity OK', 'Parity OK', 'OK']])
206 self.put(self.bits_pos[idx+length][1], self.bits_pos[idx+length][2], self.out_ann,
207 [5, ['Row parity failed', 'Parity failed', 'Fail']])
209 def print_col_parity(self, idx):
210 data_1 = self.get_8_bits(idx)
211 data_2 = self.get_8_bits(idx+9)
212 data_3 = self.get_8_bits(idx+9+9)
213 data_4 = self.get_8_bits(idx+9+9+9)
214 col_par = self.get_8_bits(idx+9+9+9+9)
215 col_par_calc = data_1^data_2^data_3^data_4
217 if col_par == col_par_calc:
218 self.put(self.bits_pos[idx+9+9+9+9][1], self.bits_pos[idx+9+9+9+9+7][2], self.out_ann,
219 [5, ['Column parity OK', 'Parity OK', 'OK']])
221 self.put(self.bits_pos[idx+9+9+9+9][1], self.bits_pos[idx+9+9+9+9+7][2], self.out_ann,
222 [5, ['Column parity failed', 'Parity failed', 'Fail']])
224 def print_8bit_data(self, idx):
225 data = self.get_8_bits(idx)
226 self.put(self.bits_pos[idx][1], self.bits_pos[idx+7][2], self.out_ann,
227 [9, ['Data' + ': %X' % data, '%X' % data]])
229 def put_fields(self):
230 if self.bit_nr == 50:
231 self.put(self.bits_pos[0][1], self.bits_pos[0][2], self.out_ann,
233 self.put(self.bits_pos[1][1], self.bits_pos[4][2], self.out_ann,
234 [4, ['Command', 'Cmd', 'C']])
235 self.put(self.bits_pos[5][1], self.bits_pos[49][2], self.out_ann,
236 [4, ['Password', 'Passwd', 'Pass', 'P']])
238 cmd = self.get_3_bits(1)
239 self.put(self.bits_pos[1][1], self.bits_pos[3][2], self.out_ann,
240 [5, [self.cmds[cmd]]])
241 self.print_row_parity(1, 3)
244 self.print_8bit_data(5)
245 self.print_row_parity(5, 8)
246 self.print_8bit_data(14)
247 self.print_row_parity(14, 8)
248 self.print_8bit_data(23)
249 self.print_row_parity(23, 8)
250 self.print_8bit_data(32)
251 self.print_row_parity(32, 8)
252 self.print_col_parity(5)
253 if self.bits_pos[49][0] == 0:
254 self.put(self.bits_pos[49][1], self.bits_pos[49][2], self.out_ann,
255 [5, ['Stop bit', 'Stop', 'SB']])
257 self.put(self.bits_pos[49][1], self.bits_pos[49][2], self.out_ann,
258 [5, ['Stop bit error', 'Error']])
261 password = self.get_32_bits(5)
262 self.put(self.bits_pos[12][1], self.bits_pos[46][2], self.out_ann,
263 [10, ['Login password: %X' % password]])
265 if self.bit_nr == 57:
266 self.put(self.bits_pos[0][1], self.bits_pos[0][2], self.out_ann,
267 [4, ['Logic zero', 'LZ']])
268 self.put(self.bits_pos[1][1], self.bits_pos[4][2], self.out_ann,
269 [4, ['Command', 'Cmd', 'C']])
270 self.put(self.bits_pos[5][1], self.bits_pos[11][2], self.out_ann,
271 [4, ['Address', 'Addr', 'A']])
272 self.put(self.bits_pos[12][1], self.bits_pos[56][2], self.out_ann,
273 [4, ['Data', 'Da', 'D']])
276 cmd = self.get_3_bits(1)
277 self.put(self.bits_pos[1][1], self.bits_pos[3][2], self.out_ann,
278 [5, [self.cmds[cmd]]])
279 self.print_row_parity(1, 3)
282 addr = self.get_4_bits(5)
283 self.put(self.bits_pos[5][1], self.bits_pos[8][2], self.out_ann,
284 [9, ['Addr' + ': %d' % addr, '%d' % addr]])
285 self.put(self.bits_pos[9][1], self.bits_pos[10][2], self.out_ann,
286 [5, ['Zero bits', 'ZB']])
287 self.print_row_parity(5, 6)
289 self.print_8bit_data(12)
290 self.print_row_parity(12, 8)
291 self.print_8bit_data(21)
292 self.print_row_parity(21, 8)
293 self.print_8bit_data(30)
294 self.print_row_parity(30, 8)
295 self.print_8bit_data(39)
296 self.print_row_parity(39, 8)
297 self.print_col_parity(12)
298 if self.bits_pos[56][0] == 0:
299 self.put(self.bits_pos[56][1], self.bits_pos[56][2], self.out_ann,
300 [5, ['Stop bit', 'Stop', 'SB']])
302 self.put(self.bits_pos[56][1], self.bits_pos[56][2], self.out_ann,
303 [5, ['Stop bit error', 'Error']])
306 self.decode_config(12)
309 password = self.get_32_bits(12)
310 self.put(self.bits_pos[12][1], self.bits_pos[46][2], self.out_ann,
311 [10, ['Write password: %X' % password]])
313 # If we are programming EM4100 data we can decode it halfway.
314 if addr == 5 and self.options['em4100_decode'] == 'on':
315 self.em4100_decode1(12)
316 if addr == 6 and self.options['em4100_decode'] == 'on':
317 self.em4100_decode2(12)
321 def add_bits_pos(self, bit, ss_bit, es_bit):
323 self.bits_pos[self.bit_nr][0] = bit
324 self.bits_pos[self.bit_nr][1] = ss_bit
325 self.bits_pos[self.bit_nr][2] = es_bit
328 def decode(self, ss, es, data):
329 if not self.samplerate:
330 raise SamplerateError('Cannot decode without samplerate.')
331 for (self.samplenum, (pin,)) in data:
332 # Ignore identical samples early on (for performance reasons).
333 if self.oldpin == pin:
336 if self.oldpin is None:
338 self.last_samplenum = self.samplenum
339 self.oldsamplenum = 0
341 self.gap_detected = 0
345 if self.oldpin != pin:
346 pl = self.samplenum - self.oldsamplenum
348 samples = self.samplenum - self.last_samplenum
350 if self.state == 'FFS_DETECTED':
351 if pl > self.writegap:
352 self.gap_detected = 1
353 if (self.last_samplenum - self.old_gap_end) > self.nogap:
354 self.gap_detected = 0
355 self.state = 'FFS_SEARCH'
356 self.put(self.old_gap_end, self.last_samplenum,
357 self.out_ann, [3, ['Write mode exit']])
360 if self.state == 'FFS_SEARCH':
362 self.gap_detected = 1
363 self.put(self.last_samplenum, self.samplenum,
364 self.out_ann, [1, ['First field stop', 'Field stop', 'FFS']])
365 self.state = 'FFS_DETECTED'
367 if self.gap_detected == 1:
368 self.gap_detected = 0
369 if (self.last_samplenum - self.old_gap_end) > self.wzmin \
370 and (self.last_samplenum - self.old_gap_end) < self.wzmax:
371 self.put(self.old_gap_end, self.samplenum,
372 self.out_ann, [0, ['0']])
373 self.add_bits_pos(0, self.old_gap_end, self.samplenum)
374 if (self.last_samplenum - self.old_gap_end) > self.womax \
375 and (self.last_samplenum-self.old_gap_end) < self.nogap:
377 one_bits = (int)((self.last_samplenum - self.old_gap_end) / self.womax)
378 for ox in range(0, one_bits):
379 bs = (int)(self.old_gap_end+ox*self.womax)
380 be = (int)(self.old_gap_end+ox*self.womax + self.womax)
381 self.put(bs, be, self.out_ann, [0, ['1']])
382 self.add_bits_pos(1, bs, be)
383 if (self.samplenum - self.last_samplenum) > self.wzmin \
384 and (self.samplenum - self.last_samplenum) < self.wzmax:
385 bs = (int)(self.old_gap_end+one_bits*self.womax)
386 self.put(bs, self.samplenum, self.out_ann, [0, ['0']])
387 self.add_bits_pos(0, bs, self.samplenum)
389 self.old_gap_end = self.samplenum
391 if self.state == 'SKIP':
392 self.state = 'FFS_SEARCH'
394 self.oldsamplenum = self.samplenum
395 self.last_samplenum = self.samplenum