|
|
package handler
|
|
|
|
|
|
import (
|
|
|
"git.noahlan.cn/noahlan/ntool-biz/nmodbus/protocol"
|
|
|
"git.noahlan.cn/noahlan/ntool-biz/nmodbus/serialize"
|
|
|
"git.noahlan.cn/noahlan/ntool-biz/nmodbus/util"
|
|
|
)
|
|
|
|
|
|
// ReadCoils 读线圈寄存器(DO) 功能码0x01
|
|
|
func ReadCoils(s *Handler, packet protocol.Packet) ([]byte, *protocol.MError) {
|
|
|
register, numRegs, endRegister := serialize.RegisterAddressAndNumber(packet.GetBody())
|
|
|
if endRegister > 65535 {
|
|
|
return []byte{}, &protocol.IllegalDataAddress
|
|
|
}
|
|
|
// 一个寄存器2字节
|
|
|
dataSize := numRegs / 8
|
|
|
if (numRegs % 8) != 0 {
|
|
|
dataSize++
|
|
|
}
|
|
|
data := make([]byte, 1+dataSize)
|
|
|
data[0] = byte(dataSize)
|
|
|
|
|
|
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)
|
|
|
}
|
|
|
}
|
|
|
return data, &protocol.Success
|
|
|
}
|
|
|
|
|
|
// ReadDiscreteInputs 读离散输入寄存器(DI) 功能码0x02
|
|
|
func ReadDiscreteInputs(s *Handler, packet protocol.Packet) ([]byte, *protocol.MError) {
|
|
|
register, numRegs, endRegister := serialize.RegisterAddressAndNumber(packet.GetBody())
|
|
|
if endRegister > 65535 {
|
|
|
return []byte{}, &protocol.IllegalDataAddress
|
|
|
}
|
|
|
dataSize := numRegs / 8
|
|
|
if (numRegs % 8) != 0 {
|
|
|
dataSize++
|
|
|
}
|
|
|
data := make([]byte, 1+dataSize)
|
|
|
data[0] = byte(dataSize)
|
|
|
|
|
|
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)
|
|
|
}
|
|
|
}
|
|
|
return data, &protocol.Success
|
|
|
}
|
|
|
|
|
|
// ReadHoldingRegisters 读保持寄存器(AI) 功能码0x03
|
|
|
func ReadHoldingRegisters(s *Handler, packet protocol.Packet) ([]byte, *protocol.MError) {
|
|
|
register, numRegs, endRegister := serialize.RegisterAddressAndNumber(packet.GetBody())
|
|
|
if endRegister > 65536 {
|
|
|
return []byte{}, &protocol.IllegalDataAddress
|
|
|
}
|
|
|
dataMgr := s.DataManager(packet.GetAddress())
|
|
|
return append([]byte{byte(numRegs * 2)}, util.Uint16ToBytes(s.byteOrder, dataMgr.ReadHoldingRegisters(register, endRegister))...), &protocol.Success
|
|
|
}
|
|
|
|
|
|
// ReadInputRegisters 读输入寄存器(AO) 功能码0x04
|
|
|
func ReadInputRegisters(s *Handler, packet protocol.Packet) ([]byte, *protocol.MError) {
|
|
|
register, numRegs, endRegister := serialize.RegisterAddressAndNumber(packet.GetBody())
|
|
|
if endRegister > 65536 {
|
|
|
return []byte{}, &protocol.IllegalDataAddress
|
|
|
}
|
|
|
dataMgr := s.DataManager(packet.GetAddress())
|
|
|
return append([]byte{byte(numRegs * 2)}, util.Uint16ToBytes(s.byteOrder, dataMgr.ReadInputRegisters(register, endRegister))...), &protocol.Success
|
|
|
}
|
|
|
|
|
|
// WriteSingleCoil 写单个线圈寄存器 功能码0x05
|
|
|
func WriteSingleCoil(s *Handler, packet protocol.Packet) ([]byte, *protocol.MError) {
|
|
|
data := packet.GetBody()
|
|
|
register, value := serialize.RegisterAddressAndValue(data)
|
|
|
// TODO Should we use 0 for off and 65,280 (0xFF00) for on?
|
|
|
if value != 0 {
|
|
|
value = 1
|
|
|
}
|
|
|
dataMgr := s.DataManager(packet.GetAddress())
|
|
|
dataMgr.WriteSingleCoil(register, byte(value))
|
|
|
|
|
|
return data[0:4], &protocol.Success
|
|
|
}
|
|
|
|
|
|
// WriteHoldingRegister 写单个保持寄存器 功能码0x06
|
|
|
func WriteHoldingRegister(s *Handler, packet protocol.Packet) ([]byte, *protocol.MError) {
|
|
|
data := packet.GetBody()
|
|
|
register, value := serialize.RegisterAddressAndValue(data)
|
|
|
|
|
|
dataMgr := s.DataManager(packet.GetAddress())
|
|
|
dataMgr.WriteSingleHoldingRegister(register, value)
|
|
|
|
|
|
return data[0:4], &protocol.Success
|
|
|
}
|
|
|
|
|
|
// WriteMultipleCoils 写多个线圈寄存器 功能码 0x0F=15
|
|
|
func WriteMultipleCoils(s *Handler, packet protocol.Packet) ([]byte, *protocol.MError) {
|
|
|
data := packet.GetBody()
|
|
|
register, numRegs, endRegister := serialize.RegisterAddressAndNumber(data)
|
|
|
valueBytes := data[5:]
|
|
|
|
|
|
if endRegister > 65536 {
|
|
|
return []byte{}, &protocol.IllegalDataAddress
|
|
|
}
|
|
|
|
|
|
// TODO This is not correct, bits and bytes do not always align
|
|
|
//if len(valueBytes)/2 != numRegs {
|
|
|
// 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++ {
|
|
|
idxList = append(idxList, register+(i*8)+int(bitPos))
|
|
|
values = append(values, util.BitAtPosition(value, bitPos))
|
|
|
|
|
|
bitCount++
|
|
|
if bitCount >= numRegs {
|
|
|
break
|
|
|
}
|
|
|
}
|
|
|
if bitCount >= numRegs {
|
|
|
break
|
|
|
}
|
|
|
}
|
|
|
|
|
|
dataMgr := s.DataManager(packet.GetAddress())
|
|
|
dataMgr.WriteCoils(idxList, values)
|
|
|
|
|
|
return data[0:4], &protocol.Success
|
|
|
}
|
|
|
|
|
|
// WriteHoldingRegisters 写入 多个保持寄存器 功能码 0x10=16
|
|
|
func WriteHoldingRegisters(s *Handler, packet protocol.Packet) ([]byte, *protocol.MError) {
|
|
|
pkgData := packet.GetBody()
|
|
|
register, numRegs, _ := serialize.RegisterAddressAndNumber(packet.GetBody())
|
|
|
valueBytes := pkgData[5:]
|
|
|
var err *protocol.MError
|
|
|
var data []byte
|
|
|
|
|
|
if len(valueBytes)/2 != numRegs {
|
|
|
err = &protocol.IllegalDataAddress
|
|
|
}
|
|
|
|
|
|
// Copy data to memory
|
|
|
values := util.BytesToUint16(s.byteOrder, valueBytes)
|
|
|
dataMgr := s.DataManager(packet.GetAddress())
|
|
|
|
|
|
valuesUpdated := dataMgr.WriteHoldingRegisters(values, register)
|
|
|
if valuesUpdated == numRegs {
|
|
|
err = &protocol.Success
|
|
|
data = pkgData[0:4]
|
|
|
} else {
|
|
|
err = &protocol.IllegalDataAddress
|
|
|
}
|
|
|
|
|
|
return data, err
|
|
|
}
|