rs232 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|