You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ntool-biz/nmodbus/handler/handler.go

106 lines
2.4 KiB
Go

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(pkg protocol.Packet, startAddr, number int, val any)
)
func NewHandler(byteOrder binary.ByteOrder) *Handler {
p := &Handler{
byteOrder: byteOrder,
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, pkg protocol.Packet, startAddr, number int, val any) {
go func() {
if fn, ok := p.logics[fnCode]; ok {
fn(pkg, startAddr, number, val)
}
}()
}