LibSerialPort.jl – access serial ports
LibSerialPort — ModuleThe 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_ports — Functionlist_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_list — Functionget_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_metadata — Functionprint_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.open — Methodopen(portname::AbstractString, baudrate::Integer;
mode::SPMode, ndatabits::Integer,
parity::SPParity, nstopbits::Integer)Construct, configure and open a SerialPort object.
portnameis the name of the serial port to open. Typical port names available depend on the operating system. Some valid names are listed byget_port_list(), but there are can be others and aliases:- Linux:
"/dev/ttyS0","/dev/ttyUSB0","/dev/serial/by-id/..."
- Linux:
- macOS:
"/dev/cu.usbserial-0001","/dev/cu.Bluetooth-Incoming-Port"
- macOS:
- Windows:
"COM1","COM2","COM3"
- Windows:
baudrateis 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.modeselects in which direction of transmission access is requested and can take the values:SP_MODE_READ,SP_MODE_WRITE, andSP_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.
LibSerialPort.SerialPort — MethodSerialPort(portname::AbstractString)Constructs and returns a SerialPort object.
Base.open — Methodopen(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.close — Methodclose(sp::SerialPort)Close the serial port sp.
LibSerialPort.set_speed — Functionset_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_frame — Functionset_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.
ndatabitsis the number of data bits, which is8in the common "8N1" schemeparitycontrols the presence and value of a party bit and can take the valuesSP_PARITY_NONE(default),SP_PARITY_ODD,SP_PARITY_EVEN,SP_PARITY_MARKandSP_PARITY_SPACEnstopbitssets the number of stop bits, typically1(default) or2
LibSerialPort.set_flow_control — Functionset_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.
rtscontrols the output line Ready To Send (RTS) and can take the valuesSP_RTS_OFF(default),SP_RTS_ONandSP_RTS_FLOW_CONTROL.ctscontrols the input line Clear To Send (CTS) and can take the valuesSP_CTS_IGNORE(default) andSP_CTS_FLOW_CONTROLdtrcontrols the output line Data Terminal Ready (DTR) and can take the valuesSP_DTR_OFF(default),SP_DTR_ON, andSP_DTR_FLOW_CONTROLdsrcontrols the input line Data Set Ready (DSR) and can take the valuesSP_DSR_IGNORE(default) andSP_DSR_FLOW_CONTROLxonxoffcontrols 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, andSP_XONXOFF_INOUT
Base.isopen — Methodisopen(sp::SerialPort) -> BoolDetermine whether a SerialPort object is open.
Base.eof — Methodeof(sp::SerialPort) -> BoolReturn 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.seteof — Functionseteof(sp::SerialPort, state::Bool)Set the return value of eof(sp) to state.
LibSerialPort.get_port_settings — Functionget_port_settings(sp::SerialPort)Return port settings for sp as a dictionary.
LibSerialPort.print_port_settings — Functionprint_port_settings(sp::SerialPort)Print port settings for sp.
LibSerialPort.set_read_timeout — Functionset_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, '\n')
line2 = readuntil(sp, '\n')
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_timeout — Functionset_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_timeout — Functionclear_read_timeout(sp::SerialPort)Cancel any previous read timeout, such that blocking read operations will now wait without any time limit.
LibSerialPort.clear_write_timeout — Functionclear_write_timeout(sp::SerialPort)Cancel any previous write timeout, such that blocking write operations will block without any time limit.
LibSerialPort.Lib.sp_flush — Functionsp_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.
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).
LibSerialPort.Lib.sp_drain — Functionsp_drain(port::Port)
sp_drain(SerialPort::Port)Wait for buffered data to be transmitted.
LibSerialPort.Lib.sp_output_waiting — FunctionReturns the number of bytes in the output buffer.
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.read — Methodread(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 (see also readchomp).
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"Base.read! — Functionread!(stream::IO, array::AbstractArray)
read!(filename::AbstractString, array::AbstractArray)Read binary data from an I/O stream or file, filling in array.
Base.readbytes! — Functionreadbytes!(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.
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.
Base.readchomp — Functionreadchomp(x)Read the entirety of x as a string and remove a single trailing newline if there is one. Equivalent to chomp(read(x, String)).
Examples
julia> open("my_file.txt", "w") do io
write(io, "JuliaLang is a GitHub organization.\nIt has many members.\n");
end;
julia> readchomp("my_file.txt")
"JuliaLang is a GitHub organization.\nIt has many members."
julia> rm("my_file.txt");Base.readavailable — Functionreadavailable(stream)Read available buffered data from a stream. Actual I/O is performed only if no data has already been buffered. The result is a Vector{UInt8}.
The amount of data returned is implementation-dependent; for example it can depend on the internal choice of buffer size. Other functions such as read should generally be used instead.
Base.readline — Functionreadline(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")Base.readlines — Functionreadlines(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 Vector{String}:
"JuliaLang is a GitHub organization."
"It has many members."
julia> readlines("my_file.txt", keep=true)
2-element Vector{String}:
"JuliaLang is a GitHub organization.\n"
"It has many members.\n"
julia> rm("my_file.txt")Base.eachline — Functioneachline(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");Base.write — Functionwrite(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
42Merging 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))Base.print — Methodprint([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!"Additional read methods
Base.read — Methodread(sp::SerialPort)Return all incoming bytes currently available in the UART as a Vector{UInt8}.
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_read — Methodnonblocking_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.bytesavailable — Methodbytesavailable(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.ntoh — Functionntoh(x)Convert the endianness of a value from Network byte order (big-endian) to that used by the Host.
Base.hton — Functionhton(x)Convert the endianness of a value from that used by the Host to Network byte order (big-endian).
Base.ltoh — Functionltoh(x)Convert the endianness of a value from Little-endian to that used by the Host.
Base.htol — Functionhtol(x)Convert the endianness of a value from that used by the Host to Little-endian.
Base.stdout — ConstantstdoutGlobal variable referring to the standard out stream.
Base.string — Methodstring(xs...)Create a string from any values 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"