Skip to content

Commit 6008854

Browse files
committed
Add a "PVFactory" that supports Tango's protocol
1 parent 5040433 commit 6008854

File tree

6 files changed

+626
-1
lines changed

6 files changed

+626
-1
lines changed

core/pv/doc/index.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,3 +151,15 @@ Examples ::
151151

152152
sys://timeOffset(12 hours)
153153
sys://timeOffset(1hour, time, 1)
154+
155+
156+
Tango
157+
------
158+
Tango is different from EPICS, the smallest unit is Device, which includes the commands, states, and attributes.
159+
The command and the attribute has been implemented, add prefix to PV Name in editing interface to distinguish, and the command usually has a return value, so need to use *Text Entry* or a combination of *Action button* and *Text Update* components to achieve it.
160+
Currently, all types of scalars are supported, but SPECTRUM and IMAGE are not yet supported.
161+
162+
Examples ::
163+
164+
tango://att:/devicename/attributename
165+
tango://com:/devicename/comandname
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
package org.phoebus.pv.tango;
2+
3+
import fr.esrf.Tango.DevFailed;
4+
import fr.esrf.Tango.EventProperties;
5+
import fr.esrf.TangoApi.AttributeInfoEx;
6+
import fr.esrf.TangoApi.AttributeProxy;
7+
import fr.esrf.TangoApi.DeviceAttribute;
8+
import fr.soleil.tango.clientapi.TangoCommand;
9+
import org.epics.vtype.*;
10+
import org.phoebus.pv.PV;
11+
import org.tango.attribute.AttributeTangoType;
12+
import org.tango.command.CommandTangoType;
13+
import org.tango.server.events.EventType;
14+
15+
import java.util.concurrent.ConcurrentHashMap;
16+
import java.util.logging.Level;
17+
18+
;
19+
20+
public class TangoContext {
21+
private static TangoContext instance;
22+
private final ConcurrentHashMap<String, AttributeProxy> attributeProxys;
23+
private final ConcurrentHashMap<String, Integer> events;
24+
private final ConcurrentHashMap<String, AttributeTangoType> types;
25+
private final ConcurrentHashMap<String, TangoCommand> commands;
26+
27+
28+
private TangoContext() {
29+
events = new ConcurrentHashMap<>();
30+
attributeProxys = new ConcurrentHashMap<>();
31+
types = new ConcurrentHashMap<>();
32+
commands = new ConcurrentHashMap<>();
33+
}
34+
35+
public static synchronized TangoContext getInstance() throws Exception {
36+
if (instance == null)
37+
instance = new TangoContext();
38+
return instance;
39+
}
40+
41+
public void subscribeAttributeEvent(String deviceName, String attributeName, String baseName, Tango_PV pv) throws DevFailed {
42+
String name = deviceName +"/" + attributeName;
43+
AttributeProxy attributeProxy;
44+
if (attributeProxys.get(baseName) == null) {
45+
attributeProxy = new AttributeProxy(name);
46+
subscribeAttributeEvent(baseName, attributeProxy, pv);
47+
attributeProxys.put(baseName,attributeProxy);
48+
}else {
49+
//nothing to do
50+
}
51+
}
52+
53+
private void subscribeAttributeEvent(String baseName, AttributeProxy attributeProxy, Tango_PV pv) throws DevFailed {
54+
System.out.println("subscribe tango attribute : " + baseName);
55+
56+
AttributeInfoEx attribute_info_ex;
57+
try {
58+
attribute_info_ex = attributeProxy.get_info_ex();
59+
} catch (DevFailed e) {
60+
throw new RuntimeException(e);
61+
}
62+
63+
//obtain the type of attribute's value.
64+
AttributeTangoType type = AttributeTangoType.getTypeFromTango(attribute_info_ex.data_type);
65+
66+
types.putIfAbsent(baseName, type);
67+
68+
69+
//obtain the tango event type.
70+
EventType eventType = EventType.CHANGE_EVENT;
71+
EventProperties tangoObj = attribute_info_ex.events.getTangoObj();
72+
if (tangoObj.ch_event.abs_change.equals("Not specified") && tangoObj.ch_event.rel_change.equals("Not specified"))
73+
eventType = EventType.PERIODIC_EVENT;
74+
75+
//subscribe the tango event.
76+
int event_id;
77+
try {
78+
event_id = attributeProxy.subscribe_event(eventType.getValue(), pv.new TangoCallBack(type), new String[]{});
79+
} catch (DevFailed e) {
80+
throw new RuntimeException(e);
81+
}
82+
events.put(baseName, event_id);
83+
84+
}
85+
86+
public void unSubscribeAttributeEvent(String baseName) throws Exception {
87+
if (!attributeProxys.containsKey(baseName)){
88+
PV.logger.log(Level.WARNING, "Could not unsubscribe Tango attribute \"" + baseName
89+
+ "\" due to no Attribute Proxy.");
90+
throw new Exception("Tango attribute unsubscribe failed: no Attribute proxy connection.");
91+
}
92+
93+
AttributeProxy attributeProxy = attributeProxys.get(baseName);
94+
Integer event_id = events.get(baseName);
95+
if (event_id == null){
96+
PV.logger.log(Level.WARNING, "Could not unsubscribe Tango attribute \"" + baseName
97+
+ "\" due to no internal record of attribute");
98+
throw new Exception("Tango attribute unsubscribe failed: no attribute record.");
99+
}
100+
attributeProxy.getDeviceProxy().unsubscribe_event(event_id);
101+
attributeProxys.remove(baseName);
102+
events.remove(baseName);
103+
types.remove(baseName);
104+
}
105+
106+
107+
public void writeAttribute(String baseName, String attributeName, Object new_value) throws Exception {
108+
AttributeProxy attributeProxy = attributeProxys.get(baseName);
109+
AttributeTangoType type = types.get(baseName);
110+
if (type == null){
111+
PV.logger.log(Level.WARNING, "Could not find type of attribute :" + baseName);
112+
throw new Exception("Tango attribute write failed: attribute type not found.");
113+
}
114+
System.out.println("Tango attribute write: attribute:"+ attributeName + " value:" + new_value);
115+
VType vType;
116+
String value;
117+
switch (type){
118+
case DEVBOOLEAN:
119+
vType = TangoTypeUtil.convert(new_value, VBoolean.class);
120+
value = TangoTypeUtil.ToString(vType);
121+
attributeProxy.write(new DeviceAttribute(attributeName, Boolean.parseBoolean(value)));
122+
break;
123+
case DEVLONG64:
124+
case DEVULONG64:
125+
vType = TangoTypeUtil.convert(new_value, VLong.class);
126+
value = TangoTypeUtil.ToString(vType);
127+
attributeProxy.write(new DeviceAttribute(attributeName, Long.parseLong(value)));
128+
break;
129+
case DEVSHORT:
130+
case DEVUSHORT:
131+
vType = TangoTypeUtil.convert(new_value, VShort.class);
132+
value = TangoTypeUtil.ToString(vType);
133+
attributeProxy.write(new DeviceAttribute(attributeName, Short.parseShort(value)));
134+
break;
135+
case DEVLONG:
136+
case DEVULONG:
137+
vType = TangoTypeUtil.convert(new_value, VInt.class);
138+
value = TangoTypeUtil.ToString(vType);
139+
attributeProxy.write(new DeviceAttribute(attributeName, Integer.parseInt(value)));
140+
break;
141+
case DEVFLOAT:
142+
vType = TangoTypeUtil.convert(new_value, VFloat.class);
143+
value = TangoTypeUtil.ToString(vType);
144+
attributeProxy.write(new DeviceAttribute(attributeName, Float.parseFloat(value)));
145+
break;
146+
case DEVDOUBLE:
147+
vType = TangoTypeUtil.convert(new_value, VDouble.class);
148+
value = TangoTypeUtil.ToString(vType);
149+
attributeProxy.write(new DeviceAttribute(attributeName, Double.parseDouble(value)));
150+
break;
151+
case DEVSTRING:
152+
vType = TangoTypeUtil.convert(new_value, VString.class);
153+
value = TangoTypeUtil.ToString(vType);
154+
attributeProxy.write(new DeviceAttribute(attributeName, value));
155+
break;
156+
case DEVUCHAR:
157+
vType = TangoTypeUtil.convert(new_value, VByte.class);
158+
value = TangoTypeUtil.ToString(vType);
159+
attributeProxy.write(new DeviceAttribute(attributeName, Byte.parseByte(value)));
160+
break;
161+
default:
162+
throw new IllegalArgumentException("Value " + new_value + " cannot be converted.");
163+
}
164+
165+
}
166+
167+
168+
public void createTangoCommand(String deviceName, String commandName, String baseName, Tango_PV pv) throws DevFailed {
169+
TangoCommand tangoCommand = commands.get(baseName);
170+
if ( tangoCommand == null ){
171+
tangoCommand = new TangoCommand(deviceName, commandName);
172+
commands.put(baseName, tangoCommand);
173+
}
174+
pv.StartCommand(tangoCommand.getCommandName());
175+
}
176+
177+
public void removeTangoCommand(String baseName) throws Exception {
178+
TangoCommand tangoCommand = commands.get(baseName);
179+
if (tangoCommand == null){
180+
PV.logger.log(Level.WARNING, "Could not remove Tango command \"" + baseName
181+
+ "\" due to no internal record of command");
182+
throw new Exception("Tango command remove failed: no command record.");
183+
}
184+
commands.remove(baseName, tangoCommand);
185+
}
186+
187+
public void executeTangoCommand(String baseName, Object new_value, Tango_PV pv) throws Exception {
188+
TangoCommand tangoCommand = commands.get(baseName);
189+
if (tangoCommand == null){
190+
PV.logger.log(Level.WARNING, "Could not find Tango command \"" + baseName
191+
+ "\" due to no internal record of command");
192+
throw new Exception("Tango command execute failed: no command record.");
193+
}
194+
195+
CommandTangoType typeFromTango = CommandTangoType.getTypeFromTango(tangoCommand.getArginType());
196+
Object res;
197+
VType value;
198+
switch (typeFromTango){
199+
case DEVBOOLEAN:
200+
res = tangoCommand.execute(Boolean.class, new_value);
201+
value = TangoTypeUtil.convert(res, VBoolean.class);
202+
pv.endCommand(value);
203+
break;
204+
case DEVSHORT:
205+
res = tangoCommand.execute(Short.class, new_value);
206+
value = TangoTypeUtil.convert(res, VShort.class);
207+
pv.endCommand(value);
208+
break;
209+
case DEVLONG64:
210+
res = tangoCommand.execute(Long.class, new_value);
211+
value = TangoTypeUtil.convert(res, VLong.class);
212+
pv.endCommand(value);
213+
break;
214+
case DEVFLOAT:
215+
res = tangoCommand.execute(Float.class, new_value);
216+
value = TangoTypeUtil.convert(res, VFloat.class);
217+
pv.endCommand(value);
218+
break;
219+
case DEVDOUBLE:
220+
res = tangoCommand.execute(Double.class,new_value);
221+
value = TangoTypeUtil.convert(res, VDouble.class);
222+
pv.endCommand(value);
223+
break;
224+
case DEVSTRING:
225+
res = tangoCommand.execute(String.class,new_value);
226+
value = TangoTypeUtil.convert(res, VString.class);
227+
pv.endCommand(value);
228+
break;
229+
case DEVLONG:
230+
res = tangoCommand.execute(Integer.class,new_value);
231+
value = TangoTypeUtil.convert(res, VInt.class);
232+
pv.endCommand(value);
233+
break;
234+
case DEVUCHAR:
235+
res = tangoCommand.execute(Byte.class,new_value);
236+
value = TangoTypeUtil.convert(res, VByte.class);
237+
pv.endCommand(value);
238+
break;
239+
default:
240+
throw new IllegalArgumentException("Value " + new_value + " cannot be converted.");
241+
}
242+
243+
244+
245+
}
246+
}

0 commit comments

Comments
 (0)