whyclxw
2021-01-05 3eb8b438f1b5d6ffd8c13ce72b12f07a7a1dd6ed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
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: vladislav.kochedykov@gmail.com
 */
 
/**
 * 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();
    }
}