rdm6300 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/rdm6300.rb +138 -0
  3. metadata +58 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: de049d9e1aa342bf79fd57474de2068df2fc54a7a88750305771656c28f11a90
4
+ data.tar.gz: 567199ef4ae0818b72f0c64b7c47732a332deec14ac0132a9aaa50a57c2db27e
5
+ SHA512:
6
+ metadata.gz: bf5e6ebfde8424c50a90b0f8e2822ec6ac863586a8722b4c4ade44241af398a162b5140cfc6f76b5677304868f915849b964e2dafe0a7ce4b1ef41ba193d8d17
7
+ data.tar.gz: a60e53446d3ab94efcb6f1b21d86dbc7082cc3ad626a76098437a08e094e0a3d757c15540869cb3d66f86d836dd227eb5ef3be4483116a1f26566245ea603284
data/lib/rdm6300.rb ADDED
@@ -0,0 +1,138 @@
1
+ require 'serialport'
2
+
3
+ ##
4
+ # This class reads 125kHz tags over an RS-232 serial port using the RDM6300 module
5
+ class Rdm6300
6
+ ##
7
+ # Read 125kHz RFID tags from a serial port using the RDM6300 module as follows:
8
+ # rdm = Rdm6300.new('/dev/ttyS0')
9
+ # while true
10
+ # puts rdm.get_tag()
11
+ # end
12
+ #
13
+ # This will return a zero-padded string with the tag number.
14
+
15
+ # RDM6300 uses 0x02 to indicate the start of a tag
16
+ START_CODE = 0x02
17
+ # RDM6300 uses 0x03 to indicate the end of a tag
18
+ END_CODE = 0x03
19
+ # Valid tag data will always have a total length of 12 bytes over RS-232
20
+ VALID_LENGTH = 12
21
+
22
+ # The default serial port is /dev/ttyAMA0 since this is the primary serial port on a Raspberry Pi
23
+ #
24
+ # You will need to stop the Linux kernel using /dev/ttyAMA0 if you want to use it with the RDM6300
25
+ #
26
+ # On a Raspberry Pi 4 and Raspberry Pi OS, this can be done by adding enable_uart=1 and dtoverlay=disable-bt to /boot/config.txt
27
+ # and removing console=serial0,115200 from /boot/cmdline.txt
28
+ #
29
+ # The flush delay handles the situation where rogue RF triggers the RDM6300. Genuine tag data takes less than a second
30
+ # to transmit to the RDM6300. If there is tag data that takes longer than flush_delay to arrive, the input buffer is flushed.
31
+ # This improves the reliability of a long-running tag reader.
32
+ def initialize(serial_port_dev = '/dev/ttyAMA0', debug: false, flush_delay: 10)
33
+ @serial_port_dev = serial_port_dev
34
+ @debug = debug
35
+ @flush_delay = flush_delay
36
+ @serial_port = SerialPort.new(@serial_port_dev, 9600, 8, 1, SerialPort::NONE)
37
+ @serial_port.read_timeout = 0
38
+ end
39
+
40
+ # Closes the serial port
41
+ def close
42
+ @serial_port.close
43
+ end
44
+
45
+ # Waits for a tag to be presented and returns a zero-padded string with the tag id
46
+ def get_tag()
47
+ @received_bytes = []
48
+ @time_of_last_byte = Time.now
49
+ @receive_started = false
50
+
51
+ # Flush input buffer if partial data was received
52
+ @timeout_active = true
53
+ Thread.new do
54
+ while @timeout_active
55
+ sleep 1
56
+ if @receive_started and (Time.now - @time_of_last_byte) > @flush_delay
57
+ STDERR.puts "Received_bytes not empty after #{@flush_delay}s" if @debug
58
+ @time_of_last_byte = Time.now
59
+ @received_bytes = []
60
+ @receive_started = false
61
+ end
62
+ end
63
+ end
64
+
65
+ while true
66
+ byte = nil
67
+ begin
68
+ byte = @serial_port.readbyte
69
+ rescue EOFError => e
70
+ # This shouldn't happen if @serial_port.read_timeout == 0
71
+ STDERR.puts "Timed out reading serial data" if @debug
72
+ @time_of_last_byte = Time.now
73
+ @received_bytes = []
74
+ next
75
+ end
76
+
77
+ # check if this is the first byte received and it is valid. if not, reset
78
+ if !@receive_started and byte != START_CODE
79
+ STDERR.puts "Got initial byte but it is not #{START_CODE} (#{byte})" if @debug
80
+ reset_serial_buffer()
81
+ end
82
+
83
+ if !@receive_started and byte == START_CODE
84
+ @receive_started = true
85
+ @time_of_last_byte = Time.now
86
+ next
87
+ end
88
+
89
+ if byte > 127
90
+ STDERR.puts "Got invalid byte #{byte}, resetting" if @debug
91
+ reset_serial_buffer()
92
+ next
93
+ end
94
+
95
+ if byte == END_CODE
96
+ if @received_bytes.length == VALID_LENGTH
97
+ if checksum_is_valid?(@received_bytes)
98
+ @timeout_active = false
99
+ return '%010d' % @received_bytes[2..9].join.to_i(16)
100
+ else
101
+ STDERR.puts "Failed to verify checksum for received data" if @debug
102
+ end
103
+ else
104
+ STDERR.puts "Invalid number of bytes received (#{@received_bytes.length})" if @debug
105
+ end
106
+ reset_serial_buffer()
107
+ next
108
+ end
109
+
110
+ @received_bytes << byte.chr
111
+ end
112
+ end
113
+
114
+ # Resets the serial buffer, called after a tag is presented
115
+ def reset_serial_buffer()
116
+ @receive_started = false
117
+ @received_bytes = []
118
+ @serial_port.close
119
+ @serial_port = SerialPort.new(@serial_port_dev, 9600, 8, 1, SerialPort::NONE)
120
+ @time_of_last_byte = Time.now
121
+ end
122
+
123
+ # Checks if the tag checksum is valid
124
+ def checksum_is_valid?(received_bytes)
125
+ # Format is 10 data bytes then two checksum bytes
126
+ # Group the received bytes into pairs, convert from ascii to hex, then XOR them
127
+ pairs = []
128
+ received_bytes[0..9].each_with_index do |char, index|
129
+ next if index % 2 == 1
130
+ pairs << char + received_bytes[index + 1]
131
+ end
132
+ checksum = pairs.map { |pair| pair.to_i(16) }.inject(:^)
133
+
134
+ # Then compare to [10..12] of received_checksum
135
+ received_checksum = (received_bytes[10] + received_bytes[11]).to_i(16)
136
+ return checksum == received_checksum
137
+ end
138
+ end
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rdm6300
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Luke Stutters
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-05-28 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: '1.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ description: rdm6300 is a Ruby library provides a simple interface for reading 125kHz
28
+ RFID tags over an RS-232 serial port using the RDM6300 module
29
+ email: lukestuts@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - lib/rdm6300.rb
35
+ homepage: https://github.com/lukestuts/ruby-rdm6300
36
+ licenses:
37
+ - GPL-3.0
38
+ metadata: {}
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubygems_version: 3.0.3
55
+ signing_key:
56
+ specification_version: 4
57
+ summary: Read 125kHz RFID tags using the RDM6300 module
58
+ test_files: []