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 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
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in RR3036.gemspec
4
+ gemspec
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,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -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
@@ -0,0 +1,3 @@
1
+ module RR3036
2
+ VERSION = "0.1.0"
3
+ end
data/lib/RR3036.rb ADDED
@@ -0,0 +1,3 @@
1
+ # coding: utf-8
2
+ require "RR3036/version"
3
+ require "RR3036/connection"
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: []