LibSerialPort.jl – access serial ports

LibSerialPortModule

The LibSerialPort module provides access to serial ports (UARTs or USB/Bluetooth devices that emulate their operating-system interface) using the portable C library libserialport.

It defines the SerialPort type, which is returned by LibSerialPort.open. This is a subtype of Base.IO and can therefore be used like a file handle, using many of the same read, write, print, etc. methods defined for Base.IO.

Example

using LibSerialPort

list_ports()
ports = get_port_list()

sp = LibSerialPort.open("/dev/ttyUSB0", 115200)
set_flow_control(sp)
sp_flush(sp, SP_BUF_BOTH)
write(sp, "hello\n")
println(readline(sp))
close(sp)

Enumerating serial ports

LibSerialPort.list_portsFunction
list_ports([nports_guess::Integer])`

Print a list of currently visible ports, along with some basic info.

nports_guess provides the number of ports guessed. Its default is 64.

LibSerialPort.get_port_listFunction
get_port_list([nports_guess::Integer])

Return a vector of currently visible ports.

nports_guess provides the number of ports guessed. Its default is 64.

LibSerialPort.print_port_metadataFunction
print_port_metadata(sp::SerialPort; show_config::Bool = true)

Print info found for this port. Note: port should be open to obtain a valid FD/handle before accessing fields.

show_config is true by default and prints out the current port settings.

Opening and configuring ports

Base.openMethod
open(portname::AbstractString, baudrate::Integer;
     mode::SPMode, ndatabits::Integer,
     parity::SPParity, nstopbits::Integer)

Construct, configure and open a SerialPort object.

  • portname is the name of the serial port to open. Typical port names available depend on the operating system. Some valid names are listed by get_port_list(), but there are can be others and aliases:
    • Linux: "/dev/ttyS0", "/dev/ttyUSB0", "/dev/serial/by-id/..."
    • macOS: "/dev/cu.usbserial-0001", "/dev/cu.Bluetooth-Incoming-Port"
    • Windows: "COM1", "COM2","COM3"
  • baudrate is the data signalling rate, or the reciprocal duration of one data bit, in bits/s. The set of values supported depends on the UART hardware, but typically includes e.g. 9600, 19200 and 115200.
  • mode selects in which direction of transmission access is requested and can take the values: SP_MODE_READ, SP_MODE_WRITE, and SP_MODE_READ_WRITE (default).

The parameters ndatabits, parity and nstopbits have the same meaning as in set_frame and default to the common “8N1” frame format (8 data bits, no parity, one stop bit).

To set the flow-control method, use set_flow_control.

Base.openMethod
open(sp::SerialPort; mode::SPMode = SP_MODE_READ_WRITE)

Open the serial port sp.

mode selects in which direction of transmission access is requested and can take the values: SP_MODE_READ, SP_MODE_WRITE, and SP_MODE_READ_WRITE (default).

Base.closeMethod
close(sp::SerialPort)

Close the serial port sp.

LibSerialPort.set_speedFunction
set_speed(sp::SerialPort, baudrate::Integer)

Set the data signalling rate, or the reciprocal duration of one data bit, in bits/s. The set of values supported depends on the UART hardware, but typically includes e.g. 9600, 19200 and 115200.

Raise an ErrorException if bps is not a value supported by the driver or hardware.

LibSerialPort.set_frameFunction
set_frame(sp::SerialPort;
          ndatabits::Integer = 8,
          parity::SPParity   = SP_PARITY_NONE,
          nstopbits::Integer = 1)

Configure the data framing parameters. Defaults to the very common “8N1” scheme, which consists of a start bit followed by eight data bits, no parity bit, one stop bit.

for more details.

  • ndatabits is the number of data bits, which is 8 in the common "8N1" scheme

  • parity controls the presence and value of a party bit and can take the values SP_PARITY_NONE (default), SP_PARITY_ODD, SP_PARITY_EVEN, SP_PARITY_MARK and SP_PARITY_SPACE

  • nstopbits sets the number of stop bits, typically 1 (default) or 2

LibSerialPort.set_flow_controlFunction
set_flow_control(sp::SerialPort;
                 rts::SPrts = SP_RTS_OFF,
                 cts::SPcts = SP_CTS_IGNORE,
                 dtr::SPdtr = SP_DTR_OFF,
                 dst::SPdsr = SP_DSR_IGNORE,
                 xonxoff::SPXonXoff = SP_XONXOFF_DISABLED)`

