Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 20 additions & 10 deletions ascii_over_tcp_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ import (

// ASCIIOverTCPClientHandler implements Packager and Transporter interface.
type ASCIIOverTCPClientHandler struct {
asciiPackager
asciiTCPTransporter
ASCIIPackager
ASCIITCPTransporter
}

// NewASCIIOverTCPClientHandler allocates and initializes a ASCIIOverTCPClientHandler.
func NewASCIIOverTCPClientHandler(address string) *ASCIIOverTCPClientHandler {
handler := &ASCIIOverTCPClientHandler{}
handler.Address = address
handler.Timeout = tcpTimeout
handler.IdleTimeout = tcpIdleTimeout
handler := &ASCIIOverTCPClientHandler{
ASCIIPackager: ASCIIPackager{},
ASCIITCPTransporter: NewASCIITCPTransporter(address),
}
return handler
}

Expand All @@ -29,12 +29,22 @@ func ASCIIOverTCPClient(address string) Client {
return NewClient(handler)
}

// asciiTCPTransporter implements Transporter interface.
type asciiTCPTransporter struct {
tcpTransporter
var _ Transporter = (*ASCIITCPTransporter)(nil)

// ASCIITCPTransporter implements Transporter interface.
type ASCIITCPTransporter struct {
TCPTransporter
}

// NewASCIITCPTransporter creates ASCIITCPTransporter with default values
func NewASCIITCPTransporter(address string) ASCIITCPTransporter {
return ASCIITCPTransporter{
TCPTransporter: NewTCPTransporter(address),
}
}

func (mb *asciiTCPTransporter) Send(aduRequest []byte) (aduResponse []byte, err error) {
// Send sends data to server and ensures response has required length.
func (mb *ASCIITCPTransporter) Send(aduRequest []byte) (aduResponse []byte, err error) {
mb.mu.Lock()
defer mb.mu.Unlock()

Expand Down
74 changes: 42 additions & 32 deletions asciiclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,16 @@ var asciiStart = []string{":", ">"}

// ASCIIClientHandler implements Packager and Transporter interface.
type ASCIIClientHandler struct {
asciiPackager
asciiSerialTransporter
ASCIIPackager
ASCIISerialTransporter
}

// NewASCIIClientHandler allocates and initializes a ASCIIClientHandler.
func NewASCIIClientHandler(address string) *ASCIIClientHandler {
handler := &ASCIIClientHandler{}
handler.Address = address
handler.Timeout = serialTimeout
handler.IdleTimeout = serialIdleTimeout
handler.serialPort.Logger = handler // expose the logger
handler := &ASCIIClientHandler{
ASCIIPackager: ASCIIPackager{},
ASCIISerialTransporter: NewASCIISerialTransporter(address),
}
return handler
}

Expand All @@ -44,24 +43,25 @@ func ASCIIClient(address string) Client {
return NewClient(handler)
}

// asciiPackager implements Packager interface.
type asciiPackager struct {
// ASCIIPackager implements Packager interface.
type ASCIIPackager struct {
SlaveID byte
}

// SetSlave sets modbus slave id for the next client operations
func (mb *asciiPackager) SetSlave(slaveID byte) {
func (mb *ASCIIPackager) SetSlave(slaveID byte) {
mb.SlaveID = slaveID
}

// Encode encodes PDU in a ASCII frame:
// Start : 1 char
// Address : 2 chars
// Function : 2 chars
// Data : 0 up to 2x252 chars
// LRC : 2 chars
// End : 2 chars
func (mb *asciiPackager) Encode(pdu *ProtocolDataUnit) (adu []byte, err error) {
//
// Start : 1 char
// Address : 2 chars
// Function : 2 chars
// Data : 0 up to 2x252 chars
// LRC : 2 chars
// End : 2 chars
func (mb *ASCIIPackager) Encode(pdu *ProtocolDataUnit) (adu []byte, err error) {
var buf bytes.Buffer

if _, err = buf.WriteString(asciiStart[0]); err != nil {
Expand All @@ -88,7 +88,7 @@ func (mb *asciiPackager) Encode(pdu *ProtocolDataUnit) (adu []byte, err error) {
}

// Verify verifies response length, frame boundary and slave id.
func (mb *asciiPackager) Verify(aduRequest []byte, aduResponse []byte) (err error) {
func (mb *ASCIIPackager) Verify(aduRequest []byte, aduResponse []byte) (err error) {
length := len(aduResponse)
// Minimum size (including address, function and LRC)
if length < asciiMinSize+6 {
Expand Down Expand Up @@ -129,7 +129,7 @@ func (mb *asciiPackager) Verify(aduRequest []byte, aduResponse []byte) (err erro
}

// Decode extracts PDU from ASCII frame and verify LRC.
func (mb *asciiPackager) Decode(adu []byte) (pdu *ProtocolDataUnit, err error) {
func (mb *ASCIIPackager) Decode(adu []byte) (pdu *ProtocolDataUnit, err error) {
pdu = &ProtocolDataUnit{}
// Slave address
address, err := readHex(adu[1:])
Expand Down Expand Up @@ -163,32 +163,42 @@ func (mb *asciiPackager) Decode(adu []byte) (pdu *ProtocolDataUnit, err error) {
return
}

// asciiSerialTransporter implements Transporter interface.
type asciiSerialTransporter struct {
serialPort
Logger logger
// ASCIISerialTransporter implements Transporter interface.
type ASCIISerialTransporter struct {
SerialPort
}

// NewASCIISerialTransporter creates ASCIISerialTransporter with default values
func NewASCIISerialTransporter(address string) ASCIISerialTransporter {
t := ASCIISerialTransporter{
SerialPort: *NewSerialPort(address),
}
t.SerialPort.Logger = &t
return t
}

func (mb *asciiSerialTransporter) Printf(format string, v ...interface{}) {
// Printf implements the Logger interface
func (mb *ASCIISerialTransporter) Printf(format string, v ...interface{}) {
if mb.Logger != nil {
mb.Logger.Printf(format, v...)
}
}

func (mb *asciiSerialTransporter) Send(aduRequest []byte) (aduResponse []byte, err error) {
mb.serialPort.mu.Lock()
defer mb.serialPort.mu.Unlock()
// Send sends data to serial device and ensures adequate response for request type
func (mb *ASCIISerialTransporter) Send(aduRequest []byte) (aduResponse []byte, err error) {
mb.SerialPort.mu.Lock()
defer mb.SerialPort.mu.Unlock()

// Make sure port is connected
if err = mb.serialPort.connect(); err != nil {
if err = mb.SerialPort.connect(); err != nil {
return
}
// Start the timer to close when idle
mb.serialPort.lastActivity = time.Now()
mb.serialPort.startCloseTimer()
mb.SerialPort.lastActivity = time.Now()
mb.SerialPort.startCloseTimer()

// Send the request
mb.serialPort.logf("modbus: send % x\n", aduRequest)
mb.SerialPort.logf("modbus: send % x\n", aduRequest)
if _, err = mb.port.Write(aduRequest); err != nil {
return
}
Expand All @@ -211,7 +221,7 @@ func (mb *asciiSerialTransporter) Send(aduRequest []byte) (aduResponse []byte, e
}
}
aduResponse = data[:length]
mb.serialPort.logf("modbus: recv % x\n", aduResponse)
mb.SerialPort.logf("modbus: recv % x\n", aduResponse)
return
}

Expand Down
10 changes: 5 additions & 5 deletions asciiclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

func TestASCIIEncoding(t *testing.T) {
encoder := asciiPackager{}
encoder := ASCIIPackager{}
encoder.SlaveID = 17

pdu := ProtocolDataUnit{}
Expand All @@ -28,7 +28,7 @@ func TestASCIIEncoding(t *testing.T) {
}

func TestASCIIDecoding(t *testing.T) {
decoder := asciiPackager{}
decoder := ASCIIPackager{}
decoder.SlaveID = 247
adu := []byte(":F7031389000A60\r\n")

Expand All @@ -47,7 +47,7 @@ func TestASCIIDecoding(t *testing.T) {
}

func TestASCIIDecodeStartCharacter(t *testing.T) {
decoder := asciiPackager{}
decoder := ASCIIPackager{}
aduReq := []byte(":010300010002F9\r\n")
aduRespGreaterThan := []byte(">010304010F1509CA\r\n")
aduRespColon := []byte(":010304010F1509CA\r\n")
Expand All @@ -69,7 +69,7 @@ func TestASCIIDecodeStartCharacter(t *testing.T) {
}

func BenchmarkASCIIEncoder(b *testing.B) {
encoder := asciiPackager{
encoder := ASCIIPackager{
SlaveID: 10,
}
pdu := ProtocolDataUnit{
Expand All @@ -85,7 +85,7 @@ func BenchmarkASCIIEncoder(b *testing.B) {
}

func BenchmarkASCIIDecoder(b *testing.B) {
decoder := asciiPackager{
decoder := ASCIIPackager{
SlaveID: 10,
}
adu := []byte(":F7031389000A60\r\n")
Expand Down
35 changes: 35 additions & 0 deletions client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package modbus

import "testing"

const localhost = ":502"

func TestTcp(t *testing.T) {
pack := TCPPackager{SlaveID: 1}
trans := NewTCPTransporter(localhost)
_ = NewClient2(&pack, &trans)
}

func TestRtuOverTcp(t *testing.T) {
pack := RtuPackager{SlaveID: 1}
trans := NewRTUTCPTransporter(localhost)
_ = NewClient2(&pack, &trans)
}

func TestAsciiOverTcp(t *testing.T) {
pack := ASCIIPackager{SlaveID: 1}
trans := NewASCIITCPTransporter(localhost)
_ = NewClient2(&pack, &trans)
}

func TestRtu(t *testing.T) {
pack := RtuPackager{SlaveID: 1}
trans := NewRtuSerialTransporter(localhost)
_ = NewClient2(&pack, &trans)
}

func TestAscii(t *testing.T) {
pack := ASCIIPackager{SlaveID: 1}
trans := NewASCIISerialTransporter(localhost)
_ = NewClient2(&pack, &trans)
}
28 changes: 18 additions & 10 deletions rtu_over_tcp_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,15 @@ import (

// RTUOverTCPClientHandler implements Packager and Transporter interface.
type RTUOverTCPClientHandler struct {
rtuPackager
rtuTCPTransporter
RtuPackager
RtuTCPTransporter
}

// NewRTUOverTCPClientHandler allocates and initializes a RTUOverTCPClientHandler.
func NewRTUOverTCPClientHandler(address string) *RTUOverTCPClientHandler {
handler := &RTUOverTCPClientHandler{}
handler.Address = address
handler.Timeout = tcpTimeout
handler.IdleTimeout = tcpIdleTimeout
handler := &RTUOverTCPClientHandler{
RtuTCPTransporter: NewRTUTCPTransporter(address),
}
return handler
}

Expand All @@ -30,13 +29,22 @@ func RTUOverTCPClient(address string) Client {
return NewClient(handler)
}

// rtuTCPTransporter implements Transporter interface.
type rtuTCPTransporter struct {
tcpTransporter
var _ Transporter = (*RtuTCPTransporter)(nil)

// RtuTCPTransporter implements Transporter interface.
type RtuTCPTransporter struct {
TCPTransporter
}

// NewRTUTCPTransporter creates RtuTCPTransporter with default values
func NewRTUTCPTransporter(address string) RtuTCPTransporter {
return RtuTCPTransporter{
TCPTransporter: NewTCPTransporter(address),
}
}

// Send sends data to server and ensures adequate response for request type
func (mb *rtuTCPTransporter) Send(aduRequest []byte) (aduResponse []byte, err error) {
func (mb *RtuTCPTransporter) Send(aduRequest []byte) (aduResponse []byte, err error) {
mb.mu.Lock()
defer mb.mu.Unlock()

Expand Down
Loading