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

140 lines
3.3 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 (
"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
}