128 lines
3.5 KiB
Go
128 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/simonvetter/modbus"
|
|
)
|
|
|
|
// Handler object, passed to the NewServer()
|
|
type modbusTcpHandler struct {
|
|
// this lock is used to avoid concurrency issues between goroutines, as
|
|
// handler methods are called from different requests
|
|
lock sync.RWMutex
|
|
}
|
|
|
|
// Coil handler method.
|
|
// This method gets called whenever a valid modbus request asking for a coil operation is
|
|
// received by the server.
|
|
func (handler *modbusTcpHandler) HandleCoils(req *modbus.CoilsRequest) (res []bool, err error) {
|
|
if rtu_client == nil {
|
|
Logger.Print("Rtu client not running.")
|
|
return
|
|
}
|
|
err = rtu_client.SetUnitId(req.UnitId)
|
|
if err != nil {
|
|
Logger.Printf("Could not set unit id (%s).", err.Error())
|
|
err = modbus.ErrConfigurationError
|
|
return
|
|
}
|
|
|
|
handler.lock.Lock()
|
|
defer handler.lock.Unlock()
|
|
|
|
if req.IsWrite {
|
|
err = rtu_client.WriteCoils(req.Addr, req.Args)
|
|
if err != nil {
|
|
Logger.Printf("Could not write coil(s) (%s).", err.Error())
|
|
err = modbus.ErrServerDeviceFailure
|
|
return
|
|
}
|
|
} else {
|
|
res, err = rtu_client.ReadCoils(req.Addr, req.Quantity)
|
|
if err != nil {
|
|
Logger.Printf("Could not read coil(s) (%s).", err.Error())
|
|
err = modbus.ErrServerDeviceFailure
|
|
return
|
|
}
|
|
}
|
|
err = nil
|
|
return
|
|
}
|
|
|
|
// Discrete input handler method.
|
|
// Note that we're returning ErrIllegalFunction unconditionally.
|
|
func (handler *modbusTcpHandler) HandleDiscreteInputs(req *modbus.DiscreteInputsRequest) (res []bool, err error) {
|
|
// this is the equivalent of saying
|
|
// "discrete inputs are not supported by this device"
|
|
err = modbus.ErrIllegalFunction
|
|
|
|
return
|
|
}
|
|
|
|
// Holding register handler method.
|
|
// This method gets called whenever a valid modbus request asking for a holding register
|
|
// operation (either read or write) received by the server.
|
|
func (handler *modbusTcpHandler) HandleHoldingRegisters(req *modbus.HoldingRegistersRequest) (res []uint16, err error) {
|
|
if rtu_client == nil {
|
|
Logger.Print("Rtu client not running.")
|
|
return
|
|
}
|
|
err = rtu_client.SetUnitId(req.UnitId)
|
|
if err != nil {
|
|
Logger.Printf("Could not set unit id (%s).", err.Error())
|
|
err = modbus.ErrConfigurationError
|
|
return
|
|
}
|
|
|
|
handler.lock.Lock()
|
|
defer handler.lock.Unlock()
|
|
|
|
if req.IsWrite {
|
|
err = rtu_client.WriteRegisters(req.Addr, req.Args)
|
|
if err != nil {
|
|
Logger.Printf("Could not write holding register(s) (%s).", err.Error())
|
|
err = modbus.ErrServerDeviceFailure
|
|
return
|
|
}
|
|
} else {
|
|
res, err = rtu_client.ReadRegisters(req.Addr, req.Quantity, modbus.HOLDING_REGISTER)
|
|
if err != nil {
|
|
Logger.Printf("Could not read holding register(s) (%s).", err.Error())
|
|
err = modbus.ErrServerDeviceFailure
|
|
return
|
|
}
|
|
}
|
|
err = nil
|
|
return
|
|
}
|
|
|
|
// Input register handler method.
|
|
// This method gets called whenever a valid modbus request asking for an input register
|
|
// operation is received by the server.
|
|
// Note that input registers are always read-only as per the modbus spec.
|
|
func (handler *modbusTcpHandler) HandleInputRegisters(req *modbus.InputRegistersRequest) (res []uint16, err error) {
|
|
if rtu_client == nil {
|
|
Logger.Print("Rtu client not running.")
|
|
return
|
|
}
|
|
err = rtu_client.SetUnitId(req.UnitId)
|
|
if err != nil {
|
|
Logger.Printf("Could not set unit id (%s).", err.Error())
|
|
err = modbus.ErrConfigurationError
|
|
return
|
|
}
|
|
|
|
handler.lock.Lock()
|
|
defer handler.lock.Unlock()
|
|
|
|
res, err = rtu_client.ReadRegisters(req.Addr, req.Quantity, modbus.INPUT_REGISTER)
|
|
if err != nil {
|
|
Logger.Printf("Could not read input register(s) (%s).", err.Error())
|
|
err = modbus.ErrServerDeviceFailure
|
|
return
|
|
}
|
|
err = nil
|
|
return
|
|
}
|