Configure the flow-control lines and method. Many systems don't support all options. If an unsupported option is requested, the library will return SPERRSUPP.

  • rts controls the output line Ready To Send (RTS) and can take the values SP_RTS_OFF (default), SP_RTS_ON and SP_RTS_FLOW_CONTROL.

  • cts controls the input line Clear To Send (CTS) and can take the values SP_CTS_IGNORE (default) and SP_CTS_FLOW_CONTROL

  • dtr controls the output line Data Terminal Ready (DTR) and can take the values SP_DTR_OFF (default), SP_DTR_ON, and SP_DTR_FLOW_CONTROL

  • dsr controls the input line Data Set Ready (DSR) and can take the values SP_DSR_IGNORE (default) and SP_DSR_FLOW_CONTROL

  • xonxoff controls whether software flow control via the control bytes XOFF (pause transmission, 0x13, Ctrl-S) and XON (resume transmission, 0x11, Ctrl-Q) is active, and in which direction; it can take the values: SP_XONXOFF_DISABLED (default), SP_XONXOFF_IN, SP_XONXOFF_OUT, and SP_XONXOFF_INOUT

Base.isopenMethod
isopen(sp::SerialPort) -> Bool

Determine whether a SerialPort object is open.

Base.eofMethod
eof(sp::SerialPort) -> Bool

Return the “end-of-file” state (true or false). Since serial ports do not have any standard mechanism for signalling the end of a transmitted file, this is just a dummy function that returns whatever Boolean value eof was previously set with seteof(sp, eof). Returns false by default.

LibSerialPort.seteofFunction
seteof(sp::SerialPort, state::Bool)

Set the return value of eof(sp) to state.

LibSerialPort.set_read_timeoutFunction
set_read_timeout(sp::SerialPort, seconds::Real)

Set a read timeout limit of t > 0 seconds for the total (cumulative) time that subsequently called blocking read functions can wait before a Timeout exception is thrown.

Example

