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.'
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,)),
72 self.samplerate = None
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']
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
95 self.out_ann = self.register(srd.OUTPUT_ANN)
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']])
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,
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,
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']])
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
163 self.put(self.bits_pos[idx][1], self.bits_pos[idx][2],
164 self.out_ann, [10, ['Partial nibble']])
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,
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,
177 self.put(self.bits_pos[idx+30][1], self.bits_pos[idx+34][2],
178 self.out_ann, [10, ['EM4100 trailer']])
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)
184 def get_8_bits(self, idx):
186 for i in range(0, 8):
188 retval |= self.bits_pos[i+idx][0]
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]
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
199 def print_row_parity(self, idx, length):
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']])
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']])
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
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']])
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']])
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]])
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,
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']])
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)
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']])
259 self.put(self.bits_pos[49][1], self.bits_pos[49][2], self.out_ann,
260 [5, ['Stop bit error', 'Error']])
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]])
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']])
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)
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)
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']])
304 self.put(self.bits_pos[56][1], self.bits_pos[56][2], self.out_ann,
305 [5, ['Stop bit error', 'Error']])
308 self.decode_config(12)
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]])
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)
323 def add_bits_pos(self, bit, ss_bit, es_bit):
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
331 if not self.samplerate:
332 raise SamplerateError('Cannot decode without samplerate.')
334 # Initialize internal state.
335 self.last_samplenum = self.samplenum
336 self.oldsamplenum = 0
338 self.gap_detected = 0
342 # Ignore identical samples, only process edges.
343 (pin,) = self.wait({0: 'e'})
345 pl = self.samplenum - self.oldsamplenum
347 samples = self.samplenum - self.last_samplenum
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:
353 self.gap_detected = 0
354 self.state = 'FFS_SEARCH'
355 self.put(self.old_gap_end, self.last_samplenum,
356 self.out_ann, [3, ['Write mode exit']])
359 if self.state == 'FFS_SEARCH':
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'
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:
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)
388 self.old_gap_end = self.samplenum
390 if self.state == 'SKIP':
391 self.state = 'FFS_SEARCH'
393 self.oldsamplenum = self.samplenum
394 self.last_samplenum = self.samplenum