ruby-nfc 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YmQ5NDY5MzE2MTUwMDJlMjEwYjNkMjU0ZDkxZTU1YmRjYTAyODUyOA==
4
+ NWMzYmQwMDJkYzBlMmMzZjM0NmRhNTdmYWJhNjk0Y2E2MDM5ZGYwOQ==
5
5
  data.tar.gz: !binary |-
6
- M2U3Mjc5ZTY3YWI0MTg3ZTYwZTZmYzExOThhYjNkM2Y5NzVhMWQzZQ==
6
+ Mjk2ZmVmNGIxMDQwY2I0ZDFjNDJmZTYxZWJjNTM1NjlkOTkwMDYzMA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- NzMwMTFlZWVlZmUwNDIzOWEzYWQ5NzIwMDY5N2UzNTViNTYwYTQwYzI1OTQ1
10
- ZmFkNzE4NjAzZDk4M2UxMzFjMTFlODliZmVkNjdhN2Y2NDk2ZWJhOWY4ZGE4
11
- NDhlYTI2NjY2NGE1NzVhZDRmMTg4NTk2ZDNkMzQwY2UxOWYzZjE=
9
+ NGJkOTIxOWY1YTNjY2JlN2FhMTQ2NDNmNDkzNWQzYTI2OTdlNGRkOTk3MDVj
10
+ YTdmNjA0N2UzNzgxNjYyMDc5NjY4NzI2MWIzNTRiMjg3YzUyY2ZmOGU2MTVl
11
+ YmI3NzM0NTc5MDFhYWIxZmY2OGU1NTYwZGY0OTAzNTE0NTI0MDI=
12
12
  data.tar.gz: !binary |-