sp=LibSerialPort.open("/dev/ttyUSB0", 115200)
# wait until either two lines have been received
# or 10 seconds have elapsed
set_read_timeout(sp, 10)
try
    line1 = readuntil(sp, '
')
    line2 = readuntil(sp, '
')
catch e
    if isa(e, LibSerialPort.Timeout)
        println("Too late!")
    else
        rethrow()
    end
end
clear_read_timeout(sp)

See also: clear_read_timeout, set_write_timeout

LibSerialPort.set_write_timeoutFunction
set_write_timeout(sp::SerialPort, seconds::Real)

Set a write timeout limit of t > 0 seconds for the total (cumulative) time that subsequently called blocking read functions can wait before a Timeout exception is thrown.

Example

sp=LibSerialPort.open("/dev/ttyUSB0", 300)
# wait until either 4000 periods have been
# passed on to the serial-port driver or
# 10 seconds have elapsed
set_write_timeout(sp, 10)
try
    for i=1:50 ; write(sp, '.' ^ 80); end
catch e
    if isa(e, LibSerialPort.Timeout)
        println("This took too long!")
    else
        rethrow()
    end
end
clear_write_timeout(sp)

See also: clear_write_timeout, set_read_timeout

LibSerialPort.clear_read_timeoutFunction
clear_read_timeout(sp::SerialPort)

Cancel any previous read timeout, such that blocking read operations will now wait without any time limit.

LibSerialPort.clear_write_timeoutFunction
clear_write_timeout(sp::SerialPort)

Cancel any previous write timeout, such that blocking write operations will block without any time limit.

LibSerialPort.Lib.sp_flushFunction
sp_flush(port::Port, buffers::SPBuffer)
sp_flush(port::SerialPort, buffers::SPBuffer)

Discard data in the selected serial-port buffer(s).

Supported values for buffers: SP_BUF_INPUT, SP_BUF_OUTPUT, SP_BUF_BOTH

Returns SP_OK upon success or raises an ErrorException otherwise.

Note

Not to be confused with Base.flush, which writes out buffered data rather than discarding it: the underlying libserialport C library unfortunately uses the verb “flush” differently from its normal meaning for Base.IO (sp_drain provides the latter in this library).

Read and write methods from Base

Many of the read/write methods defined in Base that operate on an object of type IO can also be used with objects of type SerialPort. Therefore we repeat the documentation of some of these here. (Note that some of the following docstings also refer to other methods that are not applicable to SerialPort.)

Base.readMethod
read(io::IO, T)

Read a single value of type T from io, in canonical binary representation.

Note that Julia does not convert the endianness for you. Use ntoh or ltoh for this purpose.

read(io::IO, String)

Read the entirety of io, as a String.

Examples

julia> io = IOBuffer("JuliaLang is a GitHub organization");

julia> read(io, Char)
'J': ASCII/Unicode U+004A (category Lu: Letter, uppercase)

julia> io = IOBuffer("JuliaLang is a GitHub organization");

julia> read(io, String)
"JuliaLang is a GitHub organization"
source
Base.read!Function
read!(stream::IO, array::AbstractArray)
read!(filename::AbstractString, array::AbstractArray)

Read binary data from an I/O stream or file, filling in array.

source
Base.readbytes!Function
readbytes!(stream::IO, b::AbstractVector{UInt8}, nb=length(b))

Read at most nb bytes from stream into b, returning the number of bytes read. The size of b will be increased if needed (i.e. if nb is greater than length(b) and enough bytes could be read), but it will never be decreased.

source
readbytes!(stream::IOStream, b::AbstractVector{UInt8}, nb=length(b); all::Bool=true)

Read at most nb bytes from stream into b, returning the number of bytes read. The size of b will be increased if needed (i.e. if nb is greater than length(b) and enough bytes could be read), but it will never be decreased.

If all is true (the default), this function will block repeatedly trying to read all requested bytes, until an error or end-of-file occurs. If all is false, at most one read call is performed, and the amount of data returned is device-dependent. Note that not all stream types support the all option.

source
Base.readavailableFunction
readavailable(stream)

Read all available data on the stream, blocking the task only if no data is available. The result is a Vector{UInt8}.

source
Base.readlineFunction
readline(io::IO=stdin; keep::Bool=false)
readline(filename::AbstractString; keep::Bool=false)

Read a single line of text from the given I/O stream or file (defaults to stdin). When reading from a file, the text is assumed to be encoded in UTF-8. Lines in the input end with '\n' or "\r\n" or the end of an input stream. When keep is false (as it is by default), these trailing newline characters are removed from the line before it is returned. When keep is true, they are returned as part of the line.

Examples

julia> open("my_file.txt", "w") do io
           write(io, "JuliaLang is a GitHub organization.\nIt has many members.\n");
       end
57

julia> readline("my_file.txt")
"JuliaLang is a GitHub organization."

julia> readline("my_file.txt", keep=true)
"JuliaLang is a GitHub organization.\n"

julia> rm("my_file.txt")
source
Base.readlinesFunction
readlines(io::IO=stdin; keep::Bool=false)
readlines(filename::AbstractString; keep::Bool=false)

Read all lines of an I/O stream or a file as a vector of strings. Behavior is equivalent to saving the result of reading readline repeatedly with the same arguments and saving the resulting lines as a vector of strings.

Examples

julia> open("my_file.txt", "w") do io
           write(io, "JuliaLang is a GitHub organization.\nIt has many members.\n");
       end
57

julia> readlines("my_file.txt")
2-element Array{String,1}:
 "JuliaLang is a GitHub organization."
 "It has many members."

julia> readlines("my_file.txt", keep=true)
2-element Array{String,1}:
 "JuliaLang is a GitHub organization.\n"
 "It has many members.\n"

julia> rm("my_file.txt")
source
Base.eachlineFunction
eachline(io::IO=stdin; keep::Bool=false)
eachline(filename::AbstractString; keep::Bool=false)

Create an iterable EachLine object that will yield each line from an I/O stream or a file. Iteration calls readline on the stream argument repeatedly with keep passed through, determining whether trailing end-of-line characters are retained. When called with a file name, the file is opened once at the beginning of iteration and closed at the end. If iteration is interrupted, the file will be closed when the EachLine object is garbage collected.

Examples

julia> open("my_file.txt", "w") do io
           write(io, "JuliaLang is a GitHub organization.\n It has many members.\n");
       end;

julia> for line in eachline("my_file.txt")
           print(line)
       end
JuliaLang is a GitHub organization. It has many members.

julia> rm("my_file.txt");
source
Base.writeFunction
write(io::IO, x)
write(filename::AbstractString, x)

Write the canonical binary representation of a value to the given I/O stream or file. Return the number of bytes written into the stream. See also print to write a text representation (with an encoding that may depend upon io).

The endianness of the written value depends on the endianness of the host system. Convert to/from a fixed endianness when writing/reading (e.g. using htol and ltoh) to get results that are consistent across platforms.

You can write multiple values with the same write call. i.e. the following are equivalent:

write(io, x, y...)
write(io, x) + write(io, y...)

Examples

Consistent serialization:

julia> fname = tempname(); # random temporary filename

julia> open(fname,"w") do f
           # Make sure we write 64bit integer in little-endian byte order
           write(f,htol(Int64(42)))
       end
8

julia> open(fname,"r") do f
           # Convert back to host byte order and host integer type
           Int(ltoh(read(f,Int64)))
       end
42

Merging write calls:

julia> io = IOBuffer();

julia> write(io, "JuliaLang is a GitHub organization.", " It has many members.")
56

julia> String(take!(io))
"JuliaLang is a GitHub organization. It has many members."

julia> write(io, "Sometimes those members") + write(io, " write documentation.")
44

julia> String(take!(io))
"Sometimes those members write documentation."

User-defined plain-data types without write methods can be written when wrapped in a Ref:

julia> struct MyStruct; x::Float64; end

julia> io = IOBuffer()
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)

julia> write(io, Ref(MyStruct(42.0)))
8

julia> seekstart(io); read!(io, Ref(MyStruct(NaN)))
Base.RefValue{MyStruct}(MyStruct(42.0))
source
Base.printMethod
print([io::IO], xs...)

Write to io (or to the default output stream stdout if io is not given) a canonical (un-decorated) text representation. The representation used by print includes minimal formatting and tries to avoid Julia-specific details.

print falls back to calling show, so most types should just define show. Define print if your type has a separate "plain" representation. For example, show displays strings with quotes, and print displays strings without quotes.

string returns the output of print as a string.

Examples

julia> print("Hello World!")
Hello World!
julia> io = IOBuffer();

julia> print(io, "Hello", ' ', :World!)

julia> String(take!(io))
"Hello World!"
source

Additional read methods

Base.readMethod
read(sp::SerialPort)

Return all incoming bytes currently available in the UART as a Vector{UInt8}.

Note

Julia's Base module defines read(s::IO, nb::Integer = typemax(Int)). This method overrides the default value nb to bytesavailable(sp), which is useful for this context.

LibSerialPort.nonblocking_readMethod
nonblocking_read(sp::SerialPort)

Read everything from the specified serial ports sp input buffer, one byte at a time, until it is empty. Returns a String.

Base.bytesavailableMethod
bytesavailable(sp::SerialPort)

Return the number of bytes waiting in the input buffer.

Other references

The following are listed here only because they are referenced above:

Base.ntohFunction
ntoh(x)

Convert the endianness of a value from Network byte order (big-endian) to that used by the Host.

source
Base.htonFunction
hton(x)

Convert the endianness of a value from that used by the Host to Network byte order (big-endian).

source
Base.ltohFunction
ltoh(x)

Convert the endianness of a value from Little-endian to that used by the Host.

source
Base.htolFunction
htol(x)

Convert the endianness of a value from that used by the Host to Little-endian.

source
Base.stdoutConstant
stdout

Global variable referring to the standard out stream.

source
Base.stringMethod
string(xs...)

Create a string from any values, except nothing, using the print function.

string should usually not be defined directly. Instead, define a method print(io::IO, x::MyType). If string(x) for a certain type needs to be highly efficient, then it may make sense to add a method to string and define print(io::IO, x::MyType) = print(io, string(x)) to ensure the functions are consistent.

Examples

julia> string("a", 1, true)
"a1true"
source