Skip to content

Commit f29d82c

Browse files
authored
Merge pull request #2431 from ControlSystemStudio/pva_errorhandling
PVA error handling
2 parents 8fa899b + e025066 commit f29d82c

File tree

6 files changed

+99
-14
lines changed

6 files changed

+99
-14
lines changed

core/pv/src/main/java/org/phoebus/pv/pva/PVA_PV.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,27 @@ public VType get(final long timeout, final TimeUnit unit)
164164
@Override
165165
public void write(final Object new_value) throws Exception
166166
{
167+
// With Channel Access, there are different protocol options
168+
// for "put" vs. "put-callback".
169+
// With PVA, it is currently unclear how to distinguish between
170+
// these two. The PVA server might honor certain values in the
171+
// "request", but that is not documented as part of the protocol.
172+
// On one hand, we should 'get()' the result of the write to
173+
// receive exceptions for read-only PVs.
174+
// On the other hand, such a 'get()' could last a long time
175+
// in case some detail in the 'request' caused the PVA server
176+
// to perform a put-callback type of operation,
177+
// and a GUI calling write() expect an immediate return.
178+
179+
// Perform a disconnect check right now to alert caller
180+
// of clearly disconnected channel
181+
if (isDisconnected(read()))
182+
throw new IllegalStateException("Channel '" + getName() + "' is not connected");
183+
184+
// The channel could still disconnect in the middle of the write,
185+
// the channel may be read-only or experience other errors
186+
// that we'll only see as log messages since we don't want to
187+
// wait in 'get()' here...
167188
channel.write(name_helper.getWriteRequest(), new_value);
168189
}
169190

core/pva/src/main/java/org/epics/pva/client/GetRequest.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2019 Oak Ridge National Laboratory.
2+
* Copyright (c) 2019-2022 Oak Ridge National Laboratory.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -104,7 +104,7 @@ public void handleResponse(final ByteBuffer buffer) throws Exception
104104
final byte subcmd = buffer.get();
105105
PVAStatus status = PVAStatus.decode(buffer);
106106
if (! status.isSuccess())
107-
throw new Exception(channel + " Get Response for " + request + ": " + status);
107+
fail(new Exception(channel + " Get Response for " + request + ": " + status));
108108

109109
if (subcmd == PVAHeader.CMD_SUB_INIT)
110110
{
@@ -147,6 +147,12 @@ public void handleResponse(final ByteBuffer buffer) throws Exception
147147
}
148148
}
149149

150+
/** Handle failure by both notifying whoever waits for this request to complete
151+
* and by throwing exception
152+
*
153+
* @param ex Error description
154+
* @throws Exception
155+
*/
150156
private void fail(final Exception ex) throws Exception
151157
{
152158
completeExceptionally(ex);

core/pva/src/main/java/org/epics/pva/client/PVAChannel.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,12 @@ PVAClient getClient()
8686
ClientTCPHandler getTCP() throws Exception
8787
{
8888
final ClientTCPHandler copy = tcp.get();
89+
90+
// Channel Access reacts to read/write access while disconnected
91+
// via IllegalStateException("Channel not connected.")
92+
// Use the same exception, but add channel name
8993
if (copy == null)
90-
throw new Exception("Channel '" + name + "' is not connected");
94+
throw new IllegalStateException("Channel '" + name + "' is not connected");
9195
return copy;
9296
}
9397

core/pva/src/main/java/org/epics/pva/client/PutRequest.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2019-2020 Oak Ridge National Laboratory.
2+
* Copyright (c) 2019-2022 Oak Ridge National Laboratory.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -151,9 +151,17 @@ public void handleResponse(final ByteBuffer buffer) throws Exception
151151
fail(new Exception("Incomplete Put Response"));
152152
final int request_id = buffer.getInt();
153153
final byte subcmd = buffer.get();
154-
PVAStatus status = PVAStatus.decode(buffer);
154+
final PVAStatus status = PVAStatus.decode(buffer);
155155
if (! status.isSuccess())
156-
throw new Exception(channel + " Put Response for " + request + ": " + status);
156+
{
157+
// Server reported an error with text like "Put not permitted"
158+
// for EPICS 7.0.6 QSRV.
159+
// Channel access similarly provided an Exception with text
160+
// "No write access rights granted."
161+
// Not trying to parse the message; passing it up with added
162+
// channel name and request info.
163+
fail(new Exception(channel + " Write for '" + channel.getName() + "' " + request + " failed with " + status));
164+
}
157165

158166
if (subcmd == PVAHeader.CMD_SUB_INIT)
159167
{
@@ -186,9 +194,15 @@ else if (subcmd == PVAHeader.CMD_SUB_DESTROY)
186194
complete(null);
187195
}
188196
else
189-
throw new Exception("Cannot decode Put " + subcmd + " Reply #" + request_id);
197+
fail(new Exception("Cannot decode Put " + subcmd + " Reply #" + request_id));
190198
}
191199

