RR3036 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []