com.intelligt.modbus.jlibmodbus.msg.request.DiagnosticsRequest Maven / Gradle / Ivy
package com.intelligt.modbus.jlibmodbus.msg.request;
import com.intelligt.modbus.jlibmodbus.data.CommStatus;
import com.intelligt.modbus.jlibmodbus.data.DataHolder;
import com.intelligt.modbus.jlibmodbus.exception.ModbusNumberException;
import com.intelligt.modbus.jlibmodbus.msg.base.ModbusRequest;
import com.intelligt.modbus.jlibmodbus.msg.base.ModbusResponse;
import com.intelligt.modbus.jlibmodbus.msg.response.DiagnosticsResponse;
import com.intelligt.modbus.jlibmodbus.net.stream.base.ModbusInputStream;
import com.intelligt.modbus.jlibmodbus.net.stream.base.ModbusOutputStream;
import com.intelligt.modbus.jlibmodbus.utils.DiagnosticsSubFunctionCode;
import com.intelligt.modbus.jlibmodbus.utils.ModbusFunctionCode;
import java.io.IOException;
/*
* Copyright (C) 2016 "Invertor" Factory", JSC
* [http://www.sbp-invertor.ru]
*
* This file is part of JLibModbus.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Authors: Vladislav Y. Kochedykov, software engineer.
* email: [email protected]
*/
/**
* MODBUS function code 08 provides a series of tests for checking the communication system
* between a client ( Master) device and a server ( Slave), or for checking various internal error
* conditions within a server.
* The function uses a two–byte sub-function code field in the query to define the type of test to
* be performed. The server echoes both the function code and sub-function code in a normal
* response. Some of the diagnostics cause data to be returned from the remote device in the
* data field of a normal response.
* In general, issuing a diagnostic function to a remote device does not affect the running of the
* user program in the remote device. User logic, like discrete and registers, is not accessed by
* the diagnostics. Certain functions can optionally reset error counters in the remote device.
* A server device can, however, be forced into ‘Listen Only Mode’ in which it will monitor the
* messages on the communications system but not respond to them. This can affect the
* outcome of your application program if it depends upon any further exchange of data with the
* remote device. Generally, the mode is forced to remove a malfunctioning remote device from
* the communications system.
* The following diagnostic functions are dedicated to serial line devices.
* The normal response to the Return Query Data request is to loopback the same data. The
* function code and sub-function codes are also echoed.
*/
public class DiagnosticsRequest extends ModbusRequest {
/**
* Diagnostic uses a two–byte sub-function code field in the query to define the type of test to
* be performed.
*/
final static public int CLEAR_LOG = 0xff00;
private DiagnosticsSubFunctionCode subFunctionCode = DiagnosticsSubFunctionCode.RESERVED;
private int subFunctionData = 0;
public DiagnosticsRequest() {
super();
}
@Override
protected Class getResponseClass() {
return DiagnosticsResponse.class;
}
@Override
public void writeRequest(ModbusOutputStream fifo) throws IOException {
fifo.writeShortBE(getSubFunctionCode().toInt());
fifo.writeShortBE(getSubFunctionData());
}
@Override
public int requestSize() {
return 4;
}
@Override
public ModbusResponse process(DataHolder dataHolder) throws ModbusNumberException {
DiagnosticsResponse response = new DiagnosticsResponse();
response.setServerAddress(getServerAddress());
response.setSubFunctionCode(getSubFunctionCode());
CommStatus commStatus = dataHolder.getCommStatus();
switch (getSubFunctionCode()) {
case RETURN_QUERY_DATA:
response.setSubFunctionData(getSubFunctionData());
break;
case RESTART_COMMUNICATIONS_OPTION:
if (getSubFunctionData() == 0xff00) {
commStatus.setClearLog(true);
}
commStatus.setRestartCommunicationsOption(true);
response.setSubFunctionData(getSubFunctionData());
break;
case RETURN_DIAGNOSTIC_REGISTER:
response.setSubFunctionData(commStatus.getDiagnosticRegister());
break;
case CHANGE_ASCII_INPUT_DELIMITER:
commStatus.setAsciiInputDelimiter((getSubFunctionData() >> 8) & 0xff);
response.setSubFunctionData(getSubFunctionData());
break;
case FORCE_LISTEN_ONLY_MODE:
commStatus.setListenOnlyMode(true);
break;
case CLEAR_COUNTERS_AND_DIAGNOSTIC_REGISTER:
commStatus.clearCountersAndDiagnosticRegister();
response.setSubFunctionData(getSubFunctionData());
break;
case RETURN_BUS_MESSAGE_COUNT:
response.setSubFunctionData(commStatus.getMessageCount());
break;
case RETURN_BUS_COMMUNICATION_ERROR_COUNT:
response.setSubFunctionData(commStatus.getCommunicationErrorCount());
break;
case RETURN_BUS_EXCEPTION_ERROR_COUNT:
response.setSubFunctionData(commStatus.getExceptionErrorCount());
break;
case RETURN_SLAVE_MESSAGE_COUNT:
response.setSubFunctionData(commStatus.getSlaveMessageCount());
break;
case RETURN_SLAVE_NO_RESPONSE_COUNT:
response.setSubFunctionData(commStatus.getSlaveNoResponseCount());
break;
case RETURN_SLAVE_NAK_COUNT:
response.setSubFunctionData(commStatus.getSlaveNAKCount());
break;
case RETURN_SLAVE_BUSY_COUNT:
response.setSubFunctionData(commStatus.getSlaveBusyCount());
break;
case RETURN_BUS_CHARACTER_OVERRUN_COUNT:
response.setSubFunctionData(commStatus.getCharacterOverrunCount());
break;
case CLEAR_OVERRUN_COUNTER_AND_FLAG:
commStatus.setCharacterOverrunCount(0);
response.setSubFunctionData(getSubFunctionData());
break;
case RESERVED:
break;
}
return response;
}
@Override
protected boolean validateResponseImpl(ModbusResponse response) {
DiagnosticsResponse r = (DiagnosticsResponse) response;
if (getSubFunctionCode() != r.getSubFunctionCode())
return false;
switch (subFunctionCode) {
case RETURN_QUERY_DATA:
case RESTART_COMMUNICATIONS_OPTION:
case CHANGE_ASCII_INPUT_DELIMITER:
case CLEAR_COUNTERS_AND_DIAGNOSTIC_REGISTER:
case CLEAR_OVERRUN_COUNTER_AND_FLAG:
return getSubFunctionData() == r.getSubFunctionData();
case FORCE_LISTEN_ONLY_MODE:
break;
case RETURN_DIAGNOSTIC_REGISTER:
break;
case RETURN_BUS_MESSAGE_COUNT:
break;
case RETURN_BUS_COMMUNICATION_ERROR_COUNT:
break;
case RETURN_BUS_EXCEPTION_ERROR_COUNT:
break;
case RETURN_SLAVE_MESSAGE_COUNT:
break;
case RETURN_SLAVE_NO_RESPONSE_COUNT:
break;
case RETURN_SLAVE_NAK_COUNT:
break;
case RETURN_SLAVE_BUSY_COUNT:
break;
case RETURN_BUS_CHARACTER_OVERRUN_COUNT:
break;
case RESERVED:
break;
}
return true;
}
@Override
public void readPDU(ModbusInputStream fifo) throws ModbusNumberException, IOException {
setSubFunctionCode(DiagnosticsSubFunctionCode.get(fifo.readShortBE()));
setSubFunctionData(fifo.readShortBE());
}
public int getSubFunctionData() {
return subFunctionData;
}
public void setSubFunctionData(int subFunctionData) {
this.subFunctionData = subFunctionData;
}
public DiagnosticsSubFunctionCode getSubFunctionCode() {
return subFunctionCode;
}
public void setSubFunctionCode(DiagnosticsSubFunctionCode subFunctionCode) {
this.subFunctionCode = subFunctionCode;
}
@Override
public int getFunction() {
return ModbusFunctionCode.DIAGNOSTICS.toInt();
}
}