13
- ZWNjMzUxZGQ2OGEyNDc5OGNlNzgwNzBhMTI5MWQ3MmU1NWRmZTc4ZjA2NWRl
14
- M2YzMTc0NGZkMTM1ZDliNDVlNmRlZmU4NjA5NzY1ZmZkYTEzMjRjYmY4NGIy
15
- ZWY5ZTc4NjJjYTZlN2QyYzJjMGRmODM2MWFlZDJmNjFhZmMyY2Q=
13
+ ODVmMTQzYzI2NGQ1Mjg0N2NiMGE5ZDgwOTE4ZmMxZjRjNDI2MjZkNjI1ZWEx
14
+ NWYyYWE0NTU2MWEyNzczYmRjM2I2Mjc3MDM4NzFiMmY0NDRjOWUwYTJmMWI1
15
+ ZjBiN2JhMTQ2OWFmNGM2OGE1MTMwODM1MGY2NjMzNzM1ZDlmZTY=
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Maxim M. Chechel <maximchick@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,92 @@
1
+ module APDU
2
+ class Error < ::Exception; end
3
+
4
+ class Errno < ::Exception
5
+ STATUS_STRINGS = {
6
+ #0x6XXX => "Transmission protocol related codes
7
+ #0x61XX => "SW2 indicates the number of response bytes still available",
8
+
9
+ 0x6200 => "No information given",
10
+ 0x6281 => "Returned data may be corrupted",
11
+ 0x6282 => "The end of the file has been reached before the end of reading",
12
+ 0x6283 => "Invalid DF",
13
+ 0x6284 => "Selected file is not valid. File descriptor error",
14
+
15
+ 0x6300 => "Authentification failed. Invalid secret code or forbidden value",
16
+ 0x6381 => "File filled up by the last write",
17
+ # 0x63CX => "Counter provided by 'X' (valued from 0 to 15) (exact meaning depending on the command)",
18
+
19
+ 0x6501 => "Memory failure. There have been problems in writing or reading the EEPROM\n" +
20
+ "Other hardware problems may also bring this error.",
21
+ 0x6581 => "Write problem / Memory failure / Unknown mode",
22
+
23
+ # 0x67XX => "Error, incorrect parameter P3 (ISO code)",
24
+ 0x6700 => "Incorrect length or address range error",
25
+
26
+ 0x6800 => "The request function is not supported by the card.",
27
+ 0x6881 => "Logical channel not supported",
28
+ 0x6882 => "Secure messaging not supported",
29
+
30
+ 0x6900 => "No successful transaction executed during session",
31
+ 0x6981 => "Cannot select indicated file, command not compatible with file organization",
32
+ 0x6982 => "Access conditions not fulfilled",
33
+ 0x6983 => "Secret code locked",
34
+ 0x6984 => "Referenced data invalidated",
35
+ 0x6985 => "No currently selected EF, no command to monitor / no Transaction Manager File",
36
+ 0x6986 => "Command not allowed (no current EF)",
37
+ 0x6987 => "Expected SM data objects missing",
38
+ 0x6988 => "SM data objects incorrect",
39
+
40
+ 0x6A00 => "Bytes P1 and/or P2 are incorrect.",
41
+ 0x6A80 => "The parameters in the data field are incorrect",
42
+ 0x6A81 => "Card is blocked or command not supported",
43
+ 0x6A82 => "File not found",
44
+ 0x6A83 => "Record not found",
45
+ 0x6A84 => "There is insufficient memory space in record or file",
46
+ 0x6A85 => "Lc inconsistent with TLV structure",
47
+ 0x6A86 => "Incorrect parameters P1P2",
48
+ 0x6A87 => "The P3 value is not consistent with the P1 and P2 values.",
49
+ 0x6A88 => "Referenced data not found.",
50
+
51
+ 0x6B00 => "Incorrect reference; illegal address; Invalid P1 or P2 parameter",
52
+
53
+ # 0x6CXX => "Incorrect P3 length.",
54
+
55
+ 0x6D00 => "Command not allowed. Invalid instruction byte (INS)",
56
+
57
+ 0x6E00 => "Incorrect application (CLA parameter of a command)",
58
+
59
+ 0x6F00 => "Checking error",
60
+
61
+ 0x9000 => "Command executed without error",
62
+
63
+ 0x9100 => "Purse Balance error cannot perform transaction",
64
+ 0x9102 => "Purse Balance error",
65
+
66
+ # 0x92XX => "Memory error",
67
+ 0x9202 => "Write problem / Memory failure",
68
+ 0x9240 => "Error, memory problem",
69
+
70
+ # 0x94XX => "File error",
71
+ 0x9404 => "Purse selection error or invalid purse",
72
+ 0x9406 => "Invalid purse detected during the replacement debit step",
73
+ 0x9408 => "Key file selection error",
74
+
75
+ # 0x98XX => "Security error",
76
+ 0x9800 => "Warning",
77
+ 0x9804 => "Access authorization not fulfilled",
78
+ 0x9806 => "Access authorization in Debit not fulfilled for the replacement debit step",
79
+ 0x9820 => "No temporary transaction key established",
80
+ 0x9834 => "Error, Update SSD order sequence not respected"
81
+ }
82
+
83
+ attr_accessor :code
84
+
85
+ def initialize(sw)
86
+ @code = sw
87
+ message = STATUS_STRINGS[sw] || "Unknown error"
88
+
89
+ super("#{sw.to_s(16).upcase} #{message}")
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,42 @@
1
+ require_relative './apdu'
2
+
3
+ module APDU
4
+ class Request
5
+ attr_accessor :cla, :ins, :p1, :p2, :lc, :data, :le
6
+
7
+ def self.from_string(apdu)
8
+ raise APDU::Error, "APDU is too short: #{apdu.size}" if apdu.size < 5
9
+
10
+ apdu_8bit = apdu.dup
11
+ apdu_8bit.force_encoding('ASCII-8BIT')
12
+
13
+ req = self.new
14
+ req.cla, req.ins, req.p1, req.p2, req.lc, req.data = apdu.unpack('CCCCCA*')
15
+
16
+ if req.data.size == req.lc
17
+ req.le = 0
18
+ elsif req.data.size == req.lc + 1
19
+ req.le = req.data[-1,1].ord
20
+ req.data = req.data[0...-1]
21
+ else
22
+ raise APDU::Error, "Wrong Lc or wrong command data length"
23
+ end
24
+
25
+ req
26
+ end
27
+
28
+ def self.from_hex_string(apdu)
29
+ raise APDU::Error, "Wrong format" if apdu !~ /^([a-fA-F0-9]{2}){5,128}$/
30
+ from_string([apdu].pack('H*'))
31
+ end
32
+
33
+ # Public: Build APDU command
34
+ def build
35
+ [self.to_s].pack('H*')
36
+ end
37
+
38
+ def to_s
39
+ [cla, ins, p1, p2, lc, data, le].pack('CCCCCA*C').unpack('H*').pop.upcase
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,48 @@
1
+ require_relative './apdu'
2
+
3
+ module APDU
4
+ class Response
5
+ def initialize(response)
6
+ resp_8bit = response.dup
7
+ resp_8bit.force_encoding('ASCII-8BIT')
8
+
9
+ raise APDU::Error, "Response must be at least 2-bytes long" if resp_8bit.size < 2
10
+
11
+ @response = resp_8bit
12
+ end
13
+
14
+ # Public: Raises APDU::Errno if self.sw is not equal 0x9000
15
+ def raise_errno!
16
+ raise APDU::Errno.new(sw) if sw != 0x9000
17
+ self
18
+ end
19
+
20
+ # Public: Return Status Word of an APDU response. Status Word is a two-byte
21
+ # result code
22
+ def sw
23
+ @response[-2, 2].unpack('n').pop
24
+ end
25
+
26
+ # Public: Return high byte of Status Word
27
+ def sw1
28
+ @response[-2, 1].unpack('C').pop
29
+ end
30
+
31
+ # Public: Return low byte of Status Word
32
+ def sw2
33
+ @response[-1,1].unpack('C').pop
34
+ end
35
+
36
+ def data
37
+ @response[0...-2]
38
+ end
39
+
40
+ def to_s
41
+ @response.unpack('H*').pop.upcase
42
+ end
43
+
44
+ def [](index)
45
+ @response[index]
46
+ end
47
+ end
48
+ end
@@ -26,7 +26,7 @@ module NFC
26
26
  end
