From 6835c6f0116698adbfa3b0d136a7cf65757e8930 Mon Sep 17 00:00:00 2001 From: NoahLan <6995syu@163.com> Date: Mon, 19 Jun 2023 11:25:35 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=AF=84=E5=AD=98=E5=99=A8=E5=BA=94?= =?UTF-8?q?=E5=BD=93=E6=A0=B9=E6=8D=AE=E4=B8=BB=E6=9C=BA=E5=9C=B0=E5=9D=80?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E5=8C=BA=E5=88=86=E4=BB=A5=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=A4=9A=E4=B8=BB=E6=9C=BA=E5=8D=95=E4=BB=8E=E6=9C=BA=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nmodbus/handler/data.go | 96 ++++++++++++++++++++++++++++++++++-- nmodbus/handler/functions.go | 40 ++++++++++++--- nmodbus/handler/handler.go | 29 +++++++---- nmodbus/modbus_tcp.go | 2 +- 4 files changed, 144 insertions(+), 23 deletions(-) diff --git a/nmodbus/handler/data.go b/nmodbus/handler/data.go index 23e6ef0..069edbe 100644 --- a/nmodbus/handler/data.go +++ b/nmodbus/handler/data.go @@ -1,8 +1,96 @@ package handler +import "sync" + +// DataMgr 数据管理器 type DataMgr struct { - Coils []byte // 线圈(DO:数字输出) - DiscreteInputs []byte // 离散输入(DI:数字输入) - HoldingRegisters []uint16 // 保持寄存器(AO:模拟输出) - InputRegisters []uint16 // 输入寄存器(AI:模拟输入) + Address uint8 // 主机地址 + + coils []byte // 线圈(DO:数字输出) + discreteInputs []byte // 离散输入(DI:数字输入) + holdingRegisters []uint16 // 保持寄存器(AO:模拟输出) + inputRegisters []uint16 // 输入寄存器(AI:模拟输入) + + mu sync.RWMutex +} + +func NewDataManager(address uint8) *DataMgr { + return &DataMgr{ + Address: address, + coils: make([]byte, 65536), + discreteInputs: make([]byte, 65536), + holdingRegisters: make([]uint16, 65536), + inputRegisters: make([]uint16, 65536), + mu: sync.RWMutex{}, + } +} + +func (m *DataMgr) ReadCoils(start, end int) []byte { + m.mu.RLock() + defer m.mu.RUnlock() + + return m.coils[start:end] +} + +func (m *DataMgr) ReadDiscreteInputs(start, end int) []byte { + m.mu.RLock() + defer m.mu.RUnlock() + + return m.discreteInputs[start:end] +} + +func (m *DataMgr) ReadHoldingRegisters(start, end int) []uint16 { + m.mu.RLock() + defer m.mu.RUnlock() + + return m.holdingRegisters[start:end] +} + +func (m *DataMgr) ReadInputRegisters(start, end int) []uint16 { + m.mu.RLock() + defer m.mu.RUnlock() + + return m.inputRegisters[start:end] +} + +// WriteSingleCoil 写单个线圈数据 +func (m *DataMgr) WriteSingleCoil(idx int, val byte) { + m.mu.Lock() + defer m.mu.Unlock() + + m.coils[idx] = val +} + +// WriteSingleHoldingRegister 写入单个保持寄存器 +func (m *DataMgr) WriteSingleHoldingRegister(idx int, val uint16) { + m.mu.Lock() + defer m.mu.Unlock() + + m.holdingRegisters[idx] = val +} + +// WriteCoils 写多个线圈数据 +// idxList 表示预写入的线圈地址列表 +// values 表示预写入的线圈数据,与地址列表一一对应 +func (m *DataMgr) WriteCoils(idxList []int, values []byte) { + m.mu.Lock() + defer m.mu.Unlock() + + for i, idx := range idxList { + m.coils[idx] = values[i] + } +} + +func (m *DataMgr) WriteHoldingRegisters(values []uint16, start int, end ...int) int { + m.mu.Lock() + defer m.mu.Unlock() + + var e int + if len(end) == 0 { + e = len(m.holdingRegisters) + } else { + e = end[0] + } + + return copy(m.holdingRegisters[start:e], values) } diff --git a/nmodbus/handler/functions.go b/nmodbus/handler/functions.go index 5d767cb..144b5d7 100644 --- a/nmodbus/handler/functions.go +++ b/nmodbus/handler/functions.go @@ -19,7 +19,11 @@ func ReadCoils(s *Handler, packet protocol.Packet) ([]byte, *protocol.MError) { } data := make([]byte, 1+dataSize) data[0] = byte(dataSize) - for i, value := range s.Coils[register:endRegister] { + + dataMgr := s.DataManager(packet.GetAddress()) + coils := dataMgr.ReadCoils(register, endRegister) + + for i, value := range coils { if value != 0 { shift := uint(i) % 8 data[1+i/8] |= byte(1 << shift) @@ -40,7 +44,11 @@ func ReadDiscreteInputs(s *Handler, packet protocol.Packet) ([]byte, *protocol.M } data := make([]byte, 1+dataSize) data[0] = byte(dataSize) - for i, value := range s.DiscreteInputs[register:endRegister] { + + dataMgr := s.DataManager(packet.GetAddress()) + discreteInputs := dataMgr.ReadDiscreteInputs(register, endRegister) + + for i, value := range discreteInputs { if value != 0 { shift := uint(i) % 8 data[1+i/8] |= byte(1 << shift) @@ -55,7 +63,8 @@ func ReadHoldingRegisters(s *Handler, packet protocol.Packet) ([]byte, *protocol if endRegister > 65536 { return []byte{}, &protocol.IllegalDataAddress } - return append([]byte{byte(numRegs * 2)}, util.Uint16ToBytes(s.byteOrder, s.HoldingRegisters[register:endRegister])...), &protocol.Success + dataMgr := s.DataManager(packet.GetAddress()) + return append([]byte{byte(numRegs * 2)}, util.Uint16ToBytes(s.byteOrder, dataMgr.ReadHoldingRegisters(register, endRegister))...), &protocol.Success } // ReadInputRegisters 读输入寄存器(AO) 功能码0x04 @@ -64,7 +73,8 @@ func ReadInputRegisters(s *Handler, packet protocol.Packet) ([]byte, *protocol.M if endRegister > 65536 { return []byte{}, &protocol.IllegalDataAddress } - return append([]byte{byte(numRegs * 2)}, util.Uint16ToBytes(s.byteOrder, s.InputRegisters[register:endRegister])...), &protocol.Success + dataMgr := s.DataManager(packet.GetAddress()) + return append([]byte{byte(numRegs * 2)}, util.Uint16ToBytes(s.byteOrder, dataMgr.ReadInputRegisters(register, endRegister))...), &protocol.Success } // WriteSingleCoil 写单个线圈寄存器 功能码0x05 @@ -75,7 +85,9 @@ func WriteSingleCoil(s *Handler, packet protocol.Packet) ([]byte, *protocol.MErr if value != 0 { value = 1 } - s.Coils[register] = byte(value) + dataMgr := s.DataManager(packet.GetAddress()) + dataMgr.WriteSingleCoil(register, byte(value)) + return data[0:4], &protocol.Success } @@ -83,7 +95,10 @@ func WriteSingleCoil(s *Handler, packet protocol.Packet) ([]byte, *protocol.MErr func WriteHoldingRegister(s *Handler, packet protocol.Packet) ([]byte, *protocol.MError) { data := packet.GetBody() register, value := serialize.RegisterAddressAndValue(data) - s.HoldingRegisters[register] = value + + dataMgr := s.DataManager(packet.GetAddress()) + dataMgr.WriteSingleHoldingRegister(register, value) + return data[0:4], &protocol.Success } @@ -102,10 +117,14 @@ func WriteMultipleCoils(s *Handler, packet protocol.Packet) ([]byte, *protocol.M // return []byte{}, &IllegalDataAddress //} + idxList := make([]int, 0) + values := make([]byte, 0) bitCount := 0 for i, value := range valueBytes { for bitPos := uint(0); bitPos < 8; bitPos++ { - s.Coils[register+(i*8)+int(bitPos)] = util.BitAtPosition(value, bitPos) + idxList = append(idxList, register+(i*8)+int(bitPos)) + values = append(values, util.BitAtPosition(value, bitPos)) + bitCount++ if bitCount >= numRegs { break @@ -116,6 +135,9 @@ func WriteMultipleCoils(s *Handler, packet protocol.Packet) ([]byte, *protocol.M } } + dataMgr := s.DataManager(packet.GetAddress()) + dataMgr.WriteCoils(idxList, values) + return data[0:4], &protocol.Success } @@ -133,7 +155,9 @@ func WriteHoldingRegisters(s *Handler, packet protocol.Packet) ([]byte, *protoco // Copy data to memory values := util.BytesToUint16(s.byteOrder, valueBytes) - valuesUpdated := copy(s.HoldingRegisters[register:], values) + dataMgr := s.DataManager(packet.GetAddress()) + + valuesUpdated := dataMgr.WriteHoldingRegisters(values, register) if valuesUpdated == numRegs { err = &protocol.Success data = pkgData[0:4] diff --git a/nmodbus/handler/handler.go b/nmodbus/handler/handler.go index cfba162..cc2b0e5 100644 --- a/nmodbus/handler/handler.go +++ b/nmodbus/handler/handler.go @@ -7,6 +7,7 @@ import ( 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) @@ -17,10 +18,8 @@ type ( functions map[uint8]FunctionHandler - DiscreteInputs []byte // 离散输入 - Coils []byte // 线圈 - HoldingRegisters []uint16 // 保持寄存器 - InputRegisters []uint16 // 输入寄存器 + dataMap map[uint8]*DataMgr + mu sync.RWMutex } FunctionHandler func(handler *Handler, pkg protocol.Packet) ([]byte, *protocol.MError) @@ -28,12 +27,10 @@ type ( func NewHandler(byteOrder binary.ByteOrder) *Handler { p := &Handler{ - byteOrder: byteOrder, - functions: make(map[uint8]FunctionHandler), - DiscreteInputs: make([]byte, 65536), - Coils: make([]byte, 65536), - HoldingRegisters: make([]uint16, 65536), - InputRegisters: make([]uint16, 65536), + byteOrder: byteOrder, + functions: make(map[uint8]FunctionHandler), + dataMap: make(map[uint8]*DataMgr), + mu: sync.RWMutex{}, } // 添加功能码对应功能 @@ -53,6 +50,18 @@ 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 { diff --git a/nmodbus/modbus_tcp.go b/nmodbus/modbus_tcp.go index ff9156d..aaa10f6 100644 --- a/nmodbus/modbus_tcp.go +++ b/nmodbus/modbus_tcp.go @@ -20,7 +20,7 @@ import ( // defer ngin.Stop() // // handler.RegisterFunction(code, func()) // 自定义功能码对应的处理方法 -// hr := handler.HoldingRegisters[0] // 获取地址为0x00的保持寄存器 2字节 uint16 (也可以设置,但非线程安全的) +// hr := handler.holdingRegisters[0] // 获取地址为0x00的保持寄存器 2字节 uint16 (也可以设置,但非线程安全的) // // ngin.ListenTCP(config.TCPServerConf{Protocol: "tcp", Addr: "0.0.0.0:5502"}) func NewModbusTCPEngine(conf ModbusTCPConf) (*nnet.Engine, *handler.Handler) {