|
|
|
package handler
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/binary"
|
|
|
|
"git.noahlan.cn/noahlan/nnet/connection"
|
|
|
|
"git.noahlan.cn/noahlan/nnet/packet"
|
|
|
|
rt "git.noahlan.cn/noahlan/nnet/router"
|
|
|
|
"git.noahlan.cn/noahlan/ntool-biz/nmodbus/protocol"
|
|
|
|
"git.noahlan.cn/noahlan/ntool/nlog"
|
|
|
|
"sync"
|
|
|
|
)
|
|
|
|
|
|
|
|
var _ rt.Handler = (*Handler)(nil)
|
|
|
|
|
|
|
|
type (
|
|
|
|
Handler struct {
|
|
|
|
byteOrder binary.ByteOrder // 字节序
|
|
|
|
|
|
|
|
functions map[uint8]FunctionHandler
|
|
|
|
|
|
|
|
dataMap map[uint8]*DataMgr
|
|
|
|
mu sync.RWMutex
|
|
|
|
}
|
|
|
|
|
|
|
|
FunctionHandler func(handler *Handler, pkg protocol.Packet) ([]byte, *protocol.MError)
|
|
|
|
)
|
|
|
|
|
|
|
|
func NewHandler(byteOrder binary.ByteOrder) *Handler {
|
|
|
|
p := &Handler{
|
|
|
|
byteOrder: byteOrder,
|
|
|
|
functions: make(map[uint8]FunctionHandler),
|
|
|
|
dataMap: make(map[uint8]*DataMgr),
|
|
|
|
mu: sync.RWMutex{},
|
|
|
|
}
|
|
|
|
|
|
|
|
// 添加功能码对应功能
|
|
|
|
p.functions[0x01] = ReadCoils
|
|
|
|
p.functions[0x02] = ReadDiscreteInputs
|
|
|
|
p.functions[0x03] = ReadHoldingRegisters
|
|
|
|
p.functions[0x04] = ReadInputRegisters
|
|
|
|
p.functions[0x05] = WriteSingleCoil
|
|
|
|
p.functions[0x06] = WriteHoldingRegister
|
|
|
|
p.functions[0x0F] = WriteMultipleCoils
|
|
|
|
p.functions[0x10] = WriteHoldingRegisters
|
|
|
|
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Handler) RegisterFunction(fnCode uint8, fn FunctionHandler) {
|
|
|
|
p.functions[fnCode] = fn
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Handler) DataManager(address uint8) *DataMgr {
|
|
|
|
p.mu.Lock()
|
|
|
|
defer p.mu.Unlock()
|
|
|
|
|
|
|
|
ret, ok := p.dataMap[address]
|
|
|
|
if !ok {
|
|
|
|
ret = NewDataManager(address)
|
|
|
|
p.dataMap[address] = ret
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Handler) Handle(conn *connection.Connection, pkg packet.IPacket) {
|
|
|
|
pp, ok := pkg.(protocol.Packet)
|
|
|
|
if !ok {
|
|
|
|
nlog.Error(packet.ErrWrongPacketType)
|
|
|
|
}
|
|
|
|
var (
|
|
|
|
err *protocol.MError
|
|
|
|
data []byte
|
|
|
|
)
|
|
|
|
|
|
|
|
resp := pp.Copy()
|
|
|
|
|
|
|
|
fnCode := pp.GetFunction()
|
|
|
|
fn, ok := p.functions[fnCode]
|
|
|
|
if ok {
|
|
|
|
data, err = fn(p, pp)
|
|
|
|
resp.SetBody(data)
|
|
|
|
} else {
|
|
|
|
err = &protocol.IllegalFunction
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != &protocol.Success {
|
|
|
|
resp.SetError(err)
|
|
|
|
}
|
|
|
|
_ = conn.Send(resp.GetHeader(), resp.GetBody())
|
|
|
|
}
|