mfrc522 1.0.6 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/core_ext.rb +38 -0
- data/lib/exceptions.rb +1 -0
- data/lib/mfrc522.rb +37 -106
- data/lib/mifare/classic.rb +38 -19
- data/lib/mifare/des_fire.rb +156 -157
- data/lib/mifare/key.rb +39 -12
- data/lib/mifare/plus.rb +124 -0
- data/lib/mifare/plus_sl0.rb +11 -0
- data/lib/mifare/plus_sl1.rb +0 -0
- data/lib/mifare/plus_sl3.rb +11 -0
- data/lib/mifare/ultralight.rb +68 -17
- data/lib/mifare/ultralight_c.rb +13 -14
- data/lib/mifare/ultralight_ev1.rb +40 -0
- data/lib/picc.rb +313 -9
- metadata +7 -3
- data/lib/iso144434.rb +0 -247
@@ -0,0 +1,40 @@
|
|
1
|
+
module MIFARE
|
2
|
+
module UltralightEV1
|
3
|
+
def auth(passwd)
|
4
|
+
passwd_bytes = [passwd].pack('H*').bytes
|
5
|
+
if passwd_bytes.size != 4
|
6
|
+
raise UsageError, "Expect 4 bytes password in hex, got: #{passwd_bytes.size} byte"
|
7
|
+
end
|
8
|
+
|
9
|
+
transceive([CMD_PWD_AUTH, *passwd_bytes])
|
10
|
+
end
|
11
|
+
|
12
|
+
def authed?
|
13
|
+
@authed || false
|
14
|
+
end
|
15
|
+
|
16
|
+
def fast_read(from, to)
|
17
|
+
if (to - from + 1) > @max_range
|
18
|
+
raise UsageError, "Reading from #{from} to #{to} exceeds PCD receive buffer"
|
19
|
+
end
|
20
|
+
|
21
|
+
transceive([CMD_FAST_READ, from, to])
|
22
|
+
end
|
23
|
+
|
24
|
+
def read_counter(counter)
|
25
|
+
transceive([CMD_READ_CNT, counter])
|
26
|
+
end
|
27
|
+
|
28
|
+
def increment_counter(counter)
|
29
|
+
transceive([CMD_INCR_CNT, counter])
|
30
|
+
end
|
31
|
+
|
32
|
+
def counter_torn?(counter)
|
33
|
+
transceive([CMD_CHECK_TEARING_EVENT, counter]) != 0xBD
|
34
|
+
end
|
35
|
+
|
36
|
+
def read_signature
|
37
|
+
transceive([CMD_READ_SIG, 0x00])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/picc.rb
CHANGED
@@ -1,4 +1,11 @@
|
|
1
1
|
class PICC
|
2
|
+
FSCI_to_FSC = [16, 24, 32, 40, 48, 64, 96, 128, 256]
|
3
|
+
|
4
|
+
CMD_RATS = 0xE0
|
5
|
+
CMD_PPS = 0xD0
|
6
|
+
CMD_DESELECT = 0xC2
|
7
|
+
CMD_ADDITIONAL_FRAME = 0xAF
|
8
|
+
|
2
9
|
attr_reader :uid
|
3
10
|
attr_reader :sak
|
4
11
|
|
@@ -7,22 +14,319 @@ class PICC
|
|
7
14
|
@uid = uid
|
8
15
|
@sak = sak
|
9
16
|
@halted = false
|
17
|
+
|
18
|
+
## ISO mode
|
19
|
+
@cid = 0x00 # We don't support CID, fix it to 0
|
20
|
+
@fsc = 16 # Assume PICC only supports 16 bytes frame
|
21
|
+
@fwt = 256 # 77.33ms(256 ticks) default frame waiting time
|
22
|
+
@picc_support_cid = false # PICC support for CID
|
23
|
+
@picc_support_nad = false # PICC support for NAD
|
24
|
+
@historical_byte = []
|
25
|
+
@block_number = 0 # ISO frame block number
|
26
|
+
@iso_selected = false # If card is in iso mode
|
10
27
|
end
|
11
28
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
|
29
|
+
def picc_transceive(send_data, accept_timeout = false, need_bits = false)
|
30
|
+
received_data, valid_bits = @pcd.picc_transceive(send_data, accept_timeout)
|
31
|
+
if need_bits
|
32
|
+
return received_data, valid_bits
|
16
33
|
else
|
17
|
-
|
34
|
+
return received_data
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Wrapper for handling ISO protocol
|
39
|
+
def iso_transceive(send_data)
|
40
|
+
# Split data according to max buffer size
|
41
|
+
send_data = [send_data] unless send_data.is_a? Array
|
42
|
+
chained_data = send_data.each_slice(@max_inf_size).to_a
|
43
|
+
|
44
|
+
# Initialize I-block
|
45
|
+
pcb = 0x02
|
46
|
+
|
47
|
+
# Send chained data
|
48
|
+
until chained_data.empty?
|
49
|
+
pcb &= 0xEF # Reset chaining indicator
|
50
|
+
pcb |= 0x10 if chained_data.size > 1 # Set chaining
|
51
|
+
pcb |= @block_number # Set block number
|
52
|
+
data = chained_data.shift
|
53
|
+
|
54
|
+
buffer = [pcb] + data
|
55
|
+
|
56
|
+
finished = false
|
57
|
+
until finished
|
58
|
+
received_data = handle_wtx(buffer)
|
59
|
+
|
60
|
+
# Retreive response pcb from data
|
61
|
+
r_pcb = received_data[0]
|
62
|
+
|
63
|
+
# Received ACK
|
64
|
+
if r_pcb & 0xF6 == 0xA2
|
65
|
+
# If ACK matches current block number means success
|
66
|
+
# Otherwise transmit it again
|
67
|
+
if (pcb & 0x01) == (r_pcb & 0x01)
|
68
|
+
finished = true
|
69
|
+
end
|
70
|
+
else
|
71
|
+
finished = true
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
@block_number ^= 1 # toggle block number for next frame
|
76
|
+
end
|
77
|
+
|
78
|
+
received_chained_data = [received_data]
|
79
|
+
|
80
|
+
# Receive chained data
|
81
|
+
while r_pcb & 0x10 != 0
|
82
|
+
ack = 0xA2 | @block_number # Set block number
|
83
|
+
received_data = handle_wtx([ack]) # Send ACK to receive next frame
|
84
|
+
|
85
|
+
r_pcb = received_data[0]
|
86
|
+
|
87
|
+
received_chained_data << received_data
|
88
|
+
|
89
|
+
@block_number ^= 1 # toggle block number for next frame
|
90
|
+
end
|
91
|
+
|
92
|
+
# Collect INF from chain
|
93
|
+
inf = []
|
94
|
+
received_chained_data.each do |data|
|
95
|
+
inf_position = 1
|
96
|
+
inf_position += 1 if data[0] & 0x08 != 0 # CID present
|
97
|
+
inf_position += 1 if data[0] & 0x04 != 0 # NAD present
|
98
|
+
|
99
|
+
inf.concat(data[inf_position..-1])
|
100
|
+
end
|
101
|
+
inf
|
102
|
+
end
|
103
|
+
|
104
|
+
# ISO/IEC 14443-4 select
|
105
|
+
def iso_select
|
106
|
+
# Send RATS (Request for Answer To Select)
|
107
|
+
buffer = [CMD_RATS, 0x50 | @cid]
|
108
|
+
received_data = picc_transceive(buffer)
|
109
|
+
|
110
|
+
process_ats(received_data)
|
111
|
+
|
112
|
+
# Send PPS (Protocol and Parameter Selection Request)
|
113
|
+
buffer = [CMD_PPS | @cid, 0x11, (@dsi << 2) | @dri]
|
114
|
+
received_data = picc_transceive(buffer)
|
115
|
+
raise UnexpectedDataError, 'Incorrect response' if received_data[0] != (0xD0 | @cid)
|
116
|
+
|
117
|
+
# Set PCD baud rate
|
118
|
+
@pcd.transceiver_baud_rate(:tx, @dri)
|
119
|
+
@pcd.transceiver_baud_rate(:rx, @dsi)
|
120
|
+
|
121
|
+
@block_number = 0
|
122
|
+
@max_frame_size = [@pcd.buffer_size, @fsc].min
|
123
|
+
@max_inf_size = @max_frame_size - 3 # PCB + CRC16
|
124
|
+
@max_inf_size -= 1 if @picc_support_cid
|
125
|
+
@max_inf_size -= 1 if @picc_support_nad
|
126
|
+
@iso_selected = true
|
127
|
+
end
|
128
|
+
|
129
|
+
# Send S(DESELECT)
|
130
|
+
def iso_deselect
|
131
|
+
buffer = [CMD_DESELECT]
|
132
|
+
received_data = picc_transceive(buffer)
|
133
|
+
|
134
|
+
result = received_data[0] & 0xF7 == CMD_DESELECT
|
135
|
+
@iso_selected = !result
|
136
|
+
result
|
137
|
+
end
|
138
|
+
|
139
|
+
def restart_communication
|
140
|
+
picc_was_in_iso_mode = @iso_selected
|
141
|
+
iso_deselect if picc_was_in_iso_mode
|
142
|
+
unless @pcd.reestablish_picc_communication(@uid)
|
143
|
+
halt
|
144
|
+
raise CommunicationError, 'Unable to resume communication or wrong card was presented. Halting cards in the field.'
|
18
145
|
end
|
146
|
+
iso_select if picc_was_in_iso_mode
|
19
147
|
end
|
20
148
|
|
21
149
|
def halt
|
22
|
-
if @
|
23
|
-
|
24
|
-
|
25
|
-
|
150
|
+
iso_deselect if @iso_selected
|
151
|
+
@halted = @pcd.picc_halt
|
152
|
+
end
|
153
|
+
|
154
|
+
def self.identify_model(sak)
|
155
|
+
# SAK coding separation reference:
|
156
|
+
# https://www.nxp.com/docs/en/application-note/AN10833.pdf
|
157
|
+
# https://www.nxp.com/docs/en/application-note/AN10834.pdf
|
158
|
+
if sak & 0x04 != 0
|
159
|
+
return :picc_uid_not_complete
|
160
|
+
end
|
161
|
+
|
162
|
+
if sak & 0x02 != 0
|
163
|
+
return :picc_reserved_future_use
|
164
|
+
end
|
165
|
+
|
166
|
+
if sak & 0x08 != 0
|
167
|
+
if sak & 0x10 != 0
|
168
|
+
return :picc_mifare_4k
|
169
|
+
end
|
170
|
+
|
171
|
+
if sak & 0x01 != 0
|
172
|
+
return :picc_mifare_mini
|
173
|
+
end
|
174
|
+
|
175
|
+
return :picc_mifare_1k
|
176
|
+
end
|
177
|
+
|
178
|
+
if sak & 0x10 != 0
|
179
|
+
if sak & 0x01 != 0
|
180
|
+
return :picc_mifare_plus_4k_sl2
|
181
|
+
end
|
182
|
+
|
183
|
+
return :picc_mifare_plus_2k_sl2
|
26
184
|
end
|
185
|
+
|
186
|
+
if sak == 0x00
|
187
|
+
return :picc_mifare_ultralight
|
188
|
+
end
|
189
|
+
|
190
|
+
if sak & 0x20 != 0
|
191
|
+
return :picc_iso_14443_4
|
192
|
+
end
|
193
|
+
|
194
|
+
if sak & 0x40 != 0
|
195
|
+
return :picc_iso_18092
|
196
|
+
end
|
197
|
+
|
198
|
+
return :picc_unknown
|
199
|
+
end
|
200
|
+
|
201
|
+
protected
|
202
|
+
|
203
|
+
def crc32(*datas)
|
204
|
+
crc = 0xFFFFFFFF
|
205
|
+
|
206
|
+
datas.each do |data|
|
207
|
+
data = [data] unless data.is_a? Array
|
208
|
+
data.each do |byte|
|
209
|
+
crc ^= byte
|
210
|
+
8.times do
|
211
|
+
flag = crc & 0x01 > 0
|
212
|
+
crc >>= 1
|
213
|
+
crc ^= 0xEDB88320 if flag
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
crc
|
218
|
+
end
|
219
|
+
|
220
|
+
private
|
221
|
+
|
222
|
+
def choose_d(value)
|
223
|
+
# ISO DS/DR
|
224
|
+
# 0b000: 106kBd, 0b001: 212kBd, 0b010: 424kBd, 0b100: 848kBd
|
225
|
+
# MFRC522 register & ISO DSI/DRI
|
226
|
+
# 0b000: 106kBd, 0b001: 212kBd, 0b010: 424kBd, 0b011: 848kBd
|
227
|
+
# Find largest bit(fastest baud rate)
|
228
|
+
x = (value >> 2) & 0x01
|
229
|
+
y = (value >> 1) & 0x01
|
230
|
+
z = value & 0x01
|
231
|
+
|
232
|
+
((x | y) << 1) + (x | (~y & z))
|
233
|
+
end
|
234
|
+
|
235
|
+
# Gether information from ATS (Answer to Select)
|
236
|
+
def process_ats(ats)
|
237
|
+
position = 1
|
238
|
+
t0 = ats[position] # Format byte
|
239
|
+
|
240
|
+
fsci = t0 & 0x0F # PICC buffer size integer
|
241
|
+
y1 = (t0 >> 4) & 0x07 # Optional frame(TA, TB, TC) indicator
|
242
|
+
@fsc = FSCI_to_FSC.fetch(fsci) # Convert buffer size integer to bytes
|
243
|
+
|
244
|
+
# Frame: TA
|
245
|
+
if y1 & 0x01 != 0
|
246
|
+
position += 1
|
247
|
+
ta = ats[position]
|
248
|
+
|
249
|
+
dr = ta & 0x07 # PCD to PICC baud rate
|
250
|
+
ds = (ta >> 4) & 0x07 # PICC to PCD baud rate
|
251
|
+
same_d = (ta >> 7) & 0x01
|
252
|
+
|
253
|
+
if same_d != 0
|
254
|
+
dr &= ds
|
255
|
+
ds &= dr
|
256
|
+
end
|
257
|
+
|
258
|
+
@dri = choose_d(dr)
|
259
|
+
@dsi = choose_d(ds)
|
260
|
+
end
|
261
|
+
|
262
|
+
# Frame: TB
|
263
|
+
if y1 & 0x02 != 0
|
264
|
+
position += 1
|
265
|
+
tb = ats[position]
|
266
|
+
|
267
|
+
fwi = (tb >> 4) & 0x0F # Frame wating integer
|
268
|
+
sgfi = tb & 0x0F # Start-up frame guard integer
|
269
|
+
|
270
|
+
# Convert integers to real time
|
271
|
+
@fwt = (1 << fwi)
|
272
|
+
sgft = (1 << sgfi)
|
273
|
+
|
274
|
+
# Set frame waiting time
|
275
|
+
@pcd.internal_timer(@fwt)
|
276
|
+
end
|
277
|
+
|
278
|
+
# Get info about CID or NAD
|
279
|
+
if y1 & 0x04 != 0
|
280
|
+
position += 1
|
281
|
+
tc = ats[position]
|
282
|
+
|
283
|
+
@picc_support_cid = true if tc & 0x02 != 0
|
284
|
+
@picc_support_nad = true if tc & 0x01 != 0
|
285
|
+
end
|
286
|
+
|
287
|
+
position += 1
|
288
|
+
|
289
|
+
if ats.size - position > 0
|
290
|
+
@historical_byte = ats[position..-1]
|
291
|
+
end
|
292
|
+
|
293
|
+
# Start-up guard time
|
294
|
+
sleep 0.000302 * sgft
|
295
|
+
end
|
296
|
+
|
297
|
+
def handle_wtx(data)
|
298
|
+
24.times do
|
299
|
+
begin
|
300
|
+
received_data = picc_transceive(data)
|
301
|
+
rescue CommunicationError => e
|
302
|
+
raise e unless e.is_a? PICCTimeoutError
|
303
|
+
|
304
|
+
# Try sending NAK when timeout
|
305
|
+
nak = 0xB2 | @block_number
|
306
|
+
data = [nak]
|
307
|
+
next
|
308
|
+
end
|
309
|
+
|
310
|
+
pcb = received_data[0]
|
311
|
+
|
312
|
+
# WTX detected
|
313
|
+
if pcb & 0xF7 == 0xF2
|
314
|
+
inf_position = (pcb & 0x08 != 0) ? 2 : 1
|
315
|
+
wtxm = received_data[inf_position] & 0x3F
|
316
|
+
|
317
|
+
# Set temporary timer
|
318
|
+
@pcd.internal_timer(@fwt * wtxm)
|
319
|
+
|
320
|
+
# Set WTX response
|
321
|
+
data = [0xF2, wtxm]
|
322
|
+
else
|
323
|
+
# Set timer back to FWT
|
324
|
+
@pcd.internal_timer(@fwt)
|
325
|
+
|
326
|
+
return received_data
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
raise PICCTimeoutError, 'Timeout while handling WTX frame.'
|
27
331
|
end
|
28
332
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mfrc522
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- atitan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-03-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pi_piper
|
@@ -38,13 +38,17 @@ extra_rdoc_files: []
|
|
38
38
|
files:
|
39
39
|
- lib/core_ext.rb
|
40
40
|
- lib/exceptions.rb
|
41
|
-
- lib/iso144434.rb
|
42
41
|
- lib/mfrc522.rb
|
43
42
|
- lib/mifare/classic.rb
|
44
43
|
- lib/mifare/des_fire.rb
|
45
44
|
- lib/mifare/key.rb
|
45
|
+
- lib/mifare/plus.rb
|
46
|
+
- lib/mifare/plus_sl0.rb
|
47
|
+
- lib/mifare/plus_sl1.rb
|
48
|
+
- lib/mifare/plus_sl3.rb
|
46
49
|
- lib/mifare/ultralight.rb
|
47
50
|
- lib/mifare/ultralight_c.rb
|
51
|
+
- lib/mifare/ultralight_ev1.rb
|
48
52
|
- lib/picc.rb
|
49
53
|
homepage: https://github.com/atitan/MFRC522_Ruby
|
50
54
|
licenses:
|
data/lib/iso144434.rb
DELETED
@@ -1,247 +0,0 @@
|
|
1
|
-
class ISO144434 < PICC
|
2
|
-
FSCI_to_FSC = [16, 24, 32, 40, 48, 64, 96, 128, 256]
|
3
|
-
|
4
|
-
CMD_RATS = 0xE0
|
5
|
-
CMD_PPS = 0xD0
|
6
|
-
CMD_DESELECT = 0xC2
|
7
|
-
CMD_SUCCESS = 0x00
|
8
|
-
CMD_ADDITIONAL_FRAME = 0xAF
|
9
|
-
|
10
|
-
def initialize(pcd, uid, sak)
|
11
|
-
super
|
12
|
-
|
13
|
-
@cid = 0x00 # We don't support CID
|
14
|
-
@fsc = 16 # Assume PICC only supports 16 bytes frame
|
15
|
-
@fwt = 256 # 77.33ms(256 ticks) default frame waiting time
|
16
|
-
|
17
|
-
@support_cid = false
|
18
|
-
@support_nad = false
|
19
|
-
@block_number = 0
|
20
|
-
@selected = false
|
21
|
-
end
|
22
|
-
|
23
|
-
# ISO/IEC 14443-4 select
|
24
|
-
def select
|
25
|
-
# Send RATS (Request for Answer To Select)
|
26
|
-
buffer = [CMD_RATS, 0x50 | @cid]
|
27
|
-
received_data = @pcd.picc_transceive(buffer)
|
28
|
-
|
29
|
-
dr, ds = process_ats(received_data)
|
30
|
-
|
31
|
-
# Send PPS (Protocol and Parameter Selection Request)
|
32
|
-
buffer = [CMD_PPS | @cid, 0x11, (ds << 2) | dr]
|
33
|
-
received_data = @pcd.picc_transceive(buffer)
|
34
|
-
raise UnexpectedDataError, 'Incorrect response' if received_data[0] != (0xD0 | @cid)
|
35
|
-
|
36
|
-
# Set PCD baud rate
|
37
|
-
@pcd.transceiver_baud_rate(:tx, dr)
|
38
|
-
@pcd.transceiver_baud_rate(:rx, ds)
|
39
|
-
|
40
|
-
@block_number = 0
|
41
|
-
@max_frame_size = [64, @fsc].min
|
42
|
-
@max_inf_size = @max_frame_size - 3 # PCB + CRC16
|
43
|
-
@max_inf_size -= 1 if @support_cid
|
44
|
-
@max_inf_size -= 1 if @support_nad
|
45
|
-
@selected = true
|
46
|
-
end
|
47
|
-
|
48
|
-
# Send S(DESELECT)
|
49
|
-
def deselect
|
50
|
-
buffer = [CMD_DESELECT]
|
51
|
-
received_data = @pcd.picc_transceive(buffer)
|
52
|
-
|
53
|
-
if received_data[0] & 0xF7 == CMD_DESELECT
|
54
|
-
@selected = false
|
55
|
-
true
|
56
|
-
else
|
57
|
-
false
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
# Wrapper for handling ISO protocol
|
62
|
-
def transceive(send_data)
|
63
|
-
# Split data according to max buffer size
|
64
|
-
send_data = [send_data] unless send_data.is_a? Array
|
65
|
-
chained_data = send_data.each_slice(@max_inf_size).to_a
|
66
|
-
|
67
|
-
# Initialize I-block
|
68
|
-
pcb = 0x02
|
69
|
-
|
70
|
-
# Send chained data
|
71
|
-
until chained_data.empty?
|
72
|
-
pcb &= 0xEF # Reset chaining indicator
|
73
|
-
pcb |= 0x10 if chained_data.size > 1 # Set chaining
|
74
|
-
pcb |= @block_number # Set block number
|
75
|
-
data = chained_data.shift
|
76
|
-
|
77
|
-
buffer = [pcb] + data
|
78
|
-
|
79
|
-
finished = false
|
80
|
-
until finished
|
81
|
-
received_data = handle_wtx(buffer)
|
82
|
-
|
83
|
-
# Retreive response pcb from data
|
84
|
-
r_pcb = received_data[0]
|
85
|
-
|
86
|
-
# Received ACK
|
87
|
-
if r_pcb & 0xF6 == 0xA2
|
88
|
-
# If ACK matches current block number means success
|
89
|
-
# Otherwise transmit it again
|
90
|
-
if (pcb & 0x01) == (r_pcb & 0x01)
|
91
|
-
finished = true
|
92
|
-
end
|
93
|
-
else
|
94
|
-
finished = true
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
@block_number ^= 1 # toggle block number for next frame
|
99
|
-
end
|
100
|
-
|
101
|
-
received_chained_data = [received_data]
|
102
|
-
|
103
|
-
# Receive chained data
|
104
|
-
while r_pcb & 0x10 != 0
|
105
|
-
ack = 0xA2 | @block_number # Set block number
|
106
|
-
received_data = handle_wtx([ack]) # Send ACK to receive next frame
|
107
|
-
|
108
|
-
r_pcb = received_data[0]
|
109
|
-
|
110
|
-
received_chained_data << received_data
|
111
|
-
|
112
|
-
@block_number ^= 1 # toggle block number for next frame
|
113
|
-
end
|
114
|
-
|
115
|
-
# Collect INF from chain
|
116
|
-
inf = []
|
117
|
-
received_chained_data.each do |data|
|
118
|
-
inf_position = 1
|
119
|
-
inf_position += 1 if data[0] & 0x08 != 0 # CID present
|
120
|
-
inf_position += 1 if data[0] & 0x04 != 0 # NAD present
|
121
|
-
|
122
|
-
inf.concat(data[inf_position..-1])
|
123
|
-
end
|
124
|
-
|
125
|
-
inf
|
126
|
-
end
|
127
|
-
|
128
|
-
def resume_communication
|
129
|
-
deselect rescue nil
|
130
|
-
super
|
131
|
-
end
|
132
|
-
|
133
|
-
def halt
|
134
|
-
deselect rescue nil
|
135
|
-
super
|
136
|
-
end
|
137
|
-
|
138
|
-
private
|
139
|
-
|
140
|
-
def convert_iso_baud_rate_to_pcd_setting(value)
|
141
|
-
# ISO
|
142
|
-
# 0b000: 106kBd, 0b001: 212kBd, 0b010: 424kBd, 0b100: 848kBd
|
143
|
-
# MFRC522 register
|
144
|
-
# 0b000: 106kBd, 0b001: 212kBd, 0b010: 424kBd, 0b011: 848kBd
|
145
|
-
x = (value >> 2) & 0x01
|
146
|
-
y = (value >> 1) & 0x01
|
147
|
-
z = value & 0x01
|
148
|
-
|
149
|
-
((x | y) << 1) + (x | (~y & z))
|
150
|
-
end
|
151
|
-
|
152
|
-
# Gether information from ATS (Answer to Select)
|
153
|
-
def process_ats(ats)
|
154
|
-
position = 1
|
155
|
-
t0 = ats[position] # Format byte
|
156
|
-
|
157
|
-
fsci = t0 & 0x0F # PICC buffer size integer
|
158
|
-
y1 = (t0 >> 4) & 0x07 # Optional frame(TA, TB, TC) indicator
|
159
|
-
@fsc = FSCI_to_FSC.fetch(fsci) # Convert buffer size integer to bytes
|
160
|
-
dr = 0 # default baud rate 106kBd
|
161
|
-
ds = 0
|
162
|
-
|
163
|
-
# Frame: TA
|
164
|
-
if y1 & 0x01 != 0
|
165
|
-
position += 1
|
166
|
-
ta = ats[position]
|
167
|
-
|
168
|
-
dr = ta & 0x07 # PCD to PICC baud rate
|
169
|
-
ds = (ta >> 4) & 0x07 # PICC to PCD baud rate
|
170
|
-
|
171
|
-
# Convert fastest baud rate to PCD setting
|
172
|
-
# dr = convert_iso_baud_rate_to_pcd_setting(dr)
|
173
|
-
# ds = convert_iso_baud_rate_to_pcd_setting(ds)
|
174
|
-
|
175
|
-
# FIXME: baud rate fixed to 106kBd
|
176
|
-
# until author can confirm negotiation works
|
177
|
-
dr = 0
|
178
|
-
ds = 0
|
179
|
-
end
|
180
|
-
|
181
|
-
# Frame: TB
|
182
|
-
if y1 & 0x02 != 0
|
183
|
-
position += 1
|
184
|
-
tb = ats[position]
|
185
|
-
|
186
|
-
fwi = (tb >> 4) & 0x0F # Frame wating integer
|
187
|
-
sgfi = tb & 0x0F # Start-up frame guard integer
|
188
|
-
|
189
|
-
# Convert integers to real time
|
190
|
-
@fwt = (1 << fwi)
|
191
|
-
sgft = (1 << sgfi)
|
192
|
-
|
193
|
-
# Set frame waiting time
|
194
|
-
@pcd.internal_timer(@fwt)
|
195
|
-
end
|
196
|
-
|
197
|
-
# Get info about CID or NAD
|
198
|
-
if y1 & 0x04 != 0
|
199
|
-
position += 1
|
200
|
-
tc = ats[position]
|
201
|
-
|
202
|
-
@support_cid = true if tc & 0x02 != 0
|
203
|
-
@support_nad = true if tc & 0x01 != 0
|
204
|
-
end
|
205
|
-
|
206
|
-
# Start-up guard time
|
207
|
-
sleep 0.000302 * sgft
|
208
|
-
|
209
|
-
return dr, ds
|
210
|
-
end
|
211
|
-
|
212
|
-
def handle_wtx(data)
|
213
|
-
24.times do
|
214
|
-
begin
|
215
|
-
received_data = @pcd.picc_transceive(data)
|
216
|
-
rescue CommunicationError => e
|
217
|
-
raise e unless e.is_a? PICCTimeoutError
|
218
|
-
|
219
|
-
# Try sending NAK when timeout
|
220
|
-
nak = 0xB2 | @block_number
|
221
|
-
data = [nak]
|
222
|
-
next
|
223
|
-
end
|
224
|
-
|
225
|
-
pcb = received_data[0]
|
226
|
-
|
227
|
-
# WTX detected
|
228
|
-
if pcb & 0xF7 == 0xF2
|
229
|
-
inf_position = (pcb & 0x08 != 0) ? 2 : 1
|
230
|
-
wtxm = received_data[inf_position] & 0x3F
|
231
|
-
|
232
|
-
# Set temporary timer
|
233
|
-
@pcd.internal_timer(@fwt * wtxm)
|
234
|
-
|
235
|
-
# Set WTX response
|
236
|
-
data = [0xF2, wtxm]
|
237
|
-
else
|
238
|
-
# Set timer back to FWT
|
239
|
-
@pcd.internal_timer(@fwt)
|
240
|
-
|
241
|
-
return received_data
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
raise PICCTimeoutError
|
246
|
-
end
|
247
|
-
end
|