Class: OpenC3::Win32SerialDriver
- Defined in:
- lib/openc3/io/win32_serial_driver.rb
Overview
Serial driver for use on Windows serial ports
Instance Method Summary collapse
-
#close ⇒ Object
Disconnects the driver from the comm port.
-
#closed? ⇒ Boolean
Whether the serial port has been closed.
-
#initialize(port_name = 'COM1', baud_rate = 9600, parity = :NONE, stop_bits = 1, write_timeout = 10.0, read_timeout = nil, read_polling_period = 0.01, read_max_length = 1000, flow_control = :NONE, data_bits = 8) ⇒ Win32SerialDriver
constructor
A new instance of Win32SerialDriver.
-
#read ⇒ String
Binary data read from the serial port.
-
#read_nonblock ⇒ String
Binary data read from the serial port.
- #write(data) ⇒ Object
Constructor Details
#initialize(port_name = 'COM1', baud_rate = 9600, parity = :NONE, stop_bits = 1, write_timeout = 10.0, read_timeout = nil, read_polling_period = 0.01, read_max_length = 1000, flow_control = :NONE, data_bits = 8) ⇒ Win32SerialDriver
Returns a new instance of Win32SerialDriver.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/openc3/io/win32_serial_driver.rb', line 30 def initialize(port_name = 'COM1', baud_rate = 9600, parity = :NONE, stop_bits = 1, write_timeout = 10.0, read_timeout = nil, read_polling_period = 0.01, read_max_length = 1000, flow_control = :NONE, data_bits = 8) # Verify Parameters port_name = '\\\\.\\' + port_name if /^COM[0-9]{2,3}$/.match?(port_name) raise(ArgumentError, "Invalid baud rate: #{baud_rate}") unless baud_rate.between?(Win32::BAUD_RATES[0], Win32::BAUD_RATES[-1]) raise(ArgumentError, "Invalid data bits: #{data_bits}") unless [5, 6, 7, 8].include?(data_bits) raise(ArgumentError, "Invalid parity: #{parity}") if parity and !SerialDriver::VALID_PARITY.include?(parity) case parity when SerialDriver::ODD parity = Win32::ODDPARITY when SerialDriver::EVEN parity = Win32::EVENPARITY when SerialDriver::NONE parity = Win32::NOPARITY end raise(ArgumentError, "Invalid stop bits: #{stop_bits}") unless [1, 2].include?(stop_bits) if stop_bits == 1 stop_bits = Win32::ONESTOPBIT else stop_bits = Win32::TWOSTOPBITS end @write_timeout = write_timeout @read_timeout = read_timeout @read_polling_period = read_polling_period @read_max_length = read_max_length # Open the Comm Port @handle = Win32.create_file(port_name, Win32::GENERIC_READ | Win32::GENERIC_WRITE, 0, Win32::NULL, Win32::OPEN_EXISTING, Win32::FILE_ATTRIBUTE_NORMAL) @mutex = Mutex.new # Configure the Comm Port - See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363214(v=vs.85).aspx dcb = Win32.get_comm_state(@handle) dcb.write('BaudRate', baud_rate) dcb.write('ByteSize', data_bits) dcb.write('Parity', parity) dcb.write('StopBits', stop_bits) if flow_control == :RTSCTS # Monitor CTS dcb.write('fOutxCtsFlow', 1) # 0x00 - RTS_CONTROL_DISABLE - Disables the RTS line when the device is opened and leaves it disabled. # 0x01 - RTS_CONTROL_ENABLE - Enables the RTS line when the device is opened and leaves it on. # 0x02 - RTS_CONTROL_HANDSHAKE - Enables RTS handshaking. The driver raises the RTS line when the "type-ahead" (input) buffer is less than one-half full and lowers the RTS line when the buffer is more than three-quarters full. If handshaking is enabled, it is an error for the application to adjust the line by using the EscapeCommFunction function. # 0x03 - RTS_CONTROL_TOGGLE - Specifies that the RTS line will be high if bytes are available for transmission. After all buffered bytes have been sent, the RTS line will be low. dcb.write('fRtsControl', 0x03) end Win32.set_comm_state(@handle, dcb) # Configure Timeouts, the WinAPI structure is COMMTIMEOUTS: # DWORD ReadIntervalTimeout; # DWORD ReadTotalTimeoutMultiplier; # DWORD ReadTotalTimeoutConstant; # DWORD WriteTotalTimeoutMultiplier; # DWORD WriteTotalTimeoutConstant; # 0xFFFFFFFF, 0, 0 specifies that the read operation is to return immediately # with the bytes that have already been received, even if no bytes have been received. # The WriteTotalTimeoutMultiplier is multiplied by the number of bytes to be written # and the WriteTotalTimeoutConstant is added to that total (both are in milliseconds). bits_per_symbol = data_bits + 1 # 1 start bit case stop_bits when Win32::ONESTOPBIT bits_per_symbol += 1 when Win32::TWOSTOPBITS bits_per_symbol += 2 end case parity when Win32::ODDPARITY, Win32::EVENPARITY bits_per_symbol += 1 end delay = (1000.0 / (baud_rate / bits_per_symbol.to_f)).ceil Win32.set_comm_timeouts(@handle, 0xFFFFFFFF, 0, 0, delay, 1000) end |
Instance Method Details
#close ⇒ Object
Disconnects the driver from the comm port
124 125 126 127 128 129 130 131 132 |
# File 'lib/openc3/io/win32_serial_driver.rb', line 124 def close if @handle # Close the Comm Port Win32.close_handle(@handle) @mutex.synchronize do @handle = nil end end end |
#closed? ⇒ Boolean
Returns Whether the serial port has been closed.
135 136 137 138 139 140 141 |
# File 'lib/openc3/io/win32_serial_driver.rb', line 135 def closed? if @handle false else true end end |
#read ⇒ String
Returns Binary data read from the serial port.
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/openc3/io/win32_serial_driver.rb', line 159 def read data = '' sleep_time = 0.0 loop do loop do buffer = nil @mutex.synchronize do break unless @handle buffer = Win32.read_file(@handle, @read_max_length - data.length) end break unless buffer data << buffer break if buffer.length <= 0 or data.length >= @read_max_length or !@handle end break if data.length > 0 or !@handle if @read_timeout and sleep_time >= @read_timeout raise Timeout::Error, "Read Timeout" end sleep(@read_polling_period) sleep_time += @read_polling_period end data end |
#read_nonblock ⇒ String
Returns Binary data read from the serial port.
189 190 191 192 193 194 195 196 197 |
# File 'lib/openc3/io/win32_serial_driver.rb', line 189 def read_nonblock data = '' loop do buffer = Win32.read_file(@handle, @read_max_length - data.length) data << buffer break if buffer.length <= 0 or data.length >= @read_max_length end data end |
#write(data) ⇒ Object
144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/openc3/io/win32_serial_driver.rb', line 144 def write(data) # Write the data time = Time.now.sys bytes_to_write = data.length while bytes_to_write > 0 bytes_written = Win32.write_file(@handle, data, data.length) raise "Error writing to comm port" if bytes_written <= 0 bytes_to_write -= bytes_written data = data[bytes_written..-1] raise Timeout::Error, "Write Timeout" if @write_timeout and (Time.now.sys - time > @write_timeout) and bytes_to_write > 0 end end |