Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use native IO objects & support blocking IO #50

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
63 changes: 47 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

RubySerial is a simple Ruby gem for reading from and writing to serial ports.

Unlike other Ruby serial port implementations, it supports all of the most popular Ruby implementations (MRI, JRuby, & Rubinius) on the most popular operating systems (OSX, Linux, & Windows). And it does not require any native compilation thanks to using RubyFFI [https://github.com/ffi/ffi](https://github.com/ffi/ffi).
Unlike other Ruby serial port implementations, it supports all of the most popular Ruby implementations (MRI, JRuby, & Rubinius) on the most popular operating systems (OSX, Linux, & Windows). And it does not require any native compilation thanks to using RubyFFI [https://github.com/ffi/ffi](https://github.com/ffi/ffi). Note: Windows requires JRuby >= 9.2.8.0 to fix native IO issues.

The interface to RubySerial should be (mostly) compatible with other Ruby serialport gems, so you should be able to drop in the new gem, change the `require` and use it as a replacement. If not, please let us know so we can address any issues.
The interface to RubySerial should be compatible with other Ruby serialport gems, so you should be able to drop in the new gem, change the `require` and use it as a replacement. If not, please let us know so we can address any issues.

[![Build Status](https://travis-ci.org/hybridgroup/rubyserial.svg)](https://travis-ci.org/hybridgroup/rubyserial)
[![Build status](https://ci.appveyor.com/api/projects/status/946nlaqy4443vb99/branch/master?svg=true)](https://ci.appveyor.com/project/zankich/rubyserial/branch/master)
Expand All @@ -14,40 +14,71 @@ The interface to RubySerial should be (mostly) compatible with other Ruby serial

$ gem install rubyserial

## Usage
## Basic Usage

```ruby
require 'rubyserial'

# 0.6 API (nonblocking IO by default)
serialport = Serial.new '/dev/ttyACM0' # Defaults to 9600 baud, 8 data bits, and no parity
serialport = Serial.new '/dev/ttyACM0', 57600
serialport = Serial.new '/dev/ttyACM0', 19200, 8, :even
serialport = Serial.new '/dev/ttyACM0', 19200, :even, 8
serialport = Serial.new '/dev/ttyACM0', 19200, :even, 8, true # to enable blocking IO

# SerialPort gem compatible API (blocking & nonblocking IO)
serialport = SerialPort.new '/dev/ttyACM0' # Defaults to the existing system settings.
serialport = SerialPort.new '/dev/ttyACM0', 57600
serialport = SerialPort.new '/dev/ttyACM0', 19200, 8, :even # note the order of args is different

# open style syntax
SerialPort.open '/dev/ttyACM0', 19200, 8, :even do |serialport|
serialport.read(3) # blocking
serialport.read_nonblock(3) # nonblocking
serialport.readpartial(3) # nonblocking after blocking for first character
# ...
end

# change the settings later
five = SerialPort.open '/dev/ttyACM0' do |serialport|
serialport.baud = 9600
serialport.data_bits = 8
serialport.stop_bits = 1
serialport.parity = :none
serialport.hupcl = false
# ...
5
end
```
Both SerialPort and Serial are an IO object, so standard methods like read and write are available, but do note that Serial has some nonstandard read behavior by default. See the documentation for details

## Methods
## Classes

**write(data : String) -> Int**
There are 3 levels of API:

Returns the number of bytes written.
Emits a `RubySerial::Error` on error.
* High level: {SerialPort} and {Serial}
* Medium level: {SerialIO}
* Low level: {RubySerial::Builder.build}

**read(length : Int) -> String**
Most use cases will do fine with the high level API, as those, particularly {SerialPort}, are standard IO objects. {Serial} is also an IO, but with the {Serial#read} and {Serial#getbyte} methods having non-standard return conditions (`""` if no data exists, otherwise `readpartial` for the former, and nonblocking for the latter). For this reason, new code is suggested to use {SerialPort} as `read`/`readpartial`/`read_nonblocking` work as expected in all other IO objects.

Returns a string up to `length` long. It is not guaranteed to return the entire
length specified, and will return an empty string if no data is
available. Emits a `RubySerial::Error` on error.
The medium level API with {SerialIO} also returns an IO object, but allows you to provide your own SerialIO child class to instantiate instead.

**getbyte -> Fixnum or nil**
The low level API is not considered stable, and may change in minor releases.

Returns an 8 bit byte or nil if no data is available.
Emits a `RubySerial::Error` on error.
See the yard documentation for more details

**RubySerial::Error**

A wrapper error type that returns the underlying system error code and inherits from IOError.

## Running the tests

The test suite is written using rspec, just use the `rspec` command.
The test suite is written using rspec, just use the `rspec` command. There are 3 test files: SerialPort API compatibility `serialport_spec`, Serial API compatability `rubyserial_spec`, and the DTR & timeout correctness test suite `serial_arduino_spec`. The latter requires the `spec/arduino.ino` program flashed to an arduino, or a compatible program that the test can talk to. If you wish to test either of the latter, define the enviroment variable `RS_ARDUINO_PORT` to be the arduino serial port. If you wish to run `serialport_spec`, either the `RS_ARDUINO_PORT` or `RS_TEST_PORT` must be defined.

```txt
$ export RS_ARDUINO_PORT=/dev/ttyUSB0
$ rspec
```

### Test dependencies

Expand Down
Loading