27
27
  end
28
28
 
29
- def poll(*card_types)
29
+ def poll(*card_types, &block)
30
30
  connect
31
31
 
32
32
  LibNFC.nfc_initiator_init(@ptr) # we'll be initiator not a target
@@ -57,7 +57,7 @@ module NFC
57
57
  card_types.each do |card_type|
58
58
  if card_type.match?(target)
59
59
  tag = card_type.new(target, self)
60
- yield tag
60
+ tag.connect(&block)
61
61
  # if this tag was marked as processed - continue with next tag
62
62
  break if target.processed?
63
63
  end
@@ -1,5 +1,7 @@
1
1
  require_relative '../nfc'
2
2
  require_relative './tag'
3
+ require_relative '../apdu/request'
4
+ require_relative '../apdu/response'
3
5
 
4
6
  module IsoDep
5
7
  ISO_14443_4_COMPATIBLE = 0x20
@@ -12,7 +14,7 @@ module IsoDep
12
14
  target[:nti][:nai][:btSak] & IsoDep::ISO_14443_4_COMPATIBLE > 0
13
15
  end
14
16
 
15
- def select(aid = nil, &block)
17
+ def connect(&block)
16
18
  @reader.set_flag(:NP_AUTO_ISO14443_4, true)
17
19
 
18
20
  modulation = LibNFC::Modulation.new
@@ -33,22 +35,54 @@ module IsoDep
33
35
  )
34
36
 
35
37
  if res > 0
36
- # trying to select applet if applet identifier was given
37
- if aid
38
- sw = send_apdu("\x00\xA4\x04\x00#{aid.size.chr}#{aid}")
39
- raise IsoDep::Error, "Application not found: #{aid.unpack('H*').pop}" unless "\x90\x00" == sw
40
- end
41
-
42
38
  super(&block)
43
39
  else
44
40
  raise IsoDep::Error, "Can't select tag: #{res}"
45
41
  end
46
42
  end
47
43
 
48
- def deselect
44
+ def disconnect
49
45
  0 == LibNFC.nfc_initiator_deselect_target(@reader.ptr)
50
46
  end
51
47
 
48
+ # Public: select application with give AID
49
+ #
50
+ # aid - Identifier of the application that should be selected
51
+ #
52
+ # Returns APDU::Response
53
+ def select(aid)
54
+ send_apdu("\x00\xA4\x04\x00#{aid.size.chr}#{aid}")
55
+ end
56
+
57
+ # Public: same as select but raises an APDU::Errno exception if
58
+ # application not present on the card or SW is not equal to 0x9000
59
+ #
60
+ # aid - Identifier of the application that should be selected
61
+ #
62
+ # Returns APDU::Response
63
+ # Raises APDU::Errno
64
+ def select!(aid)
65
+ select(aid).raise_errno!
66
+ end
67
+
68
+ # Public: Select application with given AID (Application Identifier)
69
+ #
70
+ # aid - Application Identifier of an applet located on a card
71
+ #
72
+ # Returns nothing.
73
+ # Raises APDU::Errno if application with such AID doesn't exists on a card
74
+ def select(aid)
75
+ send_apdu!("\x00\xA4\x04\x00#{aid.size.chr}#{aid}")
76
+ end
77
+
78
+ # Public: Send APDU command to tag
79
+ #
80
+ # apdu - APDU command to send. see ISO/IEC 7816-4 or wiki for details.
81
+ # APDU is a binary string that should
82
+ #
83
+ #
84
+ # Returns APDU::Response object
85
+ # Raises IsoDep::Error if card didn't respond
52
86
  def send_apdu(apdu)
