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

110 lines
2.7 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package handler
import (
"encoding/binary"
"git.noahlan.cn/noahlan/nnet/conn"
"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
}
// RegisterLogic 注册功能码对应的 扩展 处理方法
func (p *Handler) RegisterLogic(fnCode uint8, fn LogicFunc) {
p.logics[fnCode] = fn
}
// DataManager 数据管理器基于主机地址客户端地址modbus协议规定的主机号
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
}
// Handle 核心处理逻辑(核心路由)
func (p *Handler) Handle(nc *conn.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)
}
_ = nc.Send(resp.GetHeader(), resp.GetBody())
}
// HandleLogic 功能码对应的扩展处理方法
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)
}
}()
}