Skip to content

Commit 5dface5

Browse files
authored
Merge pull request #2309 from ControlSystemStudio/alarm_disable_fix
Fix disabled/delayed/filtered/shelved alarms
2 parents 40d2c10 + f8d2e0d commit 5dface5

File tree

7 files changed

+80
-66
lines changed

7 files changed

+80
-66
lines changed

app/alarm/Readme.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ kafka in `/opt/kafka`.
2424
# that can be used with a kafka server in the same directory
2525
cd examples
2626

27-
# Use wget, 'curl -O', or web browser
28-
wget http://ftp.wayne.edu/apache/kafka/2.3.0/kafka_2.12-2.3.0.tgz
29-
tar -vzxf kafka_2.12-2.3.0.tgz
30-
ln -s kafka_2.12-2.3.0 kafka
27+
# Use wget, 'curl -O', or web browser to fetch a recent version of kafka
28+
wget https://dlcdn.apache.org/kafka/3.2.0/kafka_2.13-3.2.0.tgz
29+
tar -vzxf kafka_2.13-3.2.0.tgz
30+
ln -s kafka_2.13-3.2.0 kafka
3131

3232
Check `config/zookeeper.properties` and `config/server.properties`.
3333
By default these contain settings for keeping data in `/tmp/`, which works for initial tests,
@@ -45,11 +45,11 @@ Similarly, change the directory setting in `server.properties`
4545
log.dirs=/tmp/kafka-logs
4646

4747

48-
Kafka depends on Zookeeper. By default, Kafka will quit if it cannot connect to Zookeeper within 6 seconds.
49-
When the Linux host boots up, this may not be long enough to allow Zookeeper to start.
48+
Kafka depends on Zookeeper. Kafka will quit if it cannot connect to Zookeeper within some timeout.
49+
When the Linux host boots up, the default timeout may not be long enough to allow Zookeeper to start.
5050

51-
# Timeout in ms for connecting to zookeeper defaults to 6000ms.
52-
# Suggest a much longer time (5 minutes)
51+
# Timeout in ms for connecting to zookeeper
52+
# Suggest about 5 minutes
5353
zookeeper.connection.timeout.ms=300000
5454

5555
By default, Kafka will automatically create topics.
@@ -66,6 +66,7 @@ If the following "First steps" generate errors of the type
6666

6767
WARN Error while fetching metadata with correlation id 39 : .. LEADER_NOT_AVAILABLE
6868
or
69+
6970
ERROR ..TimeoutException: Timed out waiting for a node assignment
7071

7172
then define the host name in `config/server.properties`.

app/alarm/ui/src/main/java/org/phoebus/applications/alarm/ui/tree/AlarmTreeView.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2018-2020 Oak Ridge National Laboratory.
2+
* Copyright (c) 2018-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
@@ -22,7 +22,6 @@
2222
import java.util.logging.Level;
2323
import java.util.stream.Collectors;
2424

25-
import javafx.scene.image.ImageView;
2625
import org.phoebus.applications.alarm.client.AlarmClient;
2726
import org.phoebus.applications.alarm.client.AlarmClientLeaf;
2827
import org.phoebus.applications.alarm.client.AlarmClientListener;
@@ -62,6 +61,7 @@
6261
import javafx.scene.control.Tooltip;
6362
import javafx.scene.control.TreeItem;
6463
import javafx.scene.control.TreeView;
64+
import javafx.scene.image.ImageView;
6565
import javafx.scene.input.ClipboardContent;
6666
import javafx.scene.input.Dragboard;
6767
import javafx.scene.input.TransferMode;
@@ -493,7 +493,7 @@ private void addClickSupport()
493493

494494
final AlarmTreeItem<?> item = tree_view.getSelectionModel().getSelectedItems().get(0).getValue();
495495
final ItemConfigDialog dialog = new ItemConfigDialog(model, item);
496-
DialogHelper.positionDialog(dialog, tree_view, -250, -400);
496+
DialogHelper.positionDialog(dialog, tree_view, -150, -300);
497497
// Show dialog, not waiting for it to close with OK or Cancel
498498
dialog.show();
499499
});

