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 }