Back to godoc.org
github.com/desertbit/serial

Package serial

v1.0.0
Latest Go to latest
Published: Aug 23, 2019 | License: BSD-3-Clause | Module: github.com/desertbit/serial

Overview

Package serial is a cross-platform serial library for the go language.

import github.com/desertbit/serial

It is possible to get the list of available serial ports with the GetPortsList function:

ports, err := serial.GetPortsList()
if err != nil {
	log.Fatal(err)
}
if len(ports) == 0 {
	log.Fatal("No serial ports found!")
}
for _, port := range ports {
	fmt.Printf("Found port: %v\n", port)
}

The serial port can be opened with the Open function:

port, err := serial.Open("/dev/ttyUSB0", serial.WithBaudrate(115200))
if err != nil {
	log.Fatal(err)
}

The Open function can accept options that specifies the configuration options for the serial port. If not specified the default options are 9600_N81, in the example above only the speed is changed so the port is opened using 115200_N81. The following snippets shows how to declare a configuration for 57600_E71:

serial.Open("/dev/ttyUSB0",
	serial.WithBaudrate(57600),
	serial.WithParity(serial.EvenParity),
	serial.WithDataBits(7),
	serial.WithStopBits(serial.OneStopBit),
)

The configuration can be changed at any time with the Reconfigure() function:

if err := port.Reconfigure(
	serial.WithBaudrate(57600),
	serial.WithParity(serial.EvenParity),
); err != nil {
	log.Fatal(err)
}

The port object implements the io.ReadWriteCloser interface, so we can use the usual Read, Write and Close functions to send and receive data from the serial port:

n, err := port.Write([]byte("10,20,30\n\r"))
if err != nil {
	log.Fatal(err)
}
fmt.Printf("Sent %v bytes\n", n)

buff := make([]byte, 100)
for {
	n, err := port.Read(buff)
	if err != nil {
		log.Fatal(err)
		break
	}
	if n == 0 {
		fmt.Println("\nEOF")
		break
	}
	fmt.Printf("%v", string(buff[:n]))
}

If a port is a virtual USB-CDC serial port (for example an USB-to-RS232 cable or a microcontroller development board) is possible to retrieve the USB metadata, like VID/PID or USB Serial Number, with the GetDetailedPortsList function in the enumerator package:

import "github.com/desertbit/serial/enumerator"

ports, err := enumerator.GetDetailedPortsList()
if err != nil {
	log.Fatal(err)
}
if len(ports) == 0 {
	fmt.Println("No serial ports found!")
	return
}
for _, port := range ports {
	fmt.Printf("Found port: %s\n", port.Name)
	if port.IsUSB {
		fmt.Printf("   USB ID     %s:%s\n", port.VID, port.PID)
		fmt.Printf("   USB serial %s\n", port.SerialNumber)
	}
}

for details on USB port enumeration see the documentation of the specific package.

This library tries to avoid the use of the "C" package (and consequently the need of cgo) to simplify cross compiling. Unfortunately the USB enumeration package for darwin (MacOSX) requires cgo to access the IOKit framework. This means that if you need USB enumeration on darwin you're forced to use cgo.

Example (SendAndReceive)

This example prints the list of serial ports and use the first one to send a string "10,20,30" and prints the response on the screen.

Code:

ports, err := serial.GetPortsList()
if err != nil {
	log.Fatal(err)
}
if len(ports) == 0 {
	log.Fatal("No serial ports found!")
}

for _, port := range ports {
	fmt.Printf("Found port: %v\n", port)
}

port, err := serial.Open(ports[0],
	serial.WithBaudrate(9600),
	serial.WithDataBits(8),
	serial.WithParity(serial.NoParity),
	serial.WithStopBits(serial.OneStopBit),
	serial.WithReadTimeout(1000),
	serial.WithWriteTimeout(1000),
)
if err != nil {
	log.Fatal(err)
}

n, err := port.Write([]byte("10,20,30\n\r"))
if err != nil {
	log.Fatal(err)
}
fmt.Printf("Sent %v bytes\n", n)

buff := make([]byte, 100)
for {

	n, err := port.Read(buff)
	if err != nil {
		log.Fatal(err)
		break
	}
	if n == 0 {
		fmt.Println("\nEOF")
		break
	}
	fmt.Printf("%v", string(buff[:n]))
}

Index

Examples

Package Files

Constants

const (
	// NoParity disable parity control (default)
	NoParity Parity = iota
	// OddParity enable odd-parity check
	OddParity
	// EvenParity enable even-parity check
	EvenParity
	// MarkParity enable mark-parity (always 1) check
	MarkParity
	// SpaceParity enable space-parity (always 0) check
	SpaceParity

	// OneStopBit sets 1 stop bit (default)
	OneStopBit StopBits = iota
	// OnePointFiveStopBits sets 1.5 stop bits
	OnePointFiveStopBits
	// TwoStopBits sets 2 stop bits
	TwoStopBits
)
const FIONREAD = 0x541B

func GetPortsList

func GetPortsList() ([]string, error)
Example

Code:

ports, err := serial.GetPortsList()
if err != nil {
	log.Fatal(err)
}
if len(ports) == 0 {
	fmt.Println("No serial ports found!")
} else {
	for _, port := range ports {
		fmt.Printf("Found port: %v\n", port)
	}
}

type ModemStatusBits

type ModemStatusBits struct {
	CTS bool // ClearToSend status
	DSR bool // DataSetReady status
	RI  bool // RingIndicator status
	DCD bool // DataCarrierDetect status
}

ModemStatusBits contains all the modem status bits for a serial port (CTS, DSR, etc...). It can be retrieved with the Port.GetModemStatusBits() method.

type Option

type Option func(p *Port)

func WithBaudrate

func WithBaudrate(o int) Option

func WithDataBits

func WithDataBits(o int) Option

func WithHUPCL

func WithHUPCL(o bool) Option

func WithParity

func WithParity(o Parity) Option

func WithReadTimeout

func WithReadTimeout(o int) Option

func WithStopBits

func WithStopBits(o StopBits) Option

func WithWriteTimeout

func WithWriteTimeout(o int) Option

type Parity

type Parity int

Parity describes a serial port parity setting

type Port

type Port struct {
	// contains filtered or unexported fields
}

Port is the interface for a serial Port

func Open

func Open(name string, opts ...Option) (*Port, error)

func (*Port) Close

func (p *Port) Close() error

func (*Port) GetModemStatusBits

func (p *Port) GetModemStatusBits() (*ModemStatusBits, error)
Example

Code:

port, err := serial.Open("/dev/ttyACM1",
	serial.WithBaudrate(9600),
	serial.WithDataBits(8),
	serial.WithParity(serial.NoParity),
	serial.WithStopBits(serial.OneStopBit),
	serial.WithReadTimeout(1000),
	serial.WithWriteTimeout(1000),
)
if err != nil {
	log.Fatal(err)
}
defer port.Close()

count := 0
for count < 25 {
	status, err := port.GetModemStatusBits()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Status: %+v\n", status)

	time.Sleep(time.Second)
	count++
	if count == 5 {
		err := port.SetDTR(false)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println("Set DTR OFF")
	}
	if count == 10 {
		err := port.SetDTR(true)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println("Set DTR ON")
	}
	if count == 15 {
		err := port.SetRTS(false)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println("Set RTS OFF")
	}
	if count == 20 {
		err := port.SetRTS(true)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println("Set RTS ON")
	}
}

func (*Port) Read

func (p *Port) Read(b []byte) (int, error)

func (*Port) ReadyToRead

func (p *Port) ReadyToRead() (uint32, error)

func (*Port) Reconfigure

func (p *Port) Reconfigure(opts ...Option) error
Example

Code:

port, err := serial.Open("/dev/ttyACM0")
if err != nil {
	log.Fatal(err)
}
if err := port.Reconfigure(
	serial.WithBaudrate(9600),
	serial.WithDataBits(8),
	serial.WithParity(serial.NoParity),
	serial.WithStopBits(serial.OneStopBit),
	serial.WithReadTimeout(1000),
	serial.WithWriteTimeout(1000),
); err != nil {
	log.Fatal(err)
}
fmt.Println("Port set to 9600 N81")

func (*Port) ResetInputBuffer

func (p *Port) ResetInputBuffer() error

func (*Port) ResetOutputBuffer

func (p *Port) ResetOutputBuffer() error

func (*Port) SetDTR

func (p *Port) SetDTR(dtr bool) error

func (*Port) SetFirstByteReadTimeout

func (p *Port) SetFirstByteReadTimeout(t uint32) error

func (*Port) SetRTS

func (p *Port) SetRTS(rts bool) error

func (*Port) SetReadTimeout

func (p *Port) SetReadTimeout(t int) error

func (*Port) SetReadTimeoutEx

func (p *Port) SetReadTimeoutEx(t, i uint32) error

func (*Port) SetWriteTimeout

func (p *Port) SetWriteTimeout(t int) error

func (*Port) String

func (p *Port) String() string

func (*Port) Write

func (p *Port) Write(b []byte) (int, error)

type PortError

type PortError struct {
	// contains filtered or unexported fields
}

PortError is a platform independent error type for serial ports

func (PortError) Code

func (e PortError) Code() PortErrorCode

Code returns an identifier for the kind of error occurred

func (PortError) EncodedErrorString

func (e PortError) EncodedErrorString() string

EncodedErrorString returns a string explaining the error code

func (PortError) Error

func (e PortError) Error() string

Error returns the complete error code with details on the cause of the error

type PortErrorCode

type PortErrorCode int

PortErrorCode is a code to easily identify the type of error

const (
	// PortBusy the serial port is already in used by another process
	PortBusy PortErrorCode = iota
	// PortNotFound the requested port doesn't exist
	PortNotFound
	// InvalidSerialPort the requested port is not a serial port
	InvalidSerialPort
	// PermissionDenied the user doesn't have enough priviledges
	PermissionDenied
	// InvalidSpeed the requested speed is not valid or not supported
	InvalidSpeed
	// InvalidDataBits the number of data bits is not valid or not supported
	InvalidDataBits
	// InvalidParity the selected parity is not valid or not supported
	InvalidParity
	// InvalidStopBits the selected number of stop bits is not valid or not supported
	InvalidStopBits
	// Invalid timeout value passed
	InvalidTimeoutValue
	// ErrorEnumeratingPorts an error occurred while listing serial port
	ErrorEnumeratingPorts
	// PortClosed the port has been closed while the operation is in progress
	PortClosed
	// FunctionNotImplemented the requested function is not implemented
	FunctionNotImplemented
	// Operating system function error
	OsError
	// Port write failed
	WriteFailed
	// Port read failed
	ReadFailed
)

type StopBits

type StopBits int

StopBits describe a serial port stop bits setting

Documentation was rendered with GOOS=linux and GOARCH=amd64.

Jump to identifier

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to identifier