app/alarm/ui/src/main/java/org/phoebus/applications/alarm/ui/tree/ConfigureComponentAction.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2018 Oak Ridge National Laboratory.
2+
* Copyright (c) 2018-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
@@ -33,7 +33,7 @@ public ConfigureComponentAction(final Node node, final AlarmClient model, final
3333
setOnAction(event -> Platform.runLater(() ->
3434
{
3535
final ItemConfigDialog dialog = new ItemConfigDialog(model, item);
36-
DialogHelper.positionDialog(dialog, node, -250, -400);
36+
DialogHelper.positionDialog(dialog, node, -150, -300);
3737
// Show dialog, not waiting for it to close with OK or Cancel
3838
dialog.show();
3939
}));

app/alarm/ui/src/main/java/org/phoebus/applications/alarm/ui/tree/ItemConfigDialog.java

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import javafx.beans.value.ChangeListener;
2525
import javafx.event.ActionEvent;
2626
import javafx.event.EventHandler;
27+
import javafx.geometry.Pos;
2728
import javafx.scene.control.Button;
2829
import javafx.scene.control.ButtonType;
2930
import javafx.scene.control.CheckBox;
@@ -34,6 +35,7 @@
3435
import javafx.scene.control.Spinner;
3536
import javafx.scene.control.TextField;
3637
import javafx.scene.control.Tooltip;
38+
import javafx.scene.layout.ColumnConstraints;
3739
import javafx.scene.layout.GridPane;
3840
import javafx.scene.layout.HBox;
3941
import javafx.scene.layout.Priority;
@@ -69,6 +71,13 @@ public ItemConfigDialog(final AlarmClient model, final AlarmTreeItem<?> item)
6971
layout.setHgap(5);
7072
layout.setVgap(5);
7173

74+
// First fixed-size column for labels
75+
// Second column grows
76+
final ColumnConstraints col1 = new ColumnConstraints(190);
77+
final ColumnConstraints col2 = new ColumnConstraints();
78+
col2.setHgrow(Priority.ALWAYS);
79+
layout.getColumnConstraints().setAll(col1, col2);
80+
7281
int row = 0;
7382

7483
// Show item path, allow copying it out.
@@ -90,9 +99,10 @@ public ItemConfigDialog(final AlarmClient model, final AlarmTreeItem<?> item)
9099

91100
layout.add(new Label("Behavior:"), 0, row);
92101
enabled = new CheckBox("Enabled");
93-
enabled.setTooltip(new Tooltip("Enable alarms? See also filter expression"));
102+
enabled.setTooltip(new Tooltip("Enable alarms? See also 'Enabling Filter'"));
94103
enabled.setSelected(leaf.isEnabled());
95-
enabled.setOnAction((event) -> {
104+
enabled.setOnAction((event) ->
105+
{
96106
relative_date.getSelectionModel().clearSelection();
97107
relative_date.setValue(null);
98108
enabled_date_picker.getEditor().clear();
@@ -112,34 +122,41 @@ public ItemConfigDialog(final AlarmClient model, final AlarmTreeItem<?> item)
112122

113123
layout.add(new Label("Disable until:"), 0, row);
114124
enabled_date_picker = new DateTimePicker();
125+
enabled_date_picker.setTooltip(new Tooltip("Select a date until which the alarm should be disabled"));
115126
enabled_date_picker.setDateTimeValue(leaf.getEnabledDate());
127+
enabled_date_picker.setPrefSize(280, 25);
128+
116129
relative_date = new ComboBox<String>();
130+
relative_date.setTooltip(new Tooltip("Select a predefined duration for disabling the alarm"));
117131
relative_date.getItems().addAll(AlarmSystem.shelving_options);
132+
relative_date.setPrefSize(200, 25);
118133

119-
final EventHandler<ActionEvent> relative_event_handler = new EventHandler<>() {
120-
@Override public void handle(ActionEvent e) {
121-
enabled.setSelected(false);
122-
enabled_date_picker.getEditor().clear();
123-
}
134+
final EventHandler<ActionEvent> relative_event_handler = (ActionEvent e) ->
135+
{
136+
enabled.setSelected(false);
137+
enabled_date_picker.getEditor().clear();
124138
};
125139

126140
relative_date.setOnAction(relative_event_handler);
127141

128142
// setOnAction for relative date must be set to null as to not trigger event when setting value
129-
enabled_date_picker.setOnAction(new EventHandler<ActionEvent>() {
130-
@Override public void handle(ActionEvent e) {
131-
if (enabled_date_picker.getDateTimeValue() != null) {
132-
relative_date.setOnAction(null);
133-
enabled.setSelected(false);
134-
enabled_date_picker.getEditor().commitValue();
135-
relative_date.getSelectionModel().clearSelection();
136-
relative_date.setValue(null);
137-
relative_date.setOnAction(relative_event_handler);
138-
};
139-
}
143+
enabled_date_picker.setOnAction((ActionEvent e) ->
144+
{
145+
if (enabled_date_picker.getDateTimeValue() != null)
146+
{
147+
relative_date.setOnAction(null);
148+
enabled.setSelected(false);
149+
enabled_date_picker.getEditor().commitValue();
150+
relative_date.getSelectionModel().clearSelection();
151+
relative_date.setValue(null);
152+
relative_date.setOnAction(relative_event_handler);
153+
};
140154
});
141155

142-
layout.add(new HBox(10, enabled_date_picker, relative_date), 1, row++);
156+
final HBox until_box = new HBox(10, enabled_date_picker, relative_date);
157+
until_box.setAlignment(Pos.CENTER);
158+
HBox.setHgrow(relative_date, Priority.ALWAYS);
159+
layout.add(until_box, 1, row++);
143160

144161
layout.add(new Label("Alarm Delay [seconds]:"), 0, row);
145162
delay = new Spinner<>(0, Integer.MAX_VALUE, leaf.getDelay());
@@ -170,7 +187,7 @@ public ItemConfigDialog(final AlarmClient model, final AlarmTreeItem<?> item)
170187
count.setPrefWidth(80);
171188
layout.add(count, 1, row++);
172189

173-
layout.add(new Label("Enabling Filter"), 0, row);
190+
layout.add(new Label("Enabling Filter:"), 0, row);
174191
filter = new TextField(leaf.getFilter());
175192
filter.setTooltip(new Tooltip("Optional expression for enabling the alarm"));
176193
layout.add(filter, 1, row++);
@@ -201,28 +218,25 @@ public ItemConfigDialog(final AlarmClient model, final AlarmTreeItem<?> item)
201218
// 'dummy' is used for that.
202219

203220
// Guidance:
204-
layout.add(new Label("Guidance:"), 0, row);
205-
final Label dummy = new Label("");
206-
GridPane.setHgrow(dummy, Priority.ALWAYS);
207-
layout.add(dummy, 1, row++);
221+
layout.add(new Label("Guidance:"), 0, row++, 2, 1);
208222
guidance = new TitleDetailTable(item.getGuidance());
209223
guidance.setPrefHeight(100);
210224
layout.add(guidance, 0, row++, 2, 1);
211225

212226
// Displays:
213-
layout.add(new Label("Displays:"), 0, row++);
227+
layout.add(new Label("Displays:"), 0, row++, 2, 1);
214228
displays = new TitleDetailTable(item.getDisplays());
215229
displays.setPrefHeight(100);
216230
layout.add(displays, 0, row++, 2, 1);
217231

218232
// Commands:
219-
layout.add(new Label("Commands:"), 0, row++);
233+
layout.add(new Label("Commands:"), 0, row++, 2, 1);
220234
commands = new TitleDetailTable(item.getCommands());
221235
commands.setPrefHeight(100);
222236
layout.add(commands, 0, row++, 2, 1);
223237

224238
// Automated Actions:
225-
layout.add(new Label("Automated Actions:"), 0, row++);
239+
layout.add(new Label("Automated Actions:"), 0, row++, 2, 1);
226240
actions = new TitleDetailDelayTable(item.getActions());
227241
actions.setPrefHeight(100);
228242
layout.add(actions, 0, row++, 2, 1);
@@ -231,9 +245,9 @@ public ItemConfigDialog(final AlarmClient model, final AlarmTreeItem<?> item)
231245
final ScrollPane scroll = new ScrollPane(layout);
232246

233247
// Scroll pane stops the content from resizing,
234-
// so tell content to use the widths of the scroll pane,
235-
// minus some border, and suggest minimum width
236-
scroll.widthProperty().addListener((p, old, width) -> layout.setPrefWidth(Math.max(width.doubleValue()-25, 450)));
248+
// so tell content to use the widths of the scroll pane
249+
// minus 40 to provide space for the scroll bar, and suggest minimum width
250+
scroll.widthProperty().addListener((p, old, width) -> layout.setPrefWidth(Math.max(width.doubleValue()-40, 450)));
237251

238252
getDialogPane().setContent(scroll);
239253
setResizable(true);

services/alarm-server/src/main/java/org/phoebus/applications/alarm/server/AlarmLogic.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public class AlarmLogic // implements GlobalAlarmListener
6161
/** 'Current' state that was received while disabled.
6262
* Is cached in case we get re-enabled, whereupon it is used
6363
*/
64-
private volatile AlarmState disabled_state = null;
64+
private final AtomicReference<AlarmState> disabled_state = new AtomicReference<>();
6565

6666
/** Latch the highest received alarm severity/status?
6767
* When <code>false</code>, the latched alarm state actually
@@ -189,7 +189,7 @@ public boolean setEnabled(final boolean enable)
189189
if (!enable)
190190
{ // Disabled
191191
// Remember current PV state in case we're re-enabled
192-
disabled_state = current_state;
192+
disabled_state.set(current_state);
193193
// Otherwise pretend all is OK, using special message
194194

195195
final AlarmState current = AlarmState.createClearState(current_state.value);
@@ -205,11 +205,9 @@ public boolean setEnabled(final boolean enable)
205205
alarm_state = new AlarmState(SeverityLevel.OK,
206206
SeverityLevel.OK.name(), "", Instant.now());
207207
// (Re-)enabled
208-
if (disabled_state != null)
209-
{
210-
computeNewState(disabled_state);
211-
disabled_state = null;
212-
}
208+
final AlarmState saved_state = disabled_state.getAndSet(null);
209+
if (saved_state != null)
210+
computeNewState(saved_state);
213211
}
214212
return true;
215213
}
@@ -321,7 +319,7 @@ public void computeNewState(final AlarmState received_state)
321319
// When disabled, ignore...
322320
if (!enabled.get())
323321
{
324-
disabled_state = received_state;
322+
disabled_state.set(received_state);
325323
return;
326324
}
327325
// Remember what used to be the 'current' severity
@@ -590,6 +588,10 @@ public void acknowledge(boolean acknowledge)
590588
*/
591589
public void dispose()
592590
{
591+
// Indicate that PV has been disposed, but call it OK.
592+
// This way a re-started PV which then receives its first update will take
593+
// any non-OK state as a change and react accordingly
594+
current_state = alarm_state = new AlarmState(SeverityLevel.OK, "Disposed", "Disposed", Instant.now());
593595
delayed_check.cancel();
594596
}
595597

services/alarm-server/src/main/java/org/phoebus/applications/alarm/server/AlarmServerPV.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@
2525
import org.phoebus.applications.alarm.Messages;
2626
import org.phoebus.applications.alarm.client.ClientState;
2727
import org.phoebus.applications.alarm.model.AlarmState;
28-
import org.phoebus.applications.alarm.model.EnabledState;
2928
import org.phoebus.applications.alarm.model.AlarmTreeItem;
3029
import org.phoebus.applications.alarm.model.AlarmTreeLeaf;
30+
import org.phoebus.applications.alarm.model.EnabledState;
3131
import org.phoebus.applications.alarm.model.SeverityLevel;
3232
import org.phoebus.applications.alarm.model.TitleDetailDelay;
3333
import org.phoebus.applications.alarm.server.actions.AutomatedActions;
@@ -59,6 +59,8 @@ public class AlarmServerPV extends AlarmTreeItem<AlarmState> implements AlarmTre
5959
return thread;
6060
});
6161

62+
private final ServerModel model;
63+
6264
private volatile String description = "";
6365

6466
private final AlarmLogic logic;
@@ -84,6 +86,7 @@ public class AlarmServerPV extends AlarmTreeItem<AlarmState> implements AlarmTre
8486
public AlarmServerPV(final ServerModel model, final String parent_path, final String name, final ClientState initial)
8587
{
8688
super(parent_path, name, Collections.emptyList());
89+
this.model = model;
8790
description = name;
8891

8992
final AlarmState current_state;
@@ -123,12 +126,6 @@ public void annunciateAlarm(final SeverityLevel severity)
123126
{
124127
model.sendAnnunciatorMessage(getPathName(), severity, description);
125128
}
126-
@Override
127-
public void alarmEnablementChanged(boolean enable) {
128-
model.sendConfigUpdate(getPathName(), AlarmServerPV.this);
129-
}
130-
131-
132129
};
133130
logic = new AlarmLogic(listener, true, true, 0, 0, current_state, alarm_state, 0);
134131
}
@@ -416,8 +413,12 @@ private void filterChanged(final double value)
416413
private void enabledDateTimeFilterChanged(final boolean enabled)
417414
{
418415
setEnabled(enabled);
419-
}
420416

417+
// Alarm server should _listen_ to config changes, not send them, with one exception:
418+
// If a 'shelved' alarm gets re-enabled by the alarm server, it sends that out
419+
if (enabled)
420+
model.sendConfigUpdate(getPathName(), this);
421+
}
421422

422423
public void stop()
423424
{

services/alarm-server/src/main/java/org/phoebus/applications/alarm/server/EnabledDateTimeFilter.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,14 @@
77
******************************************************************************/
88
package org.phoebus.applications.alarm.server;
99

10-
import static org.phoebus.applications.alarm.AlarmSystem.logger;
11-
12-
import org.phoebus.applications.alarm.client.AlarmClient;
13-
10+
import java.time.Duration;
11+
import java.time.LocalDateTime;
12+
import java.time.format.DateTimeFormatter;
1413
import java.util.concurrent.Executors;
1514
import java.util.concurrent.ScheduledExecutorService;
1615
import java.util.concurrent.ScheduledFuture;
1716
import java.util.concurrent.TimeUnit;
1817
import java.util.function.Consumer;
19-
import java.time.LocalDateTime;
20-
import java.time.Duration;
21-
import java.time.format.DateTimeFormatter;
2218

2319
import org.phoebus.framework.jobs.NamedThreadFactory;
2420

0 commit comments

Comments
 (0)