Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Ascii over UDP client #60

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
102 changes: 102 additions & 0 deletions asciiudpclient.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright 2014 Quoc-Viet Nguyen. All rights reserved.
// This software may be modified and distributed under the terms
// of the BSD license. See the LICENSE file for details.

package modbus

import (
"fmt"
"log"
"net"
"sync"
"time"
)

const (
udpTimeout = 10 * time.Second
)

// ASCIIClientHandler implements Packager and Transporter interface.
type ASCIIUDPClientHandler struct {
asciiPackager
asciiUdpTransporter
}

// NewASCIIClientHandler allocates and initializes a ASCIIClientHandler.
// The address format is ip:port
func NewASCIIUDPClientHandler(address string, slaveId int) *ASCIIUDPClientHandler {
handler := &ASCIIUDPClientHandler{}
handler.Address = address
handler.SlaveId = byte(slaveId)
handler.Timeout = udpTimeout
return handler
}

// ASCIIClient creates ASCII client with default handler and given connect string.
func ASCIIUDPClient(address string, slaveId int) Client {
handler := NewASCIIUDPClientHandler(address, slaveId)
return NewClient(handler)
}


func (mb *asciiUdpTransporter) logf(format string, v ...interface{}) {
if mb.Logger != nil {
mb.Logger.Printf(format, v...)
}
}


// asciiUdpTransporter implements Transporter interface.
type asciiUdpTransporter struct {
// Connect string
Address string
// Connect & Read timeout
Timeout time.Duration
// Transmission logger
Logger *log.Logger

// UDP "connection"
mu sync.Mutex
conn *net.UDPConn
}

func (mb *asciiUdpTransporter) Send(aduRequest []byte) (aduResponse []byte, err error) {
mb.mu.Lock()
defer mb.mu.Unlock()

// Make sure port is connected
if err = mb.connect(); err != nil {
return
}

// Send the request
mb.logf("modbus: sending %q\n", aduRequest)
if _, err = mb.conn.Write(aduRequest); err != nil {
return
}
// Get the response
var length int
data := make([]byte, asciiMaxSize)
mb.conn.SetDeadline(time.Now().Add(mb.Timeout))
length, _, err = mb.conn.ReadFromUDP(data)
if err != nil {
fmt.Println(err)
return
}
aduResponse = data[0:length]
mb.logf("modbus: received %q\n", aduResponse)
return
}


func (mb *asciiUdpTransporter) connect() error {
if mb.conn == nil {
s, err := net.ResolveUDPAddr("udp4", mb.Address)
conn, err := net.DialUDP("udp4", nil, s)
if err != nil {
return err
}
mb.conn = conn
}
return nil
}