Skip to content

Commit

Permalink
Merge of RS485
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreRenaud committed Dec 8, 2023
1 parent 8a31fcb commit e1a84d8
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 0 deletions.
29 changes: 29 additions & 0 deletions serial.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ type Mode struct {
Parity Parity // Parity (see Parity type for more info)
StopBits StopBits // Stop bits (see StopBits type for more info)
InitialStatusBits *ModemOutputBits // Initial output modem bits status (if nil defaults to DTR=true and RTS=true)
RS485 RS485Config // RS485 configuration
}

// Parity describes a serial port parity setting
Expand Down Expand Up @@ -131,6 +132,22 @@ const (
TwoStopBits
)

// RS485Config -- platform independent RS485 config. Thie structure is ignored unless Enable is true.
type RS485Config struct {
// Enable RS485 support
Enabled bool
// Delay RTS prior to send
DelayRtsBeforeSend time.Duration
// Delay RTS after send
DelayRtsAfterSend time.Duration
// Set RTS high during send
RtsHighDuringSend bool
// Set RTS high after send
RtsHighAfterSend bool
// Rx during Tx
RxDuringTx bool
}

// PortError is a platform independent error type for serial ports
type PortError struct {
code PortErrorCode
Expand Down Expand Up @@ -165,6 +182,12 @@ const (
PortClosed
// FunctionNotImplemented the requested function is not implemented
FunctionNotImplemented
// ReadFailed indicates the read failed
ReadFailed
// ConfigureRS485Error indicates an error configuring RS485 on the platform
ConfigureRS485Error
// NoPlatformSupportForRS485 indicates no platform support for RS485
NoPlatformSupportForRS485
)

// EncodedErrorString returns a string explaining the error code
Expand Down Expand Up @@ -194,6 +217,12 @@ func (e PortError) EncodedErrorString() string {
return "Port has been closed"
case FunctionNotImplemented:
return "Function not implemented"
case ReadFailed:
return "Read failed"
case ConfigureRS485Error:
return "Error configuring RS485 on the platform"
case NoPlatformSupportForRS485:
return "Platform does not support RS485"
default:
return "Other error"
}
Expand Down
48 changes: 48 additions & 0 deletions serial_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"sync"
"sync/atomic"
"time"
"unsafe"

"go.bug.st/serial/unixutils"
"golang.org/x/sys/unix"
Expand All @@ -29,6 +30,22 @@ type unixPort struct {
opened uint32
}

const (
rs485Enabled = 1 << 0
rs485RTSOnSend = 1 << 1
rs485RTSAfterSend = 1 << 2
rs485RXDuringTX = 1 << 4
rs485Tiocs = 0x542f
)

// rs485_ioctl_opts is used to configure RS485 options in the driver
type rs485IoctlOpts struct {
flags uint32
delayRtsBeforeSend uint32
delayRtsAfterSend uint32
padding [5]uint32
}

func (port *unixPort) Close() error {
if !atomic.CompareAndSwapUint32(&port.opened, 1, 0) {
return nil
Expand Down Expand Up @@ -277,6 +294,12 @@ func nativeOpen(portName string, mode *Mode) (*unixPort, error) {

port.acquireExclusiveAccess()

// Enable RS485, if requested
if err = port.enableRS485(&mode.RS485); err != nil {
port.Close()
return nil, err
}

// This pipe is used as a signal to cancel blocking Read
pipe := &unixutils.Pipe{}
if err := pipe.Open(); err != nil {
Expand Down Expand Up @@ -467,3 +490,28 @@ func (port *unixPort) acquireExclusiveAccess() error {
func (port *unixPort) releaseExclusiveAccess() error {
return unix.IoctlSetInt(port.handle, unix.TIOCNXCL, 0)
}

// enableRS485 enables RS485 functionality of driver via an ioctl if the config says so
func (port *unixPort) enableRS485(config *RS485Config) error {
if !config.Enabled {
return nil
}
rs485 := rs485IoctlOpts{
rs485Enabled,
uint32(config.DelayRtsBeforeSend / time.Millisecond),
uint32(config.DelayRtsAfterSend / time.Millisecond),
[5]uint32{0, 0, 0, 0, 0},
}

if config.RtsHighDuringSend {
rs485.flags |= rs485RTSOnSend
}
if config.RtsHighAfterSend {
rs485.flags |= rs485RTSAfterSend
}
if config.RxDuringTx {
rs485.flags |= rs485RXDuringTX
}

return unix.IoctlSetInt(port.handle, rs485Tiocs, int(uintptr(unsafe.Pointer(&rs485))))
}
9 changes: 9 additions & 0 deletions serial_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -479,3 +479,12 @@ func nativeOpen(portName string, mode *Mode) (*windowsPort, error) {
}
return port, nil
}

// enableRS485 enables RS485 functionality of driver via an ioctl if the config says so
func (port *windowsPort) enableRS485(config *RS485Config) error {
if !config.Enabled {
return &PortError{code: NoPlatformSupportForRS485, causedBy: nil}
}

return nil
}

0 comments on commit e1a84d8

Please sign in to comment.