RR3036 0.1.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 +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +33 -0
- data/RR3036.gemspec +25 -0
- data/Rakefile +2 -0
- data/lib/RR3036/connection.rb +192 -0
- data/lib/RR3036/version.rb +3 -0
- data/lib/RR3036.rb +3 -0
- metadata +97 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b15aec9fea0dc2dc8a66ce9b4bc952bd303ce80a
|
4
|
+
data.tar.gz: 6eeb7c6c02a7e5577191ccc6d95e7ae5d3a1c6d5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7d94b8cab1303c5550cbb09580794b693242058ba1af688338dfe80dc19dc7ae0c8669ad2e139b22c3ec1413c30390efa292eca1fe53b6267c6448ac303c1d09
|
7
|
+
data.tar.gz: f1ce04ed216c361171274fce11bfde760a5f4c4d230d3e35e595754989c965bcf7ff68c46d250e506dab5128bd005990a9e1658110c8a7809c04716487c72b08
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Sascha Willuweit
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# RR3036
|
2
|
+
|
3
|
+
RR3036 RFID (ISO/IEC 15693, ISO/IEC 14443A+B) reader/writer written in Ruby. Available at http://www.rfid-in-china.com/2008-09-02/products_detail_2133.html (e.g. HF RFID Reader - 02) and http://www.rfidshop.com.hk/ (e.g. HF-TP-RW-USB-D1).
|
4
|
+
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'RR3036'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install RR3036
|
19
|
+
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
$ con = RR3036::Connection.new(<path_to_your_serial_line_device>)
|
24
|
+
$ con.dump_iso15693
|
25
|
+
|
26
|
+
|
27
|
+
## Contributing
|
28
|
+
|
29
|
+
1. Fork it
|
30
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
31
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
32
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
33
|
+
5. Create new Pull Request
|
data/RR3036.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'RR3036/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "RR3036"
|
8
|
+
spec.version = RR3036::VERSION
|
9
|
+
spec.authors = ["Sascha Willuweit"]
|
10
|
+
spec.email = ["s@rprojekt.org"]
|
11
|
+
spec.description = %q{RR3036 RFID (ISO/IEC 15693, ISO/IEC 14443A+B) connector written in Ruby.}
|
12
|
+
spec.summary = %q{RR3036 RFID (ISO/IEC 15693, ISO/IEC 14443A+B) reader/writer written in Ruby. Available at http://www.rfid-in-china.com/2008-09-02/products_detail_2133.html (e.g. HF RFID Reader - 02) and http://www.rfidshop.com.hk/ (e.g. HF-TP-RW-USB-D1).}
|
13
|
+
spec.homepage = "https://github.com/545ch4/RR3036"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "serialport"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
end
|
data/Rakefile
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require "serialport"
|
3
|
+
|
4
|
+
# RR3036 RFID (ISO/IEC 15693, ISO/IEC 14443A+B) reader/writer.
|
5
|
+
#
|
6
|
+
# Author:: Sascha Willuweit (s@rprojekt.org)
|
7
|
+
# Copyright:: Copyright (c) 2013 Sascha Willuweit
|
8
|
+
# License:: MIT
|
9
|
+
module RR3036
|
10
|
+
CMDS = {
|
11
|
+
:init_device => {:cmd => 0x00, :state => 0x00},
|
12
|
+
:close_rf => {:cmd => 0x00, :state => 0x01},
|
13
|
+
:open_rf => {:cmd => 0x00, :state => 0x02},
|
14
|
+
:led => {:cmd => 0x00, :state => 0x07},
|
15
|
+
:change_to_iso15693 => {:cmd => 0x00, :state => 0x06},
|
16
|
+
:change_to_iso14443a => {:cmd => 0x00, :state => 0x05},
|
17
|
+
:change_to_iso14443b => {:cmd => 0x00, :state => 0x09},
|
18
|
+
:iso15693_inventory => {:cmd => 0x01, :state => 0x06},
|
19
|
+
:iso15693_read_4byte => {:cmd => 0x20, :state => 0x00},
|
20
|
+
:iso15693_write_4byte => {:cmd => 0x21, :state => 0x00},
|
21
|
+
:iso15693_tag_info => {:cmd =>0x2B, :state => 0x00}
|
22
|
+
}
|
23
|
+
OPERATION_MODES = [:iso15693, :iso14443a, :iso14443b]
|
24
|
+
CRC_POLYNOMIAL = 0x8408
|
25
|
+
ERROR_MSG = {
|
26
|
+
0x01 => {:msg => 'Command operand length error', :description => 'Return status 1 to host when the number of command operands doesn’t conform to the command request.'},
|
27
|
+
0x02 => {:msg => 'Command not supported', :description => 'Return status 2 to host when the reader does not support the command the host sends.'},
|
28
|
+
0x03 => {:msg => 'Operand out of range', :description => 'Return status 3 to host when one or more operand of command data block sent by host are out of range.'},
|
29
|
+
0x04 => {:msg => 'Operation Not Availible', :description => 'Return status 4 to host when the requested operation is not available for the reader.'},
|
30
|
+
0x05 => {:msg => 'Inductive field closed', :description => 'Return status 5 to host when the inductive field is closed and the host sends a ISO15693 ISO14443 protocol command.'},
|
31
|
+
0x06 => {:msg => 'EEPROM operation error', :description => 'Return status 6 to host when the reader encounters error in EEPROM access.'},
|
32
|
+
0x0A => {:msg => 'ISO15693 Inventory Operation Error', :description => 'Return status 0x0A when the reader executing an ISO15693 Inventory command does not get one complete tag’s UID before InventoryScanTime overflows.'},
|
33
|
+
0x0B => {:msg => 'ISO15693 Inventory Operation Error', :description => 'Return status 0x0B when the reader executing an ISO15693 Inventory command does not get all tags’ UIDs before InventoryScanTime overflows.'},
|
34
|
+
0x0C => {:msg => 'ISO15693 Tag Response Error', :description => 'Return status 0x0C when the reader finds one or more tag response in a way that is not compatible with ISO15693 protocol definition.'},
|
35
|
+
0x0E => {:msg => 'ISO15693 Operation No Tag Error', :description => 'Return ox0E when the reader finds no active tag in the inductive field.'},
|
36
|
+
0x1F => {:msg => 'Protocol model error', :description => 'Return status 0x1F when the reader accepts a command not conforming to its current protocol model. For example, the reader accepts a ISO14443A protocol command but its current model is ISO15693.'},
|
37
|
+
0x0F => {:further_descriptions => {
|
38
|
+
0x01 => 'Commands not support. For example: invalid command code',
|
39
|
+
0x02 => 'Commands can not be identified. For example: invalid command format',
|
40
|
+
0x03 => 'Operation not supported',
|
41
|
+
0x0f => 'Unknown error',
|
42
|
+
0x10 => 'Appointed block is not available or don’t exist.',
|
43
|
+
0x11 => 'Appointed block has been locked and can’t be locked again.',
|
44
|
+
0x12 => 'Appointed block is locked and can’t change its content.',
|
45
|
+
0x13 => 'Appointed block does not operate normally.',
|
46
|
+
0x14 => 'Appointed block can’t be locked normally.'
|
47
|
+
}, :msg => 'ISO5693 Operation Extension error', :description => 'Return status 0x0F when an error occurred in ISO15693 command execution and the further information of the error is defined by the Error_code in response data block.'},
|
48
|
+
0x10 => {:further_descriptions => {
|
49
|
+
0x10 => 'Halt failed',
|
50
|
+
0x20 => 'No ISO14443A card in the inductive area.',
|
51
|
+
0x21 => 'select failed',
|
52
|
+
0x22 => 'authentication failed',
|
53
|
+
0x23 => 'read failed',
|
54
|
+
0x24 => 'write failed',
|
55
|
+
0x25 => 'e-wallet initialization failed',
|
56
|
+
0x26 => 'read value failed',
|
57
|
+
0x27 => 'decrement/Increment failed',
|
58
|
+
0x28 => 'transfer failed',
|
59
|
+
0x29 => 'write/read E2PROM failes',
|
60
|
+
0x2A => 'load key failed',
|
61
|
+
0x2B => 'checkwrite failed',
|
62
|
+
0x2C => 'data for checkwrite error',
|
63
|
+
0x2D => 'value operation failed',
|
64
|
+
0x2E => 'Ultralight card write failed',
|
65
|
+
0x30 => 'Anti-collision failed',
|
66
|
+
0x31 => 'Multiple card entering inductive area forbidden',
|
67
|
+
0x32 => 'Mifare I and Ultralight collision error',
|
68
|
+
0x33 => 'Ultralight card collision failed.'
|
69
|
+
}, :msg => 'ISO14443A Operation error', :description => 'Return status 0x10 when an error occurred in ISO14443A command execution and the further information of the error is defined by the Error_code in response data block.'},
|
70
|
+
0x1B => {:further_descriptions => {
|
71
|
+
0x34 => 'No ISO14443B card in the inductive area.',
|
72
|
+
0x35 => 'select failed',
|
73
|
+
0x36 => 'halt failed',
|
74
|
+
0x37 => 'execute transparent command failed',
|
75
|
+
0x38 => 'Anticollision failed'
|
76
|
+
}, :msg => 'ISO14443B Operation error', :description => 'Return status 0x1B when an error occurred in ISO14443B command execution and the further information of the error is defined by the Error_code in response data block.'}
|
77
|
+
}
|
78
|
+
|
79
|
+
class Connection
|
80
|
+
attr_reader :port, :com_addr, :operation
|
81
|
+
|
82
|
+
def initialize(device, _options = {})
|
83
|
+
options = {:baud => 19200, :data_bits => 8, :stop_bit => 1, :parity => SerialPort::NONE, :mode => OPERATION_MODES.first}.update (_options||{})
|
84
|
+
@operation = options[:mode]
|
85
|
+
@com_addr = 0x00
|
86
|
+
set_and_open_port(device, _options)
|
87
|
+
end
|
88
|
+
|
89
|
+
def set_and_open_port(device, _options = {})
|
90
|
+
options = {:baud => 19200, :data_bits => 8, :stop_bit => 1, :parity => SerialPort::NONE, :read_timeout => 1000}.update (_options||{})
|
91
|
+
@port = SerialPort.new(device, options[:baud], options[:data_bits], options[:stop_bit], options[:parity])
|
92
|
+
port.read_timeout = options[:read_timeout]
|
93
|
+
end
|
94
|
+
|
95
|
+
def send_cmd(cmd, _options = {})
|
96
|
+
options = {:data => '', :continue_on_errors => [], :dont_report_crc_failures => false}.update (_options||{})
|
97
|
+
|
98
|
+
return false unless CMDS.include? cmd
|
99
|
+
|
100
|
+
# len | com_addr | cmd | state | data | lsb-crc16 | msb-crc16
|
101
|
+
cmd_data_block = [options[:data].bytes.size + 5, com_addr, CMDS[cmd][:cmd], (operation == :iso15693 ? CMDS[cmd][:state] & 0x0F : CMDS[cmd][:state] | 0xF0)] + options[:data].bytes
|
102
|
+
cmd_data_block += crc(cmd_data_block)
|
103
|
+
written_bytes = port.write cmd_data_block.pack('C*')
|
104
|
+
port.flush
|
105
|
+
|
106
|
+
response = {:len => 0x00, :com_addr => 0x00, :status => 0x00, :data => [], :crc => [0x00, 0x00]}
|
107
|
+
response[:len] = port.readbyte
|
108
|
+
(response[:addr], response[:status]) = port.read(2).bytes.to_a
|
109
|
+
response[:data] = port.read(response[:len] - 4).bytes.pack('C*')
|
110
|
+
response[:crc] = port.read(2).bytes.pack('C*')
|
111
|
+
response[:crc_calc] = crc([response[:len], response[:addr], response[:status]] + response[:data].bytes).pack('C*')
|
112
|
+
if response[:status] > 0 && !continue_on_errors.include?(response[:status])
|
113
|
+
puts "Error: " << (ERROR_MSG[response[:status]][:msg].nil? ? 'UNKNOWN ERROR' : (ERROR_MSG[response[:status]][:msg] + ' ' + ERROR_MSG[response[:status]][:description]) + ' ' + response[:data].inspect) << (ERROR_MSG[response[:status]] && ERROR_MSG[response[:status]][:further_descriptions] && !response[:data].empty? && ERROR_MSG[response[:status]][:further_descriptions][response[:data]] ? ERROR_MSG[response[:status]][:further_descriptions][response[:data]] : '')
|
114
|
+
end
|
115
|
+
if response[:crc] != response[:crc_calc] && !options[:dont_report_crc_failures]
|
116
|
+
puts "Error: CRC doesn't match."
|
117
|
+
end
|
118
|
+
return response
|
119
|
+
end
|
120
|
+
|
121
|
+
def method_missing(m, *args)
|
122
|
+
if CMDS[m.to_sym]
|
123
|
+
send_cmd(m.to_sym, *args)
|
124
|
+
else
|
125
|
+
super
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def dump_iso15693
|
130
|
+
response = init_device
|
131
|
+
puts "Init version=%i, RFU=%i, reader_type=%s, tr_type=%i, inventory_scan_time=%i"%(response[:data].unpack('S>S>hS>C'))
|
132
|
+
|
133
|
+
response = change_to_iso15693
|
134
|
+
puts "Changed to ISO15693" if response[:status] == 0
|
135
|
+
|
136
|
+
while(true)
|
137
|
+
tags = []
|
138
|
+
tag = nil
|
139
|
+
puts "Please press any key to start inventory"
|
140
|
+
gets
|
141
|
+
response = iso15693_inventory(:continue_on_errors => [0x0E])
|
142
|
+
((response[:len] - 4) / 9).times do |i|
|
143
|
+
(dsfid, uid) = response[:data][((i - 1) * 9)..((i * 9) - 1)].unpack('Ca8')
|
144
|
+
puts "#{i}) ISO15693 tag #{bytes_to_hex_string uid} with uid=#{uid.unpack('i')} (dsfid=#{dsfid})"
|
145
|
+
tags << {:block_data => [], :block_security_flag => [], :dsfid => dsfid, :uid => uid}
|
146
|
+
end
|
147
|
+
if tags.empty?
|
148
|
+
continue
|
149
|
+
else
|
150
|
+
puts "Please select a tag:"
|
151
|
+
tag = tags[gets.strip.to_i]
|
152
|
+
continue if tag.nil?
|
153
|
+
end
|
154
|
+
|
155
|
+
info = iso15693_tag_info(:data => tag[:uid])
|
156
|
+
(tag[:flag], _uid, _dsfid, tag[:afi], tag[:mem_size], tag[:ic_ref]) = info[:data].unpack('hh8CCS>C')
|
157
|
+
puts "ISO15693 tag #{bytes_to_hex_string tag[:uid]} info: flag=#{tag[:flag]}, afi=#{tag[:afi]}, mem_size=#{tag[:mem_size]}, ic_ref=#{tag[:ic_ref]}"
|
158
|
+
# TODO 4-byte vs. 8-byte reads
|
159
|
+
64.times do |i|
|
160
|
+
block = iso15693_read_4byte(:data => tag[:uid] + i.chr)
|
161
|
+
tag[:block_data] << block[:data][1..-1]
|
162
|
+
tag[:block_security_flag] << block[:data][0]
|
163
|
+
puts "ISO15693 tag #{bytes_to_hex_string tag[:uid]} block #{i}: #{bytes_to_hex_string block[:data][0]} #{block[:data][1..-1].inspect} (#{bytes_to_hex_string block[:data][1..-1]})"
|
164
|
+
end
|
165
|
+
|
166
|
+
puts "ISO15693 tag #{bytes_to_hex_string tag[:uid]} joined together: #{tag[:block_data].join.strip.inspect}"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
def bytes_to_hex_string(b)
|
173
|
+
(b.respond_to?(:bytes) ? b.bytes : b).map{|x| ('%2x'%(x)).sub(' ', '0')}.join
|
174
|
+
end
|
175
|
+
|
176
|
+
def crc(data)
|
177
|
+
crc_value = 0xFFFF
|
178
|
+
(data.kind_of?(Array) ? data : data.bytes).each do |b|
|
179
|
+
crc_value = crc_value ^ b
|
180
|
+
8.times do
|
181
|
+
if (crc_value & 0x0001) == 0x0001
|
182
|
+
crc_value = (crc_value >> 1) ^ CRC_POLYNOMIAL
|
183
|
+
else
|
184
|
+
crc_value = (crc_value >> 1)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
# LSB-CRC-16, MSB-CRC16
|
189
|
+
return [crc_value & 0x00FF, (crc_value >> 8) & 0x00FF]
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
data/lib/RR3036.rb
ADDED
metadata
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: RR3036
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sascha Willuweit
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-11-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: serialport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: RR3036 RFID (ISO/IEC 15693, ISO/IEC 14443A+B) connector written in Ruby.
|
56
|
+
email:
|
57
|
+
- s@rprojekt.org
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- .gitignore
|
63
|
+
- Gemfile
|
64
|
+
- LICENSE.txt
|
65
|
+
- README.md
|
66
|
+
- RR3036.gemspec
|
67
|
+
- Rakefile
|
68
|
+
- lib/RR3036.rb
|
69
|
+
- lib/RR3036/connection.rb
|
70
|
+
- lib/RR3036/version.rb
|
71
|
+
homepage: https://github.com/545ch4/RR3036
|
72
|
+
licenses:
|
73
|
+
- MIT
|
74
|
+
metadata: {}
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
requirements: []
|
90
|
+
rubyforge_project:
|
91
|
+
rubygems_version: 2.1.9
|
92
|
+
signing_key:
|
93
|
+
specification_version: 4
|
94
|
+
summary: RR3036 RFID (ISO/IEC 15693, ISO/IEC 14443A+B) reader/writer written in Ruby.
|
95
|
+
Available at http://www.rfid-in-china.com/2008-09-02/products_detail_2133.html (e.g.
|
96
|
+
HF RFID Reader - 02) and http://www.rfidshop.com.hk/ (e.g. HF-TP-RW-USB-D1).
|
97
|
+
test_files: []
|