53
87
  cmd = apdu
54
88
  cmd.force_encoding('ASCII-8BIT')
@@ -62,7 +96,18 @@ module IsoDep
62
96
 
63
97
  raise IsoDep::Error, "APDU sending failed: #{res_len}" if res_len < 0
64
98
 
65
- response_buffer.get_bytes(0, res_len).to_s
99
+ APDU::Response.new(response_buffer.get_bytes(0, res_len).to_s)
100
+ end
101
+
102
+ # Public: Send APDU command to tag and raises APDU::Errno exception
103
+ # if SW not equal to 0x9000
104
+ #
105
+ # apdu - APDU command to transmit to the tag
106
+ #
107
+ # Returns APDU::Response object
108
+ # Raises APDU::Errno if SW is not equal to 0x9000
109
+ def send_apdu!(apdu)
110
+ send_apdu(apdu).raise_errno!
66
111
  end
67
112
 
68
113
  alias :'<<' :send_apdu
@@ -40,18 +40,18 @@ module Mifare
40
40
  @auth_block = nil #last authenticated block
41
41
  end
42
42
 
43
- def select(&block)
43
+ def connect(&block)
44
44
  @reader.set_flag(:NP_AUTO_ISO14443_4, false)
45
45
 
46
46
  res = Mifare.mifare_classic_connect(@pointer)
47
47
  if 0 == res
48
48
  super
49
49
  else
50
- raise Mifare::Error, "Can't select tag: #{res}"
50
+ raise Mifare::Error, "Can't connect to tag: #{res}"
51
51
  end
52
52
  end
53
53
 
54
- def deselect
54
+ def disconnect
55
55
  Mifare.mifare_classic_disconnect(@pointer)
56
56
  super
57
57
  end
@@ -59,58 +59,62 @@ module Mifare
59
59
  # keytype can be :key_a or :key_b
60
60
  # key - hexadecimal string key representation like "FFFFFFFFFFFF"
61
61
  def auth(block_num, key_type, key)
62
- raise Mifare::Error.new('Wrong key type') unless [:key_a, :key_b].include? key_type
63
- raise Mifare::Error.new('Wrong key length') unless [6, 12].include? key.size
62
+ raise Mifare::Error, "Wrong key type" unless [:key_a, :key_b].include? key_type
63
+ raise Mifare::Error, "Wrong key length" unless [6, 12].include? key.size
64
64
 
65
65
  key_ptr = FFI::MemoryPointer.new(:uchar, 6)
66
- key_ptr.put_bytes(0, 6 == key.size ? key : [key].pack('H*'))
66
+ key_ptr.put_bytes(0, 6 == key.size ? key : [key].pack("H*"))
67
67
 
68
68
  res = Mifare.mifare_classic_authenticate(@pointer, block_num, key_ptr,
69
69
  key_type)
70
- if 0 == res
71
- @auth_block = block_num
72
- else
73
- raise Mifare::Error.new("Can't autenticate to block 0x%02x" % block_num)
74
- end
70
+ raise Mifare::Error, "Can't autenticate to block 0x%02x" % block_num if 0 != res
71
+
72
+ @auth_block = block_num
75
73
  end
76
74
 
77
75
  # block number to read
78
76
  def read(block_num = nil)
79
77
  block_num ||= @auth_block
80
- raise Mifare::Error.new('Not authenticated') unless block_num
78
+ raise Mifare::Error, "Not authenticated" unless block_num
81
79
 
82
80
  data_ptr = FFI::MemoryPointer.new(:uchar, 16)
83
81
  res = Mifare.mifare_classic_read(@pointer, block_num, data_ptr)
84
82
 