200+
/** Handle failure by both notifying whoever waits for this request to complete
201+
* and by throwing exception
202+
*
203+
* @param ex Error description
204+
* @throws Exception
205+
*/
192206
private void fail(final Exception ex) throws Exception
193207
{
194208
completeExceptionally(ex);

core/pva/src/test/java/org/epics/pva/client/ClientDemo.java

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2019-2020 Oak Ridge National Laboratory.
2+
* Copyright (c) 2019-2022 Oak Ridge National Laboratory.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -94,12 +94,23 @@ public void testGet() throws Exception
9494
final PVAChannel ch2 = pva.getChannel("saw", listener);
9595
CompletableFuture.allOf(ch1.connect(), ch2.connect()).get(5, TimeUnit.SECONDS);
9696

97+
System.out.println("Connected.. Stop IOC in next 10 seconds to test disconnect");
98+
TimeUnit.SECONDS.sleep(10);
99+
97100
// Get data
98-
Future<PVAStructure> data = ch1.read("");
99-
System.out.println(ch1.getName() + " = " + data.get());
101+
try
102+
{
103+
Future<PVAStructure> data = ch1.read("");
104+
System.out.println(ch1.getName() + " = " + data.get());
100105

101-
data = ch2.read("");
102-
System.out.println(ch2.getName() + " = " + data.get());
106+
data = ch2.read("");
107+
System.out.println(ch2.getName() + " = " + data.get());
108+
}
109+
catch (Exception ex)
110+
{
111+
System.out.println("Read failed");
112+
ex.printStackTrace();
113+
}
103114

104115
// Close channels
105116
ch2.close();
@@ -263,18 +274,39 @@ public void testStatic() throws Exception
263274
pva.close();
264275
}
265276

277+
/** Write ('put') test
278+
*
279+
* Includes a pause to allow manual stopping of the server.
280+
*
281+
* May be used with read-only access security on IOC
282+
* to test failed write.
283+
*/
266284
@Test
267285
public void testPut() throws Exception
268286
{
269287
// Create a client
270288
final PVAClient pva = new PVAClient();
271289

272290
// Connect to one or more channels
273-
final PVAChannel channel = pva.getChannel("ramp");
291+
final PVAChannel channel = pva.getChannel("saw");
274292
channel.connect().get(5, TimeUnit.SECONDS);
275293

294+
295+
System.out.println("CONNECTED!");
296+
System.out.println("Optionally stop the IOC within the next 10 seconds...");
297+
TimeUnit.SECONDS.sleep(10);
298+
System.out.println("Writing '2'...");
299+
276300
// Write data
277-
channel.write("value", 2.0).get(2, TimeUnit.SECONDS);
301+
try
302+
{
303+
channel.write("value", 2.0).get(2, TimeUnit.SECONDS);
304+
}
305+
catch (Exception ex)
306+
{
307+
System.out.println("Write failed");
308+
ex.printStackTrace();
309+
}
278310

279311
// Close channels
280312
channel.close();
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Test read-only PVs:
2+
#
3+
# softIocPVA -m N='' -d demo.db -a demo.acf
4+
5+
ASG(DEFAULT)
6+
{
7+
RULE(1, READ)
8+
}

0 commit comments

Comments
 (0)