rdm6300 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.
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: []