85
- raise Mifare::Error.new("Can't read block 0x%02x" % block_num) unless 0 == res
83
+ raise Mifare::Error, "Can't read block 0x%02x" % block_num if 0 != res
86
84
 
87
- data_ptr.get_bytes(0, 16).force_encoding('ASCII-8BIT')
85
+ data_ptr.get_bytes(0, 16).force_encoding("ASCII-8BIT")
88
86
  end
89
87
 
90
88
  # @data - 16 bytes represented by hexadecimal string
91
89
  # @block_num - number of block to write to
92
90
  def write(data, block_num = nil)
93
- raise Mifare::Error.new('Wrong data given') if data !~ /^[\da-f]{32}$/i
94
-
95
91
  block_num ||= @auth_block
96
- raise Mifare::Error.new('Not authenticated') unless block_num
92
+ raise Mifare::Error, "Not authenticated" unless block_num
93
+
94
+ write_data = if data =~ /^[\da-f]{32}$/i
95
+ [data].pack("H*")
96
+ elsif 16 == data.size
97
+ data.dup
98
+ else
99
+ raise Mifare::Error, "Wrong data given"
100
+ end
97
101
 
98
102
  data_ptr = FFI::MemoryPointer.new(:uchar, 16)
99
- data_ptr.put_bytes(0, [data].pack('H*'))
103
+ data_ptr.put_bytes(0, write_data)
100
104
 
101
105
  res = Mifare.mifare_classic_write(@pointer, block_num, data_ptr)
102
- (0 == res) || raise(Mifare::Error.new("Can't write block 0x%02x" % block_num))
106
+ raise Mifare::Error, "Can't write block 0x%02x" % block_num if 0 != res
103
107
  end
104
108
 
105
109
  # Create value block structure and write it to block
106
110
  def init_value(value, addr = nil, block_num = nil)
107
111
  block_num ||= @auth_block
108
- raise Mifare::Error.new('Not authenticated') unless block_num
112
+ raise Mifare::Error, "Not authenticated" unless block_num
109
113
 
110
114
  addr ||= 0
111
115
 
112
116
  res = Mifare.mifare_classic_init_value(@pointer, block_num, value, addr)
113
- (0 == res) || raise(Mifare::Error.new("Can't init value block 0x%02x" % block_num))
117
+ raise Mifare::Error, "Can't init value block 0x%02x" % block_num if 0 != res
114
118
  end
115
119
 
116
120
  # returns only value part of value block
@@ -122,12 +126,12 @@ module Mifare
122
126
  # returns value and addr
123
127
  def value_with_addr(block_num = nil)
124
128
  block_num ||= @auth_block
125
- raise Mifare::Error.new('Not authenticated') unless block_num
129
+ raise Mifare::Error, "Not authenticated" unless block_num
126
130
 
127
131
  value_ptr = FFI::MemoryPointer.new(:int32, 1)
128
132
  addr_ptr = FFI::MemoryPointer.new(:uchar, 1)
129
133
  res = Mifare.mifare_classic_read_value(@pointer, block_num, value_ptr, addr_ptr)
130
- raise Mifare::Error.new("Can't read value block 0x%02x" % block_num) unless 0 == res
134
+ raise Mifare::Error, "Can't read value block 0x%02x" % block_num if 0 != res
131
135
 
132
136
  [value_ptr.get_int32(0), addr_ptr.get_uchar(0)]
133
137
  end
@@ -135,27 +139,27 @@ module Mifare
135
139
  # Mifare classic increment
136
140
  def inc(amount = 1, block_num = nil)
137
141
  block_num ||= @auth_block
138
- raise Mifare::Error.new('Not authenticated') unless block_num
142
+ raise Mifare::Error, "Not authenticated" unless block_num
139
143
 
140
144
  res = Mifare.mifare_classic_increment(@pointer, block_num, amount)
141
- (0 == res) || raise(Mifare::Error.new("Can't increment block 0x%02x" % block_num))
145
+ raise Mifare::Error, "Can't increment block 0x%02x" % block_num if 0 != res
142
146
  end
143
147
 
144
148
  # Mifare classic decrement
145
149
  def dec(amount = 1, block_num = nil)
146
150
  block_num ||= @auth_block
147
- raise Mifare::Error.new('Not authenticated') unless block_num
151
+ raise Mifare::Error, "Not authenticated" unless block_num
148
152
 
149
153
  res = Mifare.mifare_classic_decrement(@pointer, block_num, amount)
150
- (0 == res) || raise(Mifare::Error.new("Can't decrement block 0x%02x" % block_num))
154
+ raise Mifare::Error, "Can't decrement block 0x%02x" % block_num if 0 != res
151
155
  end
152
156
 
153
157
  def transfer(block_num = nil)
154
158
  block_num ||= @auth_block
155
- raise Mifare::Error.new('Not authenticated') unless block_num
159
+ raise Mifare::Error, "Not authenticated" unless block_num
156
160
 
157
161
  res = Mifare.mifare_classic_transfer(@pointer, block_num)
158
- (0 == res) || raise(Mifare::Error.new("Can't transfer to block 0x%02x" % block_num))
162
+ raise Mifare::Error, "Can't transfer to block 0x%02x" % block_num if 0 != res
159
163
  end
160
164
 
161
165
  # Check's if our tag class is able to handle this LibNFC::Target
@@ -51,7 +51,7 @@ module Mifare
51
51
  end
52
52
 
53
53
  # frees memory allocated for mifare tag
54
- def deselect
54
+ def disconnect
55
55
  Mifare.freefare_free_tag(@pointer)
56
56
  end
57
57
 
@@ -14,18 +14,18 @@ module Mifare
14
14
 
15
15
  module Ultralight
16
16
  class Tag < Mifare::Tag
17
- def select(&block)
17
+ def connect(&block)
18
18
  @reader.set_flag(:NP_AUTO_ISO14443_4, false)
19
19
 
20
20
  res = Mifare.mifare_ultralight_connect(@pointer)
21
21
  if 0 == res
22
22
  super
23
23
  else
24
- raise Mifare::Error, "Can't select tag: #{res}"
24
+ raise Mifare::Error, "Can't connect to tag: #{res}"
25
25
  end
26
26
  end
27
27
 
28
- def deselect
28
+ def disconnect
29
29
  Mifare.mifare_ultralight_disconnect(@pointer)
30
30
  super
31
31
  end
@@ -6,12 +6,12 @@ module NFC
6
6
  @processed = false
7
7
  end
8
8
 
9
- def select(&block)
9
+ def connect(&block)
10
10
  if block_given?
11
11
  begin
12
12
  self.instance_eval(&block)
13
13
  ensure
14
- deselect
14
+ disconnect
15
15
  end
16
16
  end
17
17
  end
@@ -24,6 +24,8 @@ module NFC
24
24
  @target.processed?
25
25
  end
26
26
 
27
+ def disconnect; end
28
+
27
29
  def uid
28
30
  uid_size = @target[:nti][:nai][:szUidLen]
29
31
  @target[:nti][:nai][:abtUid].to_s[0...uid_size]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-nfc
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maxim Chechel
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ! '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  description: ! " \tThis gem is built on top of libnfc and libfreefare using ffi and
28
42
  supports:\n\t\t * Reading and writing Mifare Classic and Ultralight tags\n\t\t *
29
43
  Android HCE / Blackberry VTE emulated tags\n\t\t * Dual-interface smart cards like
@@ -33,7 +47,11 @@ executables: []
33
47
  extensions: []
34
48
  extra_rdoc_files: []
35
49
  files:
50
+ - ./LICENSE
36
51
  - ./lib/ruby-nfc.rb
52
+ - ./lib/ruby-nfc/apdu/apdu.rb
53
+ - ./lib/ruby-nfc/apdu/request.rb
54
+ - ./lib/ruby-nfc/apdu/response.rb
37
55
  - ./lib/ruby-nfc/libnfc.rb
38
56
  - ./lib/ruby-nfc/nfc.rb
39
57
  - ./lib/ruby-nfc/reader.rb
@@ -46,8 +64,8 @@ homepage: https://github.com/maximchick/ruby-nfc
46
64
  licenses:
47
65
  - MIT
48
66
  metadata: {}
49
- post_install_message: ! "Don't forget to install libnfc and libfreefare\nsee installation
50
- instructions here: \n\t https://github.com/maximchick/ruby-nfc"
67
+ post_install_message: ! " \tDon't forget to install libnfc and libfreefare\n \tsee
68
+ installation instructions here: \n \thttps://github.com/maximchick/ruby-nfc\n"
51
69
  rdoc_options: []
52
70
  require_paths:
53
71
  - lib