Skip to content

Commit

Permalink
Merge commit 'tajtiattila@48c5ab6fe68'
Browse files Browse the repository at this point in the history
This is discussed in these PRs:
#34
#38
  • Loading branch information
Tarmigan Casebolt committed Jan 31, 2016
2 parents edb6653 + 48c5ab6 commit a53c419
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 19 deletions.
2 changes: 2 additions & 0 deletions basic_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// +build linux

package serial

import (
Expand Down
52 changes: 48 additions & 4 deletions serial.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,29 @@ Example usage:
package serial

import (
"errors"
"time"
)

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 (
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
)

// Config contains the information needed to open a serial port.
//
// Currently few options are implemented, but more may be added in the
Expand All @@ -79,9 +99,14 @@ type Config struct {
Baud int
ReadTimeout time.Duration // Total timeout

// Size int // 0 get translated to 8
// Parity SomeNewTypeToGetCorrectDefaultOf_None
// StopBits SomeNewTypeToGetCorrectDefaultOf_1
// 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
Expand All @@ -90,9 +115,28 @@ type Config struct {
// CRLFTranslate bool
}

// ErrBadSize is returned if Size is not supported.
var ErrBadSize error = errors.New("unsupported serial data size")

// 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) (*Port, error) {
return openPort(c.Name, c.Baud, c.ReadTimeout)
size, par, stop := c.Size, c.Parity, c.StopBits
if size == 0 {
size = DefaultSize
}
if par == 0 {
par = ParityNone
}
if stop == 0 {
stop = Stop1
}
return openPort(c.Name, c.Baud, size, par, stop, c.ReadTimeout)
}

// Converts the timeout values for Linux / POSIX systems
Expand Down
40 changes: 38 additions & 2 deletions serial_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"unsafe"
)

func openPort(name string, baud int, readTimeout time.Duration) (p *Port, err error) {
func openPort(name string, baud int, databits byte, parity Parity, stopbits StopBits, readTimeout time.Duration) (p *Port, err error) {
var bauds = map[int]uint32{
50: syscall.B50,
75: syscall.B75,
Expand Down Expand Up @@ -60,11 +60,47 @@ func openPort(name string, baud int, readTimeout time.Duration) (p *Port, err er
}
}()

// Base settings
cflagToUse := syscall.CREAD | syscall.CLOCAL | rate
switch databits {
case 5:
cflagToUse |= syscall.CS5
case 6:
cflagToUse |= syscall.CS6
case 7:
cflagToUse |= syscall.CS7
case 8:
cflagToUse |= syscall.CS8
default:
return nil, ErrBadSize
}
// Stop bits settings
switch stopbits {
case Stop1:
// default is 1 stop bit
case Stop2:
cflagToUse |= syscall.CSTOPB
default:
// Don't know how to set 1.5
return nil, ErrBadStopBits
}
// Parity settings
switch parity {
case ParityNone:
// default is no parity
case ParityOdd:
cflagToUse |= syscall.PARENB
cflagToUse |= syscall.PARODD
case ParityEven:
cflagToUse |= syscall.PARENB
default:
return nil, ErrBadParity
}
fd := f.Fd()
vmin, vtime := posixTimeoutValues(readTimeout)
t := syscall.Termios{
Iflag: syscall.IGNPAR,
Cflag: syscall.CS8 | syscall.CREAD | syscall.CLOCAL | rate,
Cflag: cflagToUse,
Cc: [32]uint8{syscall.VMIN: vmin, syscall.VTIME: vtime},
Ispeed: rate,
Ospeed: rate,
Expand Down
39 changes: 36 additions & 3 deletions serial_posix.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
//"unsafe"
)

func openPort(name string, baud int, readTimeout time.Duration) (p *Port, err error) {
func openPort(name string, baud int, databits byte, parity Parity, stopbits StopBits, readTimeout time.Duration) (p *Port, err error) {
f, err := os.OpenFile(name, syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_NONBLOCK, 0666)
if err != nil {
return
Expand Down Expand Up @@ -72,8 +72,41 @@ func openPort(name string, baud int, readTimeout time.Duration) (p *Port, err er

// Select local mode, turn off parity, set to 8 bits
st.c_cflag &= ^C.tcflag_t(C.CSIZE | C.PARENB)
st.c_cflag |= (C.CLOCAL | C.CREAD | C.CS8)

st.c_cflag |= (C.CLOCAL | C.CREAD)
// databits
switch databits {
case 5:
st.c_cflag |= C.CS5
case 6:
st.c_cflag |= C.CS6
case 7:
st.c_cflag |= C.CS7
case 8:
st.c_cflag |= C.CS8
default:
return nil, ErrBadSize
}
// Parity settings
switch parity {
case ParityNone:
// default is no parity
case ParityOdd:
st.c_cflag |= C.PARENB
st.c_cflag |= C.PARODD
case ParityEven:
st.c_cflag |= C.PARENB
default:
return nil, ErrBadParity
}
// Stop bits settings
switch stopbits {
case Stop1:
// as is, default is 1 bit
case Stop2:
st.c_cflag |= C.CSTOPB
default:
return nil, ErrBadStopBits
}
// Select raw mode
st.c_lflag &= ^C.tcflag_t(C.ICANON | C.ECHO | C.ECHOE | C.ISIG)
st.c_oflag &= ^C.tcflag_t(C.OPOST)
Expand Down
47 changes: 37 additions & 10 deletions serial_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type structTimeouts struct {
WriteTotalTimeoutConstant uint32
}

func openPort(name string, baud int, readTimeout time.Duration) (p *Port, err error) {
func openPort(name string, baud int, databits byte, parity Parity, stopbits StopBits, readTimeout time.Duration) (p *Port, err error) {
if len(name) > 0 && name[0] != '\\' {
name = "\\\\.\\" + name
}
Expand All @@ -59,26 +59,26 @@ func openPort(name string, baud int, readTimeout time.Duration) (p *Port, err er
}
}()

if err = setCommState(h, baud); err != nil {
return
if err = setCommState(h, baud, databits, parity, stopbits); err != nil {
return nil, err
}
if err = setupComm(h, 64, 64); err != nil {
return
return nil, err
}
if err = setCommTimeouts(h, readTimeout); err != nil {
return
return nil, err
}
if err = setCommMask(h); err != nil {
return
return nil, err
}

ro, err := newOverlapped()
if err != nil {
return
return nil, err
}
wo, err := newOverlapped()
if err != nil {
return
return nil, err
}
port := new(Port)
port.f = f
Expand Down Expand Up @@ -171,15 +171,42 @@ func getProcAddr(lib syscall.Handle, name string) uintptr {
return addr
}

func setCommState(h syscall.Handle, baud int) error {
func setCommState(h syscall.Handle, baud int, databits byte, parity Parity, stopbits StopBits) error {
var params structDCB
params.DCBlength = uint32(unsafe.Sizeof(params))

params.flags[0] = 0x01 // fBinary
params.flags[0] |= 0x10 // Assert DSR

params.BaudRate = uint32(baud)
params.ByteSize = 8

params.ByteSize = databits

switch parity {
case ParityNone:
params.Parity = 0
case ParityOdd:
params.Parity = 1
case ParityEven:
params.Parity = 2
case ParityMark:
params.Parity = 3
case ParitySpace:
params.Parity = 4
default:
return ErrBadParity
}

switch stopbits {
case Stop1:
params.StopBits = 0
case Stop1Half:
params.StopBits = 1
case Stop2:
params.StopBits = 2
default:
return ErrBadStopBits
}

r, _, err := syscall.Syscall(nSetCommState, 2, uintptr(h), uintptr(unsafe.Pointer(&params)), 0)
if r == 0 {
Expand Down

0 comments on commit a53c419

Please sign in to comment.