2 ## This file is part of the libsigrokdecode project.
4 ## Copyright (C) 2015 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 EM4100'
30 desc
= 'EM4100 100-150kHz RFID protocol.'
36 {'id': 'data', 'name': 'Data', 'desc': 'Data line'},
39 {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-high',
40 'values': ('active-low', 'active-high')},
41 {'id': 'datarate' , 'desc': 'Data rate', 'default': 64,
42 'values': (64, 32, 16)},
43 # {'id': 'coding', 'desc': 'Bit coding', 'default': 'biphase',
44 # 'values': ('biphase', 'manchester', 'psk')},
45 {'id': 'coilfreq', 'desc': 'Coil frequency', 'default': 125000},
50 ('version-customer', 'Version/customer'),
52 ('rowparity-ok', 'Row parity OK'),
53 ('rowparity-err', 'Row parity error'),
54 ('colparity-ok', 'Column parity OK'),
55 ('colparity-err', 'Column parity error'),
56 ('stopbit', 'Stop bit'),
60 ('bits', 'Bits', (0,)),
61 ('fields', 'Fields', (1, 2, 3, 4, 5, 6, 7, 8)),
62 ('tags', 'Tags', (9,)),
69 self
.samplerate
= None
71 self
.last_samplenum
= None
72 self
.lastlast_samplenum
= None
75 self
.halfbit_limit
= 0
88 self
.data_col_parity
= [0, 0, 0, 0, 0, 0]
89 self
.col_parity
= [0, 0, 0, 0, 0, 0]
91 self
.all_row_parity_ok
= True
92 self
.col_parity_pos
= []
94 def metadata(self
, key
, value
):
95 if key
== srd
.SRD_CONF_SAMPLERATE
:
96 self
.samplerate
= value
97 self
.bit_width
= (self
.samplerate
/ self
.options
['coilfreq']) * self
.options
['datarate']
98 self
.halfbit_limit
= self
.bit_width
/2 + self
.bit_width
/4
99 self
.polarity
= 0 if self
.options
['polarity'] == 'active-low' else 1
102 self
.out_ann
= self
.register(srd
.OUTPUT_ANN
)
104 def putbit(self
, bit
, ss
, es
):
105 self
.put(ss
, es
, self
.out_ann
, [0, [str(bit
)]])
106 if self
.state
== 'HEADER':
108 if self
.first_one
> 0:
110 if self
.first_one
== 9:
111 self
.put(self
.ss_first
, es
, self
.out_ann
,
112 [1, ['Header', 'Head', 'He', 'H']])
114 self
.state
= 'PAYLOAD'
116 if self
.first_one
== 0:
124 if self
.state
== 'PAYLOAD':
125 self
.payload_cnt
+= 1
126 if self
.data_bits
== 0:
131 if self
.data_bits
== 5:
132 s
= 'Version/customer' if self
.payload_cnt
<= 10 else 'Data'
133 c
= 2 if self
.payload_cnt
<= 10 else 3
134 self
.put(self
.ss_data
, ss
, self
.out_ann
,
135 [c
, [s
+ ': %X' % self
.data
, '%X' % self
.data
]])
136 s
= 'OK' if self
.data_parity
== bit
else 'ERROR'
137 c
= 4 if s
== 'OK' else 5
139 self
.all_row_parity_ok
= False
140 self
.put(ss
, es
, self
.out_ann
,
141 [c
, ['Row parity: ' + s
, 'RP: ' + s
, 'RP', 'R']])
142 self
.tag
= (self
.tag
<< 4) | self
.data
144 if self
.payload_cnt
== 50:
145 self
.state
= 'TRAILER'
148 self
.data_parity ^
= bit
149 self
.data_col_parity
[self
.data_bits
] ^
= bit
150 self
.data
= (self
.data
<< 1) | bit
153 if self
.state
== 'TRAILER':
154 self
.payload_cnt
+= 1
155 if self
.data_bits
== 0:
160 self
.col_parity
[self
.data_bits
] = bit
161 self
.col_parity_pos
.append([ss
, es
])
163 if self
.data_bits
== 5:
164 self
.put(ss
, es
, self
.out_ann
, [8, ['Stop bit', 'SB', 'S']])
166 for i
in range(1, 5):
167 s
= 'OK' if self
.data_col_parity
[i
] == \
168 self
.col_parity
[i
] else 'ERROR'
169 c
= 6 if s
== 'OK' else 7
170 self
.put(self
.col_parity_pos
[i
- 1][0],
171 self
.col_parity_pos
[i
- 1][1], self
.out_ann
,
172 [c
, ['Column parity %d: %s' % (i
, s
),
173 'CP%d: %s' % (i
, s
), 'CP%d' % i
, 'C']])
175 # Emit an annotation for valid-looking tags.
176 all_col_parity_ok
= (self
.data_col_parity
[1:5] == self
.col_parity
[1:5])
177 if all_col_parity_ok
and self
.all_row_parity_ok
:
178 self
.put(self
.ss_first
, es
, self
.out_ann
,
179 [9, ['Tag: %010X' % self
.tag
, 'Tag', 'T']])
184 if self
.payload_cnt
== 5:
185 self
.state
= 'HEADER'
187 self
.data_col_parity
= [0, 0, 0, 0, 0, 0]
188 self
.col_parity
= [0, 0, 0, 0, 0, 0]
189 self
.col_parity_pos
= []
190 self
.all_row_parity_ok
= True
192 def manchester_decode(self
, pl
, pp
, pin
):
193 bit
= self
.oldpin ^ self
.polarity
194 if pl
> self
.halfbit_limit
:
195 es
= int(self
.samplenum
- pl
/2)
196 if self
.oldpl
> self
.halfbit_limit
:
197 ss
= int(self
.oldsamplenum
- self
.oldpl
/2)
199 ss
= int(self
.oldsamplenum
- self
.oldpl
)
200 self
.putbit(bit
, ss
, es
)
201 self
.last_bit_pos
= int(self
.samplenum
- pl
/2)
203 es
= int(self
.samplenum
)
204 if self
.oldpl
> self
.halfbit_limit
:
205 ss
= int(self
.oldsamplenum
- self
.oldpl
/2)
206 self
.putbit(bit
, ss
, es
)
207 self
.last_bit_pos
= int(self
.samplenum
)
209 if self
.last_bit_pos
<= self
.oldsamplenum
- self
.oldpl
:
210 ss
= int(self
.oldsamplenum
- self
.oldpl
)
211 self
.putbit(bit
, ss
, es
)
212 self
.last_bit_pos
= int(self
.samplenum
)
215 if not self
.samplerate
:
216 raise SamplerateError('Cannot decode without samplerate.')
218 # Initialize internal state from the very first sample.
221 self
.last_samplenum
= self
.samplenum
222 self
.lastlast_samplenum
= self
.samplenum
223 self
.last_edge
= self
.samplenum
226 self
.oldsamplenum
= 0
227 self
.last_bit_pos
= 0
230 # Ignore identical samples, only process edges.
231 (pin
,) = self
.wait({0: 'e'})
232 pl
= self
.samplenum
- self
.oldsamplenum
234 self
.manchester_decode(pl
, pp
, pin
)
237 self
.oldsamplenum
= self
.samplenum