fix serial
This commit is contained in:
@ -1,68 +1,169 @@
|
||||
/*
|
||||
Goserial is a simple go package to allow you to read and write from
|
||||
the serial port as a stream of bytes.
|
||||
|
||||
It aims to have the same API on all platforms, including windows. As
|
||||
an added bonus, the windows package does not use cgo, so you can cross
|
||||
compile for windows from another platform. Unfortunately goinstall
|
||||
does not currently let you cross compile so you will have to do it
|
||||
manually:
|
||||
|
||||
GOOS=windows make clean install
|
||||
|
||||
Currently there is very little in the way of configurability. You can
|
||||
set the baud rate. Then you can Read(), Write(), or Close() the
|
||||
connection. Read() will block until at least one byte is returned.
|
||||
Write is the same. There is currently no exposed way to set the
|
||||
timeouts, though patches are welcome.
|
||||
|
||||
Currently all ports are opened with 8 data bits, 1 stop bit, no
|
||||
parity, no hardware flow control, and no software flow control. This
|
||||
works fine for many real devices and many faux serial devices
|
||||
including usb-to-serial converters and bluetooth serial ports.
|
||||
|
||||
You may Read() and Write() simulantiously on the same connection (from
|
||||
different goroutines).
|
||||
|
||||
Example usage:
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/tarm/serial"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
c := &serial.Config{Name: "COM5", Baud: 115200}
|
||||
s, err := serial.OpenPort(c)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
n, err := s.Write([]byte("test"))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
buf := make([]byte, 128)
|
||||
n, err = s.Read(buf)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Print("%q", buf[:n])
|
||||
}
|
||||
*/
|
||||
package serial
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"errors"
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
goserial "github.com/tarm/serial"
|
||||
const DefaultSize = 8 // Default value for Config.Size
|
||||
|
||||
type StopBits byte
|
||||
type Parity byte
|
||||
|
||||
const (
|
||||
Stop1 StopBits = 1
|
||||
Stop1Half StopBits = 15
|
||||
Stop2 StopBits = 2
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultPort = "COM1"
|
||||
DefaultBaudRate = 9600
|
||||
ParityNone Parity = 'N'
|
||||
ParityOdd Parity = 'O'
|
||||
ParityEven Parity = 'E'
|
||||
ParityMark Parity = 'M' // parity bit is always 1
|
||||
ParitySpace Parity = 'S' // parity bit is always 0
|
||||
)
|
||||
|
||||
// COM1,9600,odd
|
||||
func ParseConfigFromAddr(addr string) *goserial.Config {
|
||||
cfg := &goserial.Config{
|
||||
Name: DefaultPort,
|
||||
Baud: DefaultBaudRate,
|
||||
}
|
||||
ss := strings.Split(addr, ",")
|
||||
switch len(ss) {
|
||||
case 1:
|
||||
cfg.Name = ss[0]
|
||||
case 2:
|
||||
cfg.Name = ss[0]
|
||||
cfg.Baud, _ = strconv.Atoi(ss[1])
|
||||
case 3:
|
||||
cfg.Name = ss[0]
|
||||
cfg.Baud, _ = strconv.Atoi(ss[1])
|
||||
cfg.Parity = parseParity(ss[2])
|
||||
}
|
||||
return cfg
|
||||
// Config contains the information needed to open a serial port.
|
||||
//
|
||||
// Currently few options are implemented, but more may be added in the
|
||||
// future (patches welcome), so it is recommended that you create a
|
||||
// new config addressing the fields by name rather than by order.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// c0 := &serial.Config{Name: "COM45", Baud: 115200, ReadTimeout: time.Millisecond * 500}
|
||||
//
|
||||
// or
|
||||
//
|
||||
// c1 := new(serial.Config)
|
||||
// c1.Name = "/dev/tty.usbserial"
|
||||
// c1.Baud = 115200
|
||||
// c1.ReadTimeout = time.Millisecond * 500
|
||||
type Config struct {
|
||||
Name string
|
||||
Baud int
|
||||
ReadTimeout time.Duration // Total timeout
|
||||
|
||||
// Size is the number of data bits. If 0, DefaultSize is used.
|
||||
Size byte
|
||||
|
||||
// Parity is the bit to use and defaults to ParityNone (no parity bit).
|
||||
Parity Parity
|
||||
|
||||
// Number of stop bits to use. Default is 1 (1 stop bit).
|
||||
StopBits StopBits
|
||||
|
||||
// RTSFlowControl bool
|
||||
// DTRFlowControl bool
|
||||
// XONFlowControl bool
|
||||
|
||||
// CRLFTranslate bool
|
||||
}
|
||||
|
||||
func AddrFromConfig(cfg *goserial.Config) string {
|
||||
ss := []string{
|
||||
cfg.Name,
|
||||
strconv.Itoa(cfg.Baud),
|
||||
}
|
||||
// ErrBadSize is returned if Size is not supported.
|
||||
var ErrBadSize error = errors.New("unsupported serial data size")
|
||||
|
||||
switch cfg.Parity {
|
||||
case goserial.ParityEven:
|
||||
ss = append(ss, "even")
|
||||
case goserial.ParityOdd:
|
||||
ss = append(ss, "odd")
|
||||
case goserial.ParityMark:
|
||||
ss = append(ss, "mark")
|
||||
case goserial.ParitySpace:
|
||||
ss = append(ss, "space")
|
||||
// ErrBadStopBits is returned if the specified StopBits setting not supported.
|
||||
var ErrBadStopBits error = errors.New("unsupported stop bit setting")
|
||||
|
||||
// ErrBadParity is returned if the parity is not supported.
|
||||
var ErrBadParity error = errors.New("unsupported parity setting")
|
||||
|
||||
// OpenPort opens a serial port with the specified configuration
|
||||
func OpenPort(c *Config) (io.ReadWriteCloser, error) {
|
||||
size, par, stop := c.Size, c.Parity, c.StopBits
|
||||
if size == 0 {
|
||||
size = DefaultSize
|
||||
}
|
||||
return strings.Join(ss, ",")
|
||||
if par == 0 {
|
||||
par = ParityNone
|
||||
}
|
||||
if stop == 0 {
|
||||
stop = Stop1
|
||||
}
|
||||
return openPort(c.Name, c.Baud, size, par, stop, c.ReadTimeout)
|
||||
}
|
||||
|
||||
func parseParity(s string) goserial.Parity {
|
||||
switch strings.ToLower(s) {
|
||||
case "o", "odd":
|
||||
return goserial.ParityOdd
|
||||
case "e", "even":
|
||||
return goserial.ParityEven
|
||||
case "m", "mark":
|
||||
return goserial.ParityMark
|
||||
case "s", "space":
|
||||
return goserial.ParitySpace
|
||||
default:
|
||||
return goserial.ParityNone
|
||||
// Converts the timeout values for Linux / POSIX systems
|
||||
func posixTimeoutValues(readTimeout time.Duration) (vmin uint8, vtime uint8) {
|
||||
const MAXUINT8 = 1<<8 - 1 // 255
|
||||
// set blocking / non-blocking read
|
||||
var minBytesToRead uint8 = 1
|
||||
var readTimeoutInDeci int64
|
||||
if readTimeout > 0 {
|
||||
// EOF on zero read
|
||||
minBytesToRead = 0
|
||||
// convert timeout to deciseconds as expected by VTIME
|
||||
readTimeoutInDeci = (readTimeout.Nanoseconds() / 1e6 / 100)
|
||||
// capping the timeout
|
||||
if readTimeoutInDeci < 1 {
|
||||
// min possible timeout 1 Deciseconds (0.1s)
|
||||
readTimeoutInDeci = 1
|
||||
} else if readTimeoutInDeci > MAXUINT8 {
|
||||
// max possible timeout is 255 deciseconds (25.5s)
|
||||
readTimeoutInDeci = MAXUINT8
|
||||
}
|
||||
}
|
||||
return minBytesToRead, uint8(readTimeoutInDeci)
|
||||
}
|
||||
|
||||
// func SendBreak()
|
||||
|
||||
// func RegisterBreakHandler(func())
|
||||
|
Reference in New Issue
Block a user