|
|
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"
|
|
|
)
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
}
|