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, see <http://www.gnu.org/licenses/>.
20 import sigrokdecode as srd
22 class SamplerateError(Exception):
25 class Decoder(srd.Decoder):
29 longname = 'RFID EM4205/EM4305'
30 desc = 'EM4205/EM4305 100-150kHz RFID protocol.'
35 {'id': 'data', 'name': 'Data', 'desc': 'Data line'},
38 {'id': 'coilfreq', 'desc': 'Coil frequency', 'default': 125000},
39 {'id': 'first_field_stop', 'desc': 'First field stop min', 'default': 40},
40 {'id': 'w_gap', 'desc': 'Write gap min', 'default': 12},
41 {'id': 'w_one_max', 'desc': 'Write one max', 'default': 32},
42 {'id': 'w_zero_on_min', 'desc': 'Write zero on min', 'default': 15},
43 {'id': 'w_zero_off_max', 'desc': 'Write zero off max', 'default': 27},
44 {'id': 'em4100_decode', 'desc': 'EM4100 decode', 'default': 'on',
45 'values': ('on', 'off')},
48 ('bit_value', 'Bit value'),
49 ('first_field_stop', 'First field stop'),
50 ('write_gap', 'Write gap'),
51 ('write_mode_exit', 'Write mode exit'),
56 ('password', 'Password'),
57 ('address', 'Address'),
58 ('bitrate', 'Bitrate'),
61 ('bits', 'Bits', (0,)),
62 ('structure', 'Structure', (1, 2, 3, 4)),
63 ('fields', 'Fields', (5, 6, 7, 8, 9)),
64 ('decode', 'Decode', (10,)),
68 self.samplerate = None
69 self.last_samplenum = None
70 self.state = 'FFS_SEARCH'
71 self.bits_pos = [[0 for col in range(3)] for row in range(70)]
72 self.br_string = ['RF/8', 'RF/16', 'Unused', 'RF/32', 'RF/40',
73 'Unused', 'Unused', 'RF/64',]
74 self.encoder = ['not used', 'Manchester', 'Bi-phase', 'not used']
75 self.delayed_on = ['No delay', 'Delayed on - BP/8', 'Delayed on - BP/4', 'No delay']
76 self.em4100_decode1_partial = 0
77 self.cmds = ['Invalid', 'Login', 'Write word', 'Invalid', 'Read word', 'Disable', 'Protect', 'Invalid']
79 def metadata(self, key, value):
80 if key == srd.SRD_CONF_SAMPLERATE:
81 self.samplerate = value
82 self.field_clock = self.samplerate / self.options['coilfreq']
83 self.wzmax = self.options['w_zero_off_max'] * self.field_clock
84 self.wzmin = self.options['w_zero_on_min'] * self.field_clock
85 self.womax = self.options['w_one_max'] * self.field_clock
86 self.ffs = self.options['first_field_stop'] * self.field_clock
87 self.writegap = self.options['w_gap'] * self.field_clock
88 self.nogap = 300 * self.field_clock
91 self.out_ann = self.register(srd.OUTPUT_ANN)
93 def decode_config(self, idx):
94 bitrate = self.get_3_bits(idx+2)
95 self.put(self.bits_pos[idx][1], self.bits_pos[idx+5][2],
96 self.out_ann, [10, ['Data rate: ' + \
97 self.br_string[bitrate], self.br_string[bitrate]]])
98 encoding = self.bits_pos[idx+6][0]<<0 | self.bits_pos[idx+7][0]<<1
99 self.put(self.bits_pos[idx+6][1], self.bits_pos[idx+10][2],
100 self.out_ann, [10, ['Encoder: ' + \
101 self.encoder[encoding], self.encoder[encoding]]])
102 self.put(self.bits_pos[idx+11][1], self.bits_pos[idx+12][2], self.out_ann,
103 [10, ['Zero bits', 'ZB']])
104 delay_on = self.bits_pos[idx+13][0]<<0 | self.bits_pos[idx+14][0]<<1
105 self.put(self.bits_pos[idx+13][1], self.bits_pos[idx+14][2],
106 self.out_ann, [10, ['Delayed on: ' + \
107 self.delayed_on[delay_on], self.delayed_on[delay_on]]])
108 lwr = self.bits_pos[idx+15][0]<<3 | self.bits_pos[idx+16][0]<<2 | \
109 self.bits_pos[idx+18][0]<<1 | self.bits_pos[idx+19][0]<<0
110 self.put(self.bits_pos[idx+15][1], self.bits_pos[idx+19][2],
111 self.out_ann, [10, ['Last default read word: %d' % lwr, 'LWR: %d' % lwr, '%d' % lwr]])
112 self.put(self.bits_pos[idx+20][1], self.bits_pos[idx+20][2],
113 self.out_ann, [10, ['Read login: %d' % self.bits_pos[idx+20][0], '%d' % self.bits_pos[idx+20][0]]])
114 self.put(self.bits_pos[idx+21][1], self.bits_pos[idx+21][2], self.out_ann,
115 [10, ['Zero bits', 'ZB']])
116 self.put(self.bits_pos[idx+22][1], self.bits_pos[idx+22][2],
117 self.out_ann, [10, ['Write login: %d' % self.bits_pos[idx+22][0], '%d' % self.bits_pos[idx+22][0]]])
118 self.put(self.bits_pos[idx+23][1], self.bits_pos[idx+24][2], self.out_ann,
119 [10, ['Zero bits', 'ZB']])
120 self.put(self.bits_pos[idx+25][1], self.bits_pos[idx+25][2],
121 self.out_ann, [10, ['Disable: %d' % self.bits_pos[idx+25][0], '%d' % self.bits_pos[idx+25][0]]])
122 self.put(self.bits_pos[idx+27][1], self.bits_pos[idx+27][2],
123 self.out_ann, [10, ['Reader talk first: %d' % self.bits_pos[idx+27][0], 'RTF: %d' % self.bits_pos[idx+27][0]]])
124 self.put(self.bits_pos[idx+28][1], self.bits_pos[idx+28][2], self.out_ann,
125 [10, ['Zero bits', 'ZB']])
126 self.put(self.bits_pos[idx+29][1], self.bits_pos[idx+29][2],
127 self.out_ann, [10, ['Pigeon mode: %d' % self.bits_pos[idx+29][0], '%d' % self.bits_pos[idx+29][0]]])
128 self.put(self.bits_pos[idx+30][1], self.bits_pos[idx+34][2],
129 self.out_ann, [10, ['Reserved', 'Res', 'R']])
131 def put4bits(self, idx):
132 bits = self.bits_pos[idx][0]<<3 | self.bits_pos[idx+1][0]<<2 | \
133 self.bits_pos[idx+2][0]<<1 | self.bits_pos[idx+3][0]
134 self.put(self.bits_pos[idx][1], self.bits_pos[idx+3][2], self.out_ann,
137 def em4100_decode1(self, idx):
138 self.put(self.bits_pos[idx][1], self.bits_pos[idx+9][2], self.out_ann,
139 [10, ['EM4100 header', 'EM header', 'Header', 'H']])
140 self.put4bits(idx+10)
141 bits = self.bits_pos[idx+15][0]<<3 | self.bits_pos[idx+16][0]<<2 | \
142 self.bits_pos[idx+18][0]<<1 | self.bits_pos[idx+19][0]<<0
143 self.put(self.bits_pos[idx+15][1], self.bits_pos[idx+19][2], self.out_ann,
145 self.put4bits(idx+21)
146 self.put4bits(idx+27)
147 self.em4100_decode1_partial = self.bits_pos[idx+32][0]<<3 | \
148 self.bits_pos[idx+33][0]<<2 | self.bits_pos[idx+34][0]<<1
149 self.put(self.bits_pos[idx+32][1], self.bits_pos[idx+34][2],
150 self.out_ann, [10, ['Partial nibble']])
152 def em4100_decode2(self, idx):
153 if self.em4100_decode1_partial != 0:
154 bits = self.em4100_decode1_partial + self.bits_pos[idx][0]
155 self.put(self.bits_pos[idx][1], self.bits_pos[idx][2],
156 self.out_ann, [10, ['%X' % bits]])
157 self.em4100_decode1_partial = 0
159 self.put(self.bits_pos[idx][1], self.bits_pos[idx][2],
160 self.out_ann, [10, ['Partial nibble']])
163 bits = self.bits_pos[idx+7][0]<<3 | self.bits_pos[idx+9][0]<<2 | \
164 self.bits_pos[idx+10][0]<<1 | self.bits_pos[idx+11][0]<<0
165 self.put(self.bits_pos[idx+7][1], self.bits_pos[idx+11][2], self.out_ann,
167 self.put4bits(idx+13)
168 self.put4bits(idx+19)
169 bits = self.bits_pos[idx+24][0]<<3 | self.bits_pos[idx+25][0]<<2 | \
170 self.bits_pos[idx+27][0]<<1 | self.bits_pos[idx+28][0]<<0
171 self.put(self.bits_pos[idx+24][1], self.bits_pos[idx+28][2], self.out_ann,
173 self.put(self.bits_pos[idx+30][1], self.bits_pos[idx+34][2],
174 self.out_ann, [10, ['EM4100 trailer']])
176 def get_32_bits(self, idx):
177 return self.get_8_bits(idx+27)<<24 | self.get_8_bits(idx+18)<<16 | \
178 self.get_8_bits(idx+9)<<8 | self.get_8_bits(idx)
180 def get_8_bits(self, idx):
182 for i in range(0, 8):
184 retval |= self.bits_pos[i+idx][0]
187 def get_3_bits(self, idx):
188 return self.bits_pos[idx][0]<<2 | self.bits_pos[idx+1][0]<<1 | \
189 self.bits_pos[idx+2][0]
191 def get_4_bits(self, idx):
192 return self.bits_pos[idx][0]<<0 | self.bits_pos[idx+1][0]<<1 | \
193 self.bits_pos[idx+2][0]<<2 | self.bits_pos[idx+3][0]<<3
195 def print_row_parity(self, idx, length):
197 for i in range(0, length):
198 parity += self.bits_pos[i+idx][0]
199 parity = parity & 0x1
200 if parity == self.bits_pos[idx+length][0]:
201 self.put(self.bits_pos[idx+length][1], self.bits_pos[idx+length][2], self.out_ann,
202 [5, ['Row parity OK', 'Parity OK', 'OK']])
204 self.put(self.bits_pos[idx+length][1], self.bits_pos[idx+length][2], self.out_ann,
205 [5, ['Row parity failed', 'Parity failed', 'Fail']])
207 def print_col_parity(self, idx):
208 data_1 = self.get_8_bits(idx)
209 data_2 = self.get_8_bits(idx+9)
210 data_3 = self.get_8_bits(idx+9+9)
211 data_4 = self.get_8_bits(idx+9+9+9)
212 col_par = self.get_8_bits(idx+9+9+9+9)
213 col_par_calc = data_1^data_2^data_3^data_4
215 if col_par == col_par_calc:
216 self.put(self.bits_pos[idx+9+9+9+9][1], self.bits_pos[idx+9+9+9+9+7][2], self.out_ann,
217 [5, ['Column parity OK', 'Parity OK', 'OK']])
219 self.put(self.bits_pos[idx+9+9+9+9][1], self.bits_pos[idx+9+9+9+9+7][2], self.out_ann,
220 [5, ['Column parity failed', 'Parity failed', 'Fail']])
222 def print_8bit_data(self, idx):
223 data = self.get_8_bits(idx)
224 self.put(self.bits_pos[idx][1], self.bits_pos[idx+7][2], self.out_ann,
225 [9, ['Data' + ': %X' % data, '%X' % data]])
227 def put_fields(self):
228 if self.bit_nr == 50:
229 self.put(self.bits_pos[0][1], self.bits_pos[0][2], self.out_ann,
231 self.put(self.bits_pos[1][1], self.bits_pos[4][2], self.out_ann,
232 [4, ['Command', 'Cmd', 'C']])
233 self.put(self.bits_pos[5][1], self.bits_pos[49][2], self.out_ann,
234 [4, ['Password', 'Passwd', 'Pass', 'P']])
236 cmd = self.get_3_bits(1)
237 self.put(self.bits_pos[1][1], self.bits_pos[3][2], self.out_ann,
238 [5, [self.cmds[cmd]]])
239 self.print_row_parity(1, 3)
242 self.print_8bit_data(5)
243 self.print_row_parity(5, 8)
244 self.print_8bit_data(14)
245 self.print_row_parity(14, 8)
246 self.print_8bit_data(23)
247 self.print_row_parity(23, 8)
248 self.print_8bit_data(32)
249 self.print_row_parity(32, 8)
250 self.print_col_parity(5)
251 if self.bits_pos[49][0] == 0:
252 self.put(self.bits_pos[49][1], self.bits_pos[49][2], self.out_ann,
253 [5, ['Stop bit', 'Stop', 'SB']])
255 self.put(self.bits_pos[49][1], self.bits_pos[49][2], self.out_ann,
256 [5, ['Stop bit error', 'Error']])
259 password = self.get_32_bits(5)
260 self.put(self.bits_pos[12][1], self.bits_pos[46][2], self.out_ann,
261 [10, ['Login password: %X' % password]])
263 if self.bit_nr == 57:
264 self.put(self.bits_pos[0][1], self.bits_pos[0][2], self.out_ann,
265 [4, ['Logic zero', 'LZ']])
266 self.put(self.bits_pos[1][1], self.bits_pos[4][2], self.out_ann,
267 [4, ['Command', 'Cmd', 'C']])
268 self.put(self.bits_pos[5][1], self.bits_pos[11][2], self.out_ann,
269 [4, ['Address', 'Addr', 'A']])
270 self.put(self.bits_pos[12][1], self.bits_pos[56][2], self.out_ann,
271 [4, ['Data', 'Da', 'D']])
274 cmd = self.get_3_bits(1)
275 self.put(self.bits_pos[1][1], self.bits_pos[3][2], self.out_ann,
276 [5, [self.cmds[cmd]]])
277 self.print_row_parity(1, 3)
280 addr = self.get_4_bits(5)
281 self.put(self.bits_pos[5][1], self.bits_pos[8][2], self.out_ann,
282 [9, ['Addr' + ': %d' % addr, '%d' % addr]])
283 self.put(self.bits_pos[9][1], self.bits_pos[10][2], self.out_ann,
284 [5, ['Zero bits', 'ZB']])
285 self.print_row_parity(5, 6)
287 self.print_8bit_data(12)
288 self.print_row_parity(12, 8)
289 self.print_8bit_data(21)
290 self.print_row_parity(21, 8)
291 self.print_8bit_data(30)
292 self.print_row_parity(30, 8)
293 self.print_8bit_data(39)
294 self.print_row_parity(39, 8)
295 self.print_col_parity(12)
296 if self.bits_pos[56][0] == 0:
297 self.put(self.bits_pos[56][1], self.bits_pos[56][2], self.out_ann,
298 [5, ['Stop bit', 'Stop', 'SB']])
300 self.put(self.bits_pos[56][1], self.bits_pos[56][2], self.out_ann,
301 [5, ['Stop bit error', 'Error']])
304 self.decode_config(12)
307 password = self.get_32_bits(12)
308 self.put(self.bits_pos[12][1], self.bits_pos[46][2], self.out_ann,
309 [10, ['Write password: %X' % password]])
311 # If we are programming EM4100 data we can decode it halfway.
312 if addr == 5 and self.options['em4100_decode'] == 'on':
313 self.em4100_decode1(12)
314 if addr == 6 and self.options['em4100_decode'] == 'on':
315 self.em4100_decode2(12)
319 def add_bits_pos(self, bit, ss_bit, es_bit):
321 self.bits_pos[self.bit_nr][0] = bit
322 self.bits_pos[self.bit_nr][1] = ss_bit
323 self.bits_pos[self.bit_nr][2] = es_bit
327 if not self.samplerate:
328 raise SamplerateError('Cannot decode without samplerate.')
330 # Initialize internal state.
331 self.last_samplenum = self.samplenum
332 self.oldsamplenum = 0
334 self.gap_detected = 0
338 # Ignore identical samples, only process edges.
339 (pin,) = self.wait({0: 'e'})
341 pl = self.samplenum - self.oldsamplenum
343 samples = self.samplenum - self.last_samplenum
345 if self.state == 'FFS_DETECTED':
346 if pl > self.writegap:
347 self.gap_detected = 1
348 if (self.last_samplenum - self.old_gap_end) > self.nogap:
349 self.gap_detected = 0
350 self.state = 'FFS_SEARCH'
351 self.put(self.old_gap_end, self.last_samplenum,
352 self.out_ann, [3, ['Write mode exit']])
355 if self.state == 'FFS_SEARCH':
357 self.gap_detected = 1
358 self.put(self.last_samplenum, self.samplenum,
359 self.out_ann, [1, ['First field stop', 'Field stop', 'FFS']])
360 self.state = 'FFS_DETECTED'
362 if self.gap_detected == 1:
363 self.gap_detected = 0
364 if (self.last_samplenum - self.old_gap_end) > self.wzmin \
365 and (self.last_samplenum - self.old_gap_end) < self.wzmax:
366 self.put(self.old_gap_end, self.samplenum,
367 self.out_ann, [0, ['0']])
368 self.add_bits_pos(0, self.old_gap_end, self.samplenum)
369 if (self.last_samplenum - self.old_gap_end) > self.womax \
370 and (self.last_samplenum-self.old_gap_end) < self.nogap:
372 one_bits = (int)((self.last_samplenum - self.old_gap_end) / self.womax)
373 for ox in range(0, one_bits):
374 bs = (int)(self.old_gap_end+ox*self.womax)
375 be = (int)(self.old_gap_end+ox*self.womax + self.womax)
376 self.put(bs, be, self.out_ann, [0, ['1']])
377 self.add_bits_pos(1, bs, be)
378 if (self.samplenum - self.last_samplenum) > self.wzmin \
379 and (self.samplenum - self.last_samplenum) < self.wzmax:
380 bs = (int)(self.old_gap_end+one_bits*self.womax)
381 self.put(bs, self.samplenum, self.out_ann, [0, ['0']])
382 self.add_bits_pos(0, bs, self.samplenum)
384 self.old_gap_end = self.samplenum
386 if self.state == 'SKIP':
387 self.state = 'FFS_SEARCH'
389 self.oldsamplenum = self.samplenum
390 self.last_samplenum = self.samplenum