This is a multi-part message in MIME format.

------extPart_000_000D_01C1C568.EBA5B220
Content-Type: text/plain;
	charsetindows-1255"
Content-Transfer-Encoding: 7bit

David, I had the same need and have been using win32ole to access the mscomm
serial com object which comes with visual basic.

I am enclosing a copy of the code I wrote.... consider it an alpha, It's
almost midnight here so I will send an example of it's use tomorrow.  Please
do not put into general circulation yet, I need to spend some more time on
it.  Hope it helps... Let me know.

Ignore the PacketizeData class, I'm still working on that. :)

-----Original Message-----
From: David Wende [mailto:DWende / lynxpn.com]
Sent: Wednesday, March 06, 2002 11:38 AM
To: ruby-talk ML
Subject: Ruby Serial Ports under Windows


I've started using Ruby a week ago as my first OOP
language - very impressed.
I need to access the COM1 serial port under Windows.
Can this be done?

Thanks

David Wende


------extPart_000_000D_01C1C568.EBA5B220
Content-Type: application/octet-stream;
	nameScomm.rb"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filenameScomm.rb"

require 'win32ole'
require 'thread.rb'

class MSComm
  include WIN32OLE::VARIANT

	# Handshake Constants
	CONST_comNone				= 0 	# No handshaking.
	CONST_comXonXoff 			= 1 	# XOn/XOff handshaking.
	CONST_comRTS 				= 2 	# Request-to-send/clear-to-send handshaking.
	CONST_comRTSXOnXOff 		= 3 	# Both request-to-send and XOn/XOff handshaking.

	# OnComm Constants
	CONST_comEvSend 			= 1 	# Send event.
	CONST_comEvReceive 			= 2 	# Receive event.
	CONST_comEvCTS	 			= 3 	# Change in clear-to-send line.
	CONST_comEvDSR 				= 4 	# Change in data-set ready line.
	CONST_comEvCD 				= 5 	# Change in carrier detect line.
	CONST_comEvRing 			= 6 	# Ring detect.
	CONST_comEvEOF 				= 7 	# End of file.

	# Error Constants
	CONST_comEventBreak 		= 1001 	# Break signal received
	CONST_comEventFrame 		= 1004 	# Framing error
	CONST_comEventOverrun 		= 1006 	# Port overrun
	CONST_comEventRxOver 		= 1008 	# Receive buffer overflow
	CONST_comEventRxParity	 	= 1009 	# Parity error
	CONST_comEventTxFull 		= 1010 	# Transmit buffer full
	CONST_comEventDCB 			= 1011 	# Unexpected error retrieving Device Control Block (DCB) for the port

	# InputMode Constants
	CONST_comInputModeText 		= 0 	# (Default) Data is retrieved through the Input property as text.
	CONST_comInputModeBinary  	= 1 	# Data is retrieved through the Input property as binary data.

	@@clsid 	= "{648A5600-2C6E-101B-82B6-000000000014}"
	@@progid 	= "MSCOMMLib.MSComm"

	def initialize
		@dispatch 	= WIN32OLE.new @@progid
		@lastargs 	= nil
		@handlers   = {}
		@we         = nil
		@mutex		= Mutex.new
	end

	def AboutBox()
		ret = @dispatch._invoke(-552, [],[])
		@lastargs = WIN32OLE::ARGV
		ret
	end

	#----------------------------------------------------------
	# onEvent allows you to specify individual Proc routines
	# for events as specified above.
	# ie.
	# 	onEvent ( [MSComm::CONST_comEvReceive], Proc.new { | e, mscomm | print "Receive happened" }
	# 	onEvent ( [MSComm::CONST_comEvReceive,MSComm::CONST_comEvSend], Proc.new { | e, mscomm | print "Receive or send happened" }
	#
	# Note: that the proc must take a single argument which
	# is the MSComm object itself.
	#----------------------------------------------------------
	def onEvent ( eventList, handler = nil )
		raise "Invalid Event Array" if !eventList.kind_of?( Array )
		raise "Invalid Handler" if !( handler.nil? || handler.kind_of?( Proc ) )
		raise "Invalid Handler - should handle two arguments ( event, mscomm )." if handler.kind_of?( Proc ) && handler.arity != 2
		@mutex.synchronize do
			eventList.each { |e|
				@handlers[e] = handler
			}
		end
	end

	def CommPort
		@dispatch.CommPort
	end

	def baud
		@dispatch.Settings.split(",")[0]
	end

	def parity
		@dispatch.Settings.split(",")[1]
	end

	def dataBits
		@dispatch.Settings.split(",")[2]
	end

	def stopBits
		@dispatch.Settings.split(",")[3]
	end

	def Handshaking
		@dispatch.Handshaking
	end

	def Handshaking= ( hsMode )
		raise "Invalid handshaking value (#{hsMode})" if [CONST_comNone,CONST_comXonXoff,CONST_comRTS,CONST_comRTSXOnXOff].index( hsMode ) == nil
		@dispatch.Handshaking = hsMode
	end

	def RThreshold
		@dispatch.RThreshold
	end

	def RThreshold= ( numOfChars )
		@dispatch.RThreshold = numOfChars
	end

	def SThreshold
		@dispatch.SThreshold
	end

	def SThreshold= ( numOfChars )
		@dispatch.SThreshold = numOfChars
	end

	def open ( settings )
		close if self.PortOpen
		s = settings.split(":")
		s2 = s[1].split(",")
		# valid comm port?
		port = %w{ COM1 COM2 COM3 COM4 COM5 COM6 COM7 COM8 COM9 COM10 COM11 COM12 COM13 COM14 COM15 COM16 }.index( s[0].upcase )
		raise "Invalid COM Port (#{s[0].upcase})" if port.nil?
		raise "Invalid Baud (#{s2[0].upcase})" if %w{ 110 300 600 1200 2400 9600 14400 19200 28800 38400 56000 128000 256000 }.index( s2[0].upcase ) == nil
		raise "Invalid Parity (#{s2[1].upcase})" if %w{ E M N O S }.index( s2[1].upcase ) == nil
		raise "Invalid Databits (#{s2[2].upcase})" if %w{ 4 5 6 7 8 }.index( s2[2].upcase ) == nil
		raise "Invalid Stopbits (#{s2[3].upcase})" if %w{ 1 1.5 2 }.index( s2[3].upcase ) == nil
		begin
	  		@dispatch.CommPort = port+1
			@dispatch.Settings = s[1]
			@dispatch.PortOpen = true
			@we = WIN32OLE_EVENT.new( @dispatch )
			@we.on_event { |*args| self.onEventHandler( *args ) }
			true
		rescue
			false
		end
	end

	def close
		@dispatch.PortOpen = false
		@we = nil
	end

	def Break
		@dispatch.Break
	end

	def Break= ( onOff )
		@dispatch.Break = onOff
	end

	def CommID
		@dispatch.CommID
	end

	def PortOpen
		@dispatch.PortOpen
	end

	def InBufferSize
		@dispatch.InBufferSize
	end

	def InBufferSize= ( size )
		@dispatch.InBufferSize = size
	end

	def InBufferCount
		@dispatch.InBufferCount
	end

	def Input
		@dispatch.Input
	end

	def Name
		@dispatch.Name
	end

	def InputLen
		@dispatch.InputLen
	end

	def InputLen= ( size )
		@dispatch.InputLen = size
	end

	def InputMode
		@dispatch.InputMode
	end

	def InputMode= ( mode )
		raise "Invalid input mode (#{mode})" if [CONST_comInputModeText,CONST_comInputModeBinary].index( mode ) == nil
		@dispatch.InputMode = mode
	end

	def setInputToText
		self.InputMode = CONST_comInputModeText
	end

	def setInputToBinary
		self.InputMode = CONST_comInputModeBinary
	end

	def isTextMode?
		self.InputMode == CONST_comInputModeText
	end

	def isBinaryMode?
		self.InputMode == CONST_comInputModeBinary
	end

	def Output= ( out )
		@dispatch.Output = out
	end

	def OutBufferCount
		@dispatch.OutBufferCount
	end

	def OutBufferSize
		@dispatch.OutBufferSize
	end

	def OutBufferSize= ( size )
		@dispatch.OutBufferSize = size
	end

	def CDHolding
		@dispatch.CDHolding
	end

	def CTSHolding
		@dispatch.CTSHolding
	end

	def DSRHolding
		@dispatch.DSRHolding
	end

	def DTREnable
		@dispatch.DTREnable
	end

	def DTREnable= ( onOff )
		@dispatch.DTREnable = onOff
	end

	def EOFEnable
		@dispatch.EOFEnable
	end

	def EOFEnable= ( onOff )
		@dispatch.EOFEnable = onOff
	end

	def RTSEnable
		@dispatch.RTSEnable
	end

	def RTSEnable= ( onOff )
		@dispatch.RTSEnable = onOff
	end

	def onEventHandler ( *args )
		raise "Invalid Event Notification #{args[0]}" if  args[0] != "OnComm"
		handler = nil
		e = @dispatch.CommEvent
		@mutex.synchronize do
			handler = @handlers[e]
			handler = @handlers["*"] if handler.nil?
		end
		handler.call( e, self ) if !handler.nil?
	end

end

class PacketizeData
	def initialize ( beginPacket, endPacket, onCompletePacket, onOutOfBoundsData )
		@bp 	= beginPacket
		@ep 	= endPacket
		@onCP 	= onCompletePacket
		@onOBD	= onOutOfBoundsData
		@data 	= ""
	end

	def clear
		@data = nil
	end

	def addData ( data )
		@data += data
		while ( @data.length )
			if ( @bp.nil? ) then
				#simply search for the end of the packet
				p = @data.index( @ep )
				if ( !p.nil? ) then
					@onCP.call( @data[0,p] )
					@data = @data[p+@ep.length,-1]
				else
					return
				end
			else
				# could be a partial match
			end
		end
	end

end
------extPart_000_000D_01C1C568.EBA5B220--