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,)),
71 self.samplerate = None
72 self.last_samplenum = None
73 self.state = 'FFS_SEARCH'
74 self.bits_pos = [[0 for col in range(3)] for row in range(70)]
75 self.br_string = ['RF/8', 'RF/16', 'Unused', 'RF/32', 'RF/40',
76 'Unused', 'Unused', 'RF/64',]
77 self.encoder = ['not used', 'Manchester', 'Bi-phase', 'not used']
78 self.delayed_on = ['No delay', 'Delayed on - BP/8', 'Delayed on - BP/4', 'No delay']
79 self.em4100_decode1_partial = 0
80 self.cmds = ['Invalid', 'Login', 'Write word', 'Invalid', 'Read word', 'Disable', 'Protect', 'Invalid']
82 def metadata(self, key, value):
83 if key == srd.SRD_CONF_SAMPLERATE:
84 self.samplerate = value
85 self.field_clock = self.samplerate / self.options['coilfreq']
86 self.wzmax = self.options['w_zero_off_max'] * self.field_clock
87 self.wzmin = self.options['w_zero_on_min'] * self.field_clock
88 self.womax = self.options['w_one_max'] * self.field_clock
89 self.ffs = self.options['first_field_stop'] * self.field_clock
90 self.writegap = self.options['w_gap'] * self.field_clock
91 self.nogap = 300 * self.field_clock
94 self.out_ann = self.register(srd.OUTPUT_ANN)
96 def decode_config(self, idx):
97 bitrate = self.get_3_bits(idx+2)
98 self.put(self.bits_pos[idx][1], self.bits_pos[idx+5][2],
99 self.out_ann, [10, ['Data rate: ' + \
100 self.br_string[bitrate], self.br_string[bitrate]]])
101 encoding = self.bits_pos[idx+6][0]<<0 | self.bits_pos[idx+7][0]<<1
102 self.put(self.bits_pos[idx+6][1], self.bits_pos[idx+10][2],
103 self.out_ann, [10, ['Encoder: ' + \
104 self.encoder[encoding], self.encoder[encoding]]])
105 self.put(self.bits_pos[idx+11][1], self.bits_pos[idx+12][2], self.out_ann,
106 [10, ['Zero bits', 'ZB']])
107 delay_on = self.bits_pos[idx+13][0]<<0 | self.bits_pos[idx+14][0]<<1
108 self.put(self.bits_pos[idx+13][1], self.bits_pos[idx+14][2],
109 self.out_ann, [10, ['Delayed on: ' + \
110 self.delayed_on[delay_on], self.delayed_on[delay_on]]])
111 lwr = self.bits_pos[idx+15][0]<<3 | self.bits_pos[idx+16][0]<<2 | \
112 self.bits_pos[idx+18][0]<<1 | self.bits_pos[idx+19][0]<<0
113 self.put(self.bits_pos[idx+15][1], self.bits_pos[idx+19][2],
114 self.out_ann, [10, ['Last default read word: %d' % lwr, 'LWR: %d' % lwr, '%d' % lwr]])
115 self.put(self.bits_pos[idx+20][1], self.bits_pos[idx+20][2],
116 self.out_ann, [10, ['Read login: %d' % self.bits_pos[idx+20][0], '%d' % self.bits_pos[idx+20][0]]])
117 self.put(self.bits_pos[idx+21][1], self.bits_pos[idx+21][2], self.out_ann,
118 [10, ['Zero bits', 'ZB']])
119 self.put(self.bits_pos[idx+22][1], self.bits_pos[idx+22][2],
120 self.out_ann, [10, ['Write login: %d' % self.bits_pos[idx+22][0], '%d' % self.bits_pos[idx+22][0]]])
121 self.put(self.bits_pos[idx+23][1], self.bits_pos[idx+24][2], self.out_ann,
122 [10, ['Zero bits', 'ZB']])
123 self.put(self.bits_pos[idx+25][1], self.bits_pos[idx+25][2],
124 self.out_ann, [10, ['Disable: %d' % self.bits_pos[idx+25][0], '%d' % self.bits_pos[idx+25][0]]])
125 self.put(self.bits_pos[idx+27][1], self.bits_pos[idx+27][2],
126 self.out_ann, [10, ['Reader talk first: %d' % self.bits_pos[idx+27][0], 'RTF: %d' % self.bits_pos[idx+27][0]]])
127 self.put(self.bits_pos[idx+28][1], self.bits_pos[idx+28][2], self.out_ann,
128 [10, ['Zero bits', 'ZB']])
129 self.put(self.bits_pos[idx+29][1], self.bits_pos[idx+29][2],
130 self.out_ann, [10, ['Pigeon mode: %d' % self.bits_pos[idx+29][0], '%d' % self.bits_pos[idx+29][0]]])
131 self.put(self.bits_pos[idx+30][1], self.bits_pos[idx+34][2],
132 self.out_ann, [10, ['Reserved', 'Res', 'R']])
134 def put4bits(self, idx):
135 bits = self.bits_pos[idx][0]<<3 | self.bits_pos[idx+1][0]<<2 | \
136 self.bits_pos[idx+2][0]<<1 | self.bits_pos[idx+3][0]
137 self.put(self.bits_pos[idx][1], self.bits_pos[idx+3][2], self.out_ann,
140 def em4100_decode1(self, idx):
141 self.put(self.bits_pos[idx][1], self.bits_pos[idx+9][2], self.out_ann,
142 [10, ['EM4100 header', 'EM header', 'Header', 'H']])
143 self.put4bits(idx+10)
144 bits = self.bits_pos[idx+15][0]<<3 | self.bits_pos[idx+16][0]<<2 | \
145 self.bits_pos[idx+18][0]<<1 | self.bits_pos[idx+19][0]<<0
146 self.put(self.bits_pos[idx+15][1], self.bits_pos[idx+19][2], self.out_ann,
148 self.put4bits(idx+21)
149 self.put4bits(idx+27)
150 self.em4100_decode1_partial = self.bits_pos[idx+32][0]<<3 | \
151 self.bits_pos[idx+33][0]<<2 | self.bits_pos[idx+34][0]<<1
152 self.put(self.bits_pos[idx+32][1], self.bits_pos[idx+34][2],
153 self.out_ann, [10, ['Partial nibble']])
155 def em4100_decode2(self, idx):
156 if self.em4100_decode1_partial != 0:
157 bits = self.em4100_decode1_partial + self.bits_pos[idx][0]
158 self.put(self.bits_pos[idx][1], self.bits_pos[idx][2],
159 self.out_ann, [10, ['%X' % bits]])
160 self.em4100_decode1_partial = 0
162 self.put(self.bits_pos[idx][1], self.bits_pos[idx][2],
163 self.out_ann, [10, ['Partial nibble']])
166 bits = self.bits_pos[idx+7][0]<<3 | self.bits_pos[idx+9][0]<<2 | \
167 self.bits_pos[idx+10][0]<<1 | self.bits_pos[idx+11][0]<<0
168 self.put(self.bits_pos[idx+7][1], self.bits_pos[idx+11][2], self.out_ann,
170 self.put4bits(idx+13)
171 self.put4bits(idx+19)
172 bits = self.bits_pos[idx+24][0]<<3 | self.bits_pos[idx+25][0]<<2 | \
173 self.bits_pos[idx+27][0]<<1 | self.bits_pos[idx+28][0]<<0
174 self.put(self.bits_pos[idx+24][1], self.bits_pos[idx+28][2], self.out_ann,
176 self.put(self.bits_pos[idx+30][1], self.bits_pos[idx+34][2],
177 self.out_ann, [10, ['EM4100 trailer']])
179 def get_32_bits(self, idx):
180 return self.get_8_bits(idx+27)<<24 | self.get_8_bits(idx+18)<<16 | \
181 self.get_8_bits(idx+9)<<8 | self.get_8_bits(idx)
183 def get_8_bits(self, idx):
185 for i in range(0, 8):
187 retval |= self.bits_pos[i+idx][0]
190 def get_3_bits(self, idx):
191 return self.bits_pos[idx][0]<<2 | self.bits_pos[idx+1][0]<<1 | \
192 self.bits_pos[idx+2][0]
194 def get_4_bits(self, idx):
195 return self.bits_pos[idx][0]<<0 | self.bits_pos[idx+1][0]<<1 | \
196 self.bits_pos[idx+2][0]<<2 | self.bits_pos[idx+3][0]<<3
198 def print_row_parity(self, idx, length):
200 for i in range(0, length):
201 parity += self.bits_pos[i+idx][0]
202 parity = parity & 0x1
203 if parity == self.bits_pos[idx+length][0]:
204 self.put(self.bits_pos[idx+length][1], self.bits_pos[idx+length][2], self.out_ann,
205 [5, ['Row parity OK', 'Parity OK', 'OK']])
207 self.put(self.bits_pos[idx+length][1], self.bits_pos[idx+length][2], self.out_ann,
208 [5, ['Row parity failed', 'Parity failed', 'Fail']])
210 def print_col_parity(self, idx):
211 data_1 = self.get_8_bits(idx)
212 data_2 = self.get_8_bits(idx+9)
213 data_3 = self.get_8_bits(idx+9+9)
214 data_4 = self.get_8_bits(idx+9+9+9)
215 col_par = self.get_8_bits(idx+9+9+9+9)
216 col_par_calc = data_1^data_2^data_3^data_4
218 if col_par == col_par_calc:
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 OK', 'Parity OK', 'OK']])
222 self.put(self.bits_pos[idx+9+9+9+9][1], self.bits_pos[idx+9+9+9+9+7][2], self.out_ann,
223 [5, ['Column parity failed', 'Parity failed', 'Fail']])
225 def print_8bit_data(self, idx):
226 data = self.get_8_bits(idx)
227 self.put(self.bits_pos[idx][1], self.bits_pos[idx+7][2], self.out_ann,
228 [9, ['Data' + ': %X' % data, '%X' % data]])
230 def put_fields(self):
231 if self.bit_nr == 50:
232 self.put(self.bits_pos[0][1], self.bits_pos[0][2], self.out_ann,
234 self.put(self.bits_pos[1][1], self.bits_pos[4][2], self.out_ann,
235 [4, ['Command', 'Cmd', 'C']])
236 self.put(self.bits_pos[5][1], self.bits_pos[49][2], self.out_ann,
237 [4, ['Password', 'Passwd', 'Pass', 'P']])
239 cmd = self.get_3_bits(1)
240 self.put(self.bits_pos[1][1], self.bits_pos[3][2], self.out_ann,
241 [5, [self.cmds[cmd]]])
242 self.print_row_parity(1, 3)
245 self.print_8bit_data(5)
246 self.print_row_parity(5, 8)
247 self.print_8bit_data(14)
248 self.print_row_parity(14, 8)
249 self.print_8bit_data(23)
250 self.print_row_parity(23, 8)
251 self.print_8bit_data(32)
252 self.print_row_parity(32, 8)
253 self.print_col_parity(5)
254 if self.bits_pos[49][0] == 0:
255 self.put(self.bits_pos[49][1], self.bits_pos[49][2], self.out_ann,
256 [5, ['Stop bit', 'Stop', 'SB']])
258 self.put(self.bits_pos[49][1], self.bits_pos[49][2], self.out_ann,
259 [5, ['Stop bit error', 'Error']])
262 password = self.get_32_bits(5)
263 self.put(self.bits_pos[12][1], self.bits_pos[46][2], self.out_ann,
264 [10, ['Login password: %X' % password]])
266 if self.bit_nr == 57:
267 self.put(self.bits_pos[0][1], self.bits_pos[0][2], self.out_ann,
268 [4, ['Logic zero', 'LZ']])
269 self.put(self.bits_pos[1][1], self.bits_pos[4][2], self.out_ann,
270 [4, ['Command', 'Cmd', 'C']])
271 self.put(self.bits_pos[5][1], self.bits_pos[11][2], self.out_ann,
272 [4, ['Address', 'Addr', 'A']])
273 self.put(self.bits_pos[12][1], self.bits_pos[56][2], self.out_ann,
274 [4, ['Data', 'Da', 'D']])
277 cmd = self.get_3_bits(1)
278 self.put(self.bits_pos[1][1], self.bits_pos[3][2], self.out_ann,
279 [5, [self.cmds[cmd]]])
280 self.print_row_parity(1, 3)
283 addr = self.get_4_bits(5)
284 self.put(self.bits_pos[5][1], self.bits_pos[8][2], self.out_ann,
285 [9, ['Addr' + ': %d' % addr, '%d' % addr]])
286 self.put(self.bits_pos[9][1], self.bits_pos[10][2], self.out_ann,
287 [5, ['Zero bits', 'ZB']])
288 self.print_row_parity(5, 6)
290 self.print_8bit_data(12)
291 self.print_row_parity(12, 8)
292 self.print_8bit_data(21)
293 self.print_row_parity(21, 8)
294 self.print_8bit_data(30)
295 self.print_row_parity(30, 8)
296 self.print_8bit_data(39)
297 self.print_row_parity(39, 8)
298 self.print_col_parity(12)
299 if self.bits_pos[56][0] == 0:
300 self.put(self.bits_pos[56][1], self.bits_pos[56][2], self.out_ann,
301 [5, ['Stop bit', 'Stop', 'SB']])
303 self.put(self.bits_pos[56][1], self.bits_pos[56][2], self.out_ann,
304 [5, ['Stop bit error', 'Error']])
307 self.decode_config(12)
310 password = self.get_32_bits(12)
311 self.put(self.bits_pos[12][1], self.bits_pos[46][2], self.out_ann,
312 [10, ['Write password: %X' % password]])
314 # If we are programming EM4100 data we can decode it halfway.
315 if addr == 5 and self.options['em4100_decode'] == 'on':
316 self.em4100_decode1(12)
317 if addr == 6 and self.options['em4100_decode'] == 'on':
318 self.em4100_decode2(12)
322 def add_bits_pos(self, bit, ss_bit, es_bit):
324 self.bits_pos[self.bit_nr][0] = bit
325 self.bits_pos[self.bit_nr][1] = ss_bit
326 self.bits_pos[self.bit_nr][2] = es_bit
330 if not self.samplerate:
331 raise SamplerateError('Cannot decode without samplerate.')
333 # Initialize internal state.
334 self.last_samplenum = self.samplenum
335 self.oldsamplenum = 0
337 self.gap_detected = 0
341 # Ignore identical samples, only process edges.
342 (pin,) = self.wait({0: 'e'})
344 pl = self.samplenum - self.oldsamplenum
346 samples = self.samplenum - self.last_samplenum
348 if self.state == 'FFS_DETECTED':
349 if pl > self.writegap:
350 self.gap_detected = 1
351 if (self.last_samplenum - self.old_gap_end) > self.nogap:
352 self.gap_detected = 0
353 self.state = 'FFS_SEARCH'
354 self.put(self.old_gap_end, self.last_samplenum,
355 self.out_ann, [3, ['Write mode exit']])
358 if self.state == 'FFS_SEARCH':
360 self.gap_detected = 1
361 self.put(self.last_samplenum, self.samplenum,
362 self.out_ann, [1, ['First field stop', 'Field stop', 'FFS']])
363 self.state = 'FFS_DETECTED'
365 if self.gap_detected == 1:
366 self.gap_detected = 0
367 if (self.last_samplenum - self.old_gap_end) > self.wzmin \
368 and (self.last_samplenum - self.old_gap_end) < self.wzmax:
369 self.put(self.old_gap_end, self.samplenum,
370 self.out_ann, [0, ['0']])
371 self.add_bits_pos(0, self.old_gap_end, self.samplenum)
372 if (self.last_samplenum - self.old_gap_end) > self.womax \
373 and (self.last_samplenum-self.old_gap_end) < self.nogap:
375 one_bits = (int)((self.last_samplenum - self.old_gap_end) / self.womax)
376 for ox in range(0, one_bits):
377 bs = (int)(self.old_gap_end+ox*self.womax)
378 be = (int)(self.old_gap_end+ox*self.womax + self.womax)
379 self.put(bs, be, self.out_ann, [0, ['1']])
380 self.add_bits_pos(1, bs, be)
381 if (self.samplenum - self.last_samplenum) > self.wzmin \
382 and (self.samplenum - self.last_samplenum) < self.wzmax:
383 bs = (int)(self.old_gap_end+one_bits*self.womax)
384 self.put(bs, self.samplenum, self.out_ann, [0, ['0']])
385 self.add_bits_pos(0, bs, self.samplenum)
387 self.old_gap_end = self.samplenum
389 if self.state == 'SKIP':
390 self.state = 'FFS_SEARCH'
392 self.oldsamplenum = self.samplenum
393 self.last_samplenum = self.samplenum