|
|
|
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 // 字节序
|
|
|
|
|
|
|
|
logics map[uint8]LogicFunc
|
|
|
|
handlerMap map[uint8]FunctionHandler
|
|
|
|
|
|
|
|
dataMap map[uint8]*DataMgr
|
|
|
|
mu sync.RWMutex
|
|
|
|
}
|
|
|
|
|
|
|
|
FunctionHandler interface {
|
|
|
|
Function(handler *Handler, req protocol.Packet, resp protocol.Packet) *protocol.MError
|
|
|
|
FnCode() uint8
|
|
|
|
}
|
|
|
|
|
|
|
|
LogicFunc func(startAddr, number int, val any)
|
|
|
|
)
|
|
|
|
|
|
|
|
func NewHandler(byteOrder binary.ByteOrder) *Handler {
|
|
|
|
p := &Handler{
|
|
|
|
byteOrder: byteOrder,
|
|
|
|
//functions: make(map[uint8]FunctionFunc),
|
|
|
|
logics: make(map[uint8]LogicFunc),
|
|
|
|
handlerMap: make(map[uint8]FunctionHandler),
|
|
|
|
dataMap: make(map[uint8]*DataMgr),
|
|
|
|
mu: sync.RWMutex{},
|
|
|
|
}
|
|
|
|
|
|
|
|
// 添加功能码对应功能
|
|
|
|
p.RegisterFunction(NewReadCoils(0x01))
|
|
|
|
p.RegisterFunction(NewReadDiscreteInputs(0x02))
|
|
|
|
p.RegisterFunction(NewReadHoldingRegisters(0x03))
|
|
|
|
p.RegisterFunction(NewReadInputRegisters(0x04))
|
|
|
|
p.RegisterFunction(NewWriteSingleCoil(0x05))
|
|
|
|
p.RegisterFunction(NewWriteHoldingRegister(0x06))
|
|
|
|
p.RegisterFunction(NewWriteMultipleCoils(0x0F))
|
|
|
|
p.RegisterFunction(NewWriteHoldingRegisters(0x10))
|
|
|
|
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Handler) RegisterFunction(fn FunctionHandler) {
|
|
|
|
p.handlerMap[fn.FnCode()] = fn
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Handler) RegisterLogic(fnCode uint8, fn LogicFunc) {
|
|
|
|
p.logics[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) {
|
|
|
|
req, ok := pkg.(protocol.Packet)
|
|
|
|
if !ok {
|
|
|
|
nlog.Error(packet.ErrWrongPacketType)
|
|
|
|
}
|
|
|
|
var err *protocol.MError
|
|
|
|
|
|
|
|
resp := req.Copy()
|
|
|
|
|
|
|
|
fnCode := req.GetFunction()
|
|
|
|
handler, ok := p.handlerMap[fnCode]
|
|
|
|
if ok {
|
|
|
|
err = handler.Function(p, req, resp)
|
|
|
|
} else {
|
|
|
|
err = &protocol.IllegalFunction
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != &protocol.Success {
|
|
|
|
resp.SetError(err)
|
|
|
|
}
|
|
|
|
_ = conn.Send(resp.GetHeader(), resp.GetBody())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Handler) HandleLogic(fnCode uint8, startAddr, number int, val any) {
|
|
|
|
go func() {
|
|
|
|
if fn, ok := p.logics[fnCode]; ok {
|
|
|
|
fn(startAddr, number, val)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|