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/fn_coils.go

143 lines
3.5 KiB
Go

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
type ReadCoils struct {
fnCode uint8
}
func NewReadCoils(fnCode uint8) FunctionHandler {
return &ReadCoils{fnCode: fnCode}
}
func (r *ReadCoils) FnCode() uint8 {
return r.fnCode
}
// Function 读线圈寄存器DO 功能码0x01
func (r *ReadCoils) Function(s *Handler, req protocol.Packet, resp protocol.Packet) *protocol.MError {
register, numRegs, endRegister := serialize.RegisterAddressAndNumber(req.GetBody())
if endRegister > 65535 {
resp.SetBody([]byte{})
return &protocol.IllegalDataAddress
}
// 一个寄存器2字节
dataSize := numRegs / 8
if (numRegs % 8) != 0 {
dataSize++
}
data := make([]byte, 1+dataSize)
data[0] = byte(dataSize)
dataMgr := s.DataManager(req.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)
}
}
s.HandleLogic(r.fnCode, req, register, numRegs, coils)
resp.SetBody(data)
return &protocol.Success
}
////////////////////////////////////////////// write-single
// WriteSingleCoil 写单个线圈寄存器 功能码0x05
type WriteSingleCoil struct {
fnCode uint8
}
func NewWriteSingleCoil(fnCode uint8) FunctionHandler {
return &WriteSingleCoil{fnCode: fnCode}
}
func (r *WriteSingleCoil) FnCode() uint8 {
return r.fnCode
}
// Function 写单个线圈寄存器 功能码0x05
func (r *WriteSingleCoil) Function(s *Handler, req protocol.Packet, resp protocol.Packet) *protocol.MError {
data := req.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(req.GetAddress())
dataMgr.WriteSingleCoil(register, byte(value))
s.HandleLogic(r.fnCode, req, register, 1, value)
resp.SetBody(data[0:4])
return &protocol.Success
}
////////////////////////////////////////////// write-multiple
// WriteMultipleCoils 写多个线圈寄存器 功能码 0x0F=15
type WriteMultipleCoils struct {
fnCode uint8
}
func NewWriteMultipleCoils(fnCode uint8) FunctionHandler {
return &WriteMultipleCoils{fnCode: fnCode}
}
func (r *WriteMultipleCoils) FnCode() uint8 {
return r.fnCode
}
// Function 写多个线圈寄存器 功能码 0x0F=15
func (r *WriteMultipleCoils) Function(s *Handler, req protocol.Packet, resp protocol.Packet) *protocol.MError {
data := req.GetBody()
register, numRegs, endRegister := serialize.RegisterAddressAndNumber(data)
valueBytes := data[5:]
if endRegister > 65536 {
resp.SetBody([]byte{})
return &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(req.GetAddress())
dataMgr.WriteCoils(idxList, values)
s.HandleLogic(r.fnCode, req, register, numRegs, values)
resp.SetBody(data[0:4])
return &protocol.Success
}