rs232 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.
- data/README +40 -0
- data/lib/rs232.rb +144 -0
- data/rakefile.rb +11 -0
- data/test/test_rs232.rb +19 -0
- metadata +79 -0
data/README
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
##
|
2
|
+
#
|
3
|
+
# RS232
|
4
|
+
#
|
5
|
+
# Ruby interface to Windows Serial Port API
|
6
|
+
#
|
7
|
+
# author hugo benichi
|
8
|
+
# email hugo.benichi@m4x.org
|
9
|
+
# copyright 2012 hugo benichi
|
10
|
+
# version 0.1.0
|
11
|
+
#
|
12
|
+
##
|
13
|
+
|
14
|
+
installation:
|
15
|
+
|
16
|
+
run in the root directory
|
17
|
+
rake gem_install
|
18
|
+
|
19
|
+
it will compile the gem library and produce a .gem package for ruby
|
20
|
+
it will then install the .gem automatically
|
21
|
+
|
22
|
+
usage:
|
23
|
+
|
24
|
+
cf test/test_rs232.rb
|
25
|
+
|
26
|
+
first, require the gem with
|
27
|
+
require 'rs232'
|
28
|
+
|
29
|
+
then instance an object of RS232, passing an address, and optionally parameters to configure
|
30
|
+
serial_port = RS232.new 'COM1'
|
31
|
+
|
32
|
+
the default parameters are
|
33
|
+
baud rate: 9600
|
34
|
+
8 bits
|
35
|
+
1 bit stop bit
|
36
|
+
no parity bit
|
37
|
+
control flow hardware (RTS/CTS)
|
38
|
+
delimiters "\r\n"
|
39
|
+
|
40
|
+
you can directly use the RS232 instance with the 'write', 'read', and 'query' commands
|
data/lib/rs232.rb
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
|
2
|
+
class RS232
|
3
|
+
|
4
|
+
require 'ffi'
|
5
|
+
|
6
|
+
attr_accessor :report, :delimiter
|
7
|
+
attr_reader :count, :error
|
8
|
+
|
9
|
+
# serial port object constructor
|
10
|
+
# also sets the parameters and timeout properties through an hash argument
|
11
|
+
def initialize address, params = {}
|
12
|
+
mode = Win32::GENERIC_READ | Win32::GENERIC_WRITE
|
13
|
+
type = Win32::OPEN_EXISTING
|
14
|
+
attr = Win32::FILE_ATTRIBUTE_NORMAL
|
15
|
+
@serial = Win32::CreateFileA( address, mode, 0, nil, type, attr, nil)
|
16
|
+
@error = Win32.error_check
|
17
|
+
puts "RS232 >> got file handle 0x%.8x for com port %s" % [@serial, address]
|
18
|
+
DCB.new.tap do |p|
|
19
|
+
p[:dcblength] = DCB::Sizeof
|
20
|
+
Win32::GetCommState @serial, p
|
21
|
+
p[:baudrate] = params[:baudrate] || 9600
|
22
|
+
p[:bytesize] = params[:bytesize] || 8
|
23
|
+
p[:stopbits] = params[:stopbits] || DCB::ONESTOPBIT
|
24
|
+
p[:parity] = params[:parity] || DCB::NOPARITY
|
25
|
+
Win32::SetCommState @serial, p
|
26
|
+
@error = Win32.error_check
|
27
|
+
end
|
28
|
+
CommTimeouts.new.tap do |timeouts|
|
29
|
+
timeouts[:read_interval_timeout] = params[:read_interval_timeout] || 50
|
30
|
+
timeouts[:read_total_timeout_multiplier] = params[:read_total_timeout_multiplier] || 50
|
31
|
+
timeouts[:read_total_timeout_constant] = params[:read_total_timeout_constant] || 10
|
32
|
+
timeouts[:write_total_timeout_multiplier] = params[:write_total_timeout_multiplier] || 50
|
33
|
+
timeouts[:write_total_timeout_constant] = params[:write_total_timeout_constant] || 10
|
34
|
+
Win32::SetCommTimeouts @serial, timeouts
|
35
|
+
@error = Win32.error_check
|
36
|
+
end
|
37
|
+
grow_buffer 128
|
38
|
+
@count = FFI::MemoryPointer.new :uint, 1
|
39
|
+
@report = false
|
40
|
+
@delimiter = params[:delimiter] || "\r\n"
|
41
|
+
end
|
42
|
+
|
43
|
+
# writes a string to the Serial port and happens the delimiter characters stores in @delimiters
|
44
|
+
def write string
|
45
|
+
command = "%s%s" % [string.chomp, @delimiter]
|
46
|
+
grow_buffer command.length
|
47
|
+
@buffer.write_string command
|
48
|
+
Win32::WriteFile @serial, @buffer, command.length, @count, nil
|
49
|
+
@error = Win32.error_check
|
50
|
+
puts "write count %i" % @count.read_uint32 if @report
|
51
|
+
end
|
52
|
+
|
53
|
+
# read a string from the Serial port
|
54
|
+
def read
|
55
|
+
Win32::ReadFile @serial, @buffer, @buflen, @count, nil
|
56
|
+
@error = Win32.error_check
|
57
|
+
puts "read count %i" % @count.read_uint32 if @report
|
58
|
+
@buffer.read_string
|
59
|
+
end
|
60
|
+
|
61
|
+
# write and read helper method
|
62
|
+
def query string
|
63
|
+
write sring
|
64
|
+
read
|
65
|
+
end
|
66
|
+
|
67
|
+
# close the Com port
|
68
|
+
def stop
|
69
|
+
Win32::CloseHandle @serial
|
70
|
+
@error = Win32.error_check
|
71
|
+
end
|
72
|
+
|
73
|
+
# increase the buffer size for reading and writing
|
74
|
+
def grow_buffer size
|
75
|
+
@buffer = FFI::MemoryPointer.new :char, @buflen = size if @buffer.nil? || @buflen < size
|
76
|
+
end
|
77
|
+
|
78
|
+
# wraps the native Windows API functions for file IO and COMM port found in kernel32.dll
|
79
|
+
module Win32
|
80
|
+
extend FFI::Library
|
81
|
+
ffi_lib 'kernel32.dll'
|
82
|
+
[
|
83
|
+
[ :GetLastError, [], :uint32],
|
84
|
+
[ :CreateFileA, [:pointer, :uint32, :uint32, :pointer, :uint32, :uint32, :pointer], :pointer],
|
85
|
+
# CreateFile first argument is a const char*
|
86
|
+
# Windows can decide to read it as a C string (1 char = 1 byte) or a unicode string (1 char = 2 byte)
|
87
|
+
# the real dll functions are actually CreateFileA for the C strings and CreateFileW for unicode
|
88
|
+
# I strongly suggest to use CreateFileA since FFI will automatically write a C string from Ruby string
|
89
|
+
[ :CloseHandle, [:pointer], :int],
|
90
|
+
[ :ReadFile, [:pointer, :pointer, :uint32, :pointer, :pointer], :int32],
|
91
|
+
[ :WriteFile, [:pointer, :pointer, :uint32, :pointer, :pointer], :int32],
|
92
|
+
[ :GetCommState, [:pointer, :pointer], :int32],
|
93
|
+
[ :SetCommState, [:pointer, :pointer], :int32],
|
94
|
+
[ :GetCommTimeouts, [:pointer, :pointer], :int32],
|
95
|
+
[ :SetCommTimeouts, [:pointer, :pointer], :int32],
|
96
|
+
].each{ |sig| attach_function *sig }
|
97
|
+
def self.error_code
|
98
|
+
err = self::GetLastError()
|
99
|
+
"error code: %i | 0x%.8x" % [err,err]
|
100
|
+
end
|
101
|
+
def self.error_check
|
102
|
+
self::GetLastError().tap{ |err| puts "error: %i | 0x%.8x" % [err,err] if err != 0 }
|
103
|
+
end
|
104
|
+
GENERIC_READ = 0x80000000 # consts from Windows seven sdk:
|
105
|
+
GENERIC_WRITE = 0x40000000 # extract with
|
106
|
+
OPEN_EXISTING = 3 # grep -i "generic_read" *.h
|
107
|
+
FILE_ATTRIBUTE_NORMAL = 0x00000080 # from the /Include directory
|
108
|
+
end
|
109
|
+
|
110
|
+
# this struct is used by windows to configure the COMM port
|
111
|
+
class DCB < FFI::Struct
|
112
|
+
layout :dcblength, :uint32,
|
113
|
+
:baudrate, :uint32,
|
114
|
+
:flags, :uint32, # the :flag uint32 is actually a bit fields compound with structure
|
115
|
+
:wreserved, :uint16, # uint32 fBinary :1;
|
116
|
+
:xonlim, :uint16, # uint32 fParity :1;
|
117
|
+
:xofflim, :uint16, # uint32 fParity :1;
|
118
|
+
:bytesize, :uint8, # uint32 fOutxCtsFlow :1;
|
119
|
+
:parity, :uint8, # uint32 fOutxDsrFlow :1;
|
120
|
+
:stopbits, :uint8, # uint32 fDtrControl :2;
|
121
|
+
:xonchar, :int8, # uint32 fDsrSensitivity :1;
|
122
|
+
:xoffchar, :int8, # uint32 fTXContinueOnXoff :1;
|
123
|
+
:errorchar, :int8, # uint32 fOutX :1;
|
124
|
+
:eofchar, :int8, # uint32 fInX :1;
|
125
|
+
:evtchar, :int8, # uint32 fErrorChar :1;
|
126
|
+
:wreserved1, :uint16 # uint32 fNull :1;
|
127
|
+
# uint32 fRtsControl :2;
|
128
|
+
# uint32 fAbortOnError :1;
|
129
|
+
# uint32 fDummy2 :17;
|
130
|
+
Sizeof = 28 # this is used to tell windows the size of its own struct, not sure why it is necessary (different Windows version)
|
131
|
+
ONESTOPBIT = 0
|
132
|
+
NOPARITY = 0
|
133
|
+
end
|
134
|
+
|
135
|
+
# this structure is used to set timeout properties of the opened COM ports
|
136
|
+
class CommTimeouts < FFI::Struct
|
137
|
+
layout :read_interval_timeout, :uint32,
|
138
|
+
:read_total_timeout_multiplier, :uint32,
|
139
|
+
:read_total_timeout_constant, :uint32,
|
140
|
+
:write_total_timeout_multiplier, :uint32,
|
141
|
+
:write_total_timeout_constant, :uint32
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
data/rakefile.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
task :test_global do ruby "test/test_rs232.rb" end
|
2
|
+
task :test_local do ruby "-Ilib test/test_rs232.rb" end
|
3
|
+
|
4
|
+
task :gem_build do sh "gem build rs232.gemspec" end
|
5
|
+
task :gem_install => :gem_build do
|
6
|
+
gemfile = Dir.new("./").entries.select{ |f| f =~ /rs232-[\d]+\.[\d]+\.[\d]+.gem/ }.sort[-1]
|
7
|
+
puts "installing %s" % gemfile
|
8
|
+
#sh "gem install --local %s" % gemfile
|
9
|
+
end
|
10
|
+
|
11
|
+
task :default => :test_local
|
data/test/test_rs232.rb
ADDED
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rs232
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Hugo Benichi
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2012-07-10 00:00:00 +09:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: ffi
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
33
|
+
description: Allows to script access to the serial port on Windows. Simple read and write commands
|
34
|
+
email: hugo.benichi@m4x.org
|
35
|
+
executables: []
|
36
|
+
|
37
|
+
extensions: []
|
38
|
+
|
39
|
+
extra_rdoc_files: []
|
40
|
+
|
41
|
+
files:
|
42
|
+
- lib/rs232.rb
|
43
|
+
- test/test_rs232.rb
|
44
|
+
- rakefile.rb
|
45
|
+
- README
|
46
|
+
has_rdoc: true
|
47
|
+
homepage: http://github.com/hugobenichi/rs232
|
48
|
+
licenses: []
|
49
|
+
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
segments:
|
69
|
+
- 0
|
70
|
+
version: "0"
|
71
|
+
requirements: []
|
72
|
+
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 1.3.7
|
75
|
+
signing_key:
|
76
|
+
specification_version: 3
|
77
|
+
summary: Ruby interface to Windows Serial Port API
|
78
|
+
test_files: []
|
79
|
+
|