Skip to content

Commit b802d1b

Browse files
committed
Adding support for most types
1 parent a8e83fc commit b802d1b

7 files changed

Lines changed: 748 additions & 1 deletion

File tree

gpclient/gpclient-ca/src/main/java/org/epics/gpclient/datasource/ca/CADataSource.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44
*/
55
package org.epics.gpclient.datasource.ca;
66

7-
import java.util.concurrent.Executors;
87
import java.util.logging.Level;
98
import java.util.logging.Logger;
109

1110
import org.epics.gpclient.datasource.ChannelHandler;
1211
import org.epics.gpclient.datasource.DataSource;
12+
import org.epics.gpclient.datasource.ca.types.CATypeSupport;
13+
import org.epics.gpclient.datasource.ca.types.CAVTypeAdapterSet;
1314

1415
import com.cosylab.epics.caj.CAJContext;
1516

@@ -99,4 +100,9 @@ protected ChannelHandler createChannel(String channelName) {
99100
return new CAChannelHandler(channelName, this);
100101
}
101102

103+
@Override
104+
public void close() {
105+
context.dispose();
106+
}
107+
102108
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/**
2+
* Copyright information and license terms for this software can be
3+
* found in the file LICENSE.TXT included with the distribution.
4+
*/
5+
package org.epics.gpclient.datasource.ca.types;
6+
7+
import java.text.NumberFormat;
8+
import java.time.Instant;
9+
import java.time.temporal.ChronoUnit;
10+
11+
import org.epics.util.text.NumberFormats;
12+
import org.epics.vtype.Alarm;
13+
import org.epics.vtype.AlarmSeverity;
14+
import org.epics.vtype.AlarmStatus;
15+
import org.epics.vtype.Time;
16+
17+
import gov.aps.jca.dbr.DBR;
18+
import gov.aps.jca.dbr.DBR_CTRL_Double;
19+
import gov.aps.jca.dbr.PRECISION;
20+
import gov.aps.jca.dbr.Severity;
21+
import gov.aps.jca.dbr.TimeStamp;
22+
23+
public class CADataUtils {
24+
25+
/**
26+
* Converts an alarm severity from JCA to {@link Alarm}.
27+
*
28+
* @param severity the JCA severity
29+
* @return the VData severity
30+
*/
31+
public static Alarm fromEpics(Severity severity) {
32+
33+
if (Severity.NO_ALARM.isEqualTo(severity)) {
34+
return Alarm.none();
35+
} else if (Severity.MINOR_ALARM.isEqualTo(severity)) {
36+
return Alarm.of(AlarmSeverity.MINOR, AlarmStatus.RECORD, "");
37+
} else if (Severity.MAJOR_ALARM.isEqualTo(severity)) {
38+
return Alarm.of(AlarmSeverity.MAJOR, AlarmStatus.RECORD, "");
39+
} else if (Severity.INVALID_ALARM.isEqualTo(severity)) {
40+
return Alarm.of(AlarmSeverity.INVALID, AlarmStatus.RECORD, "");
41+
} else {
42+
return Alarm.of(AlarmSeverity.UNDEFINED, AlarmStatus.UNDEFINED, "");
43+
}
44+
}
45+
/**
46+
* Constant to convert epics seconds to UNIX seconds. It counts the number
47+
* of seconds for 20 years, 5 of which leap years. It does _not_ count the
48+
* number of leap seconds (which should have been 15).
49+
*/
50+
static long TS_EPOCH_SEC_PAST_1970=631152000; //7305*86400;
51+
52+
/**
53+
* Converts a JCA timestamp to an epics.util timestamp.
54+
*
55+
* @param timeStamp the epics timestamp
56+
* @return a new epics.util timestamp
57+
*/
58+
public static Time timestampOf(TimeStamp timeStamp) {
59+
if (timeStamp == null)
60+
return null;
61+
return Time.of(Instant.ofEpochSecond(timeStamp.secPastEpoch() + TS_EPOCH_SEC_PAST_1970, 0)
62+
.plus(timeStamp.nsec(), ChronoUnit.NANOS));
63+
}
64+
65+
public static NumberFormat getFormat(DBR metadata, boolean honorZeroPrecision) {
66+
int precision = -1;
67+
if (metadata instanceof PRECISION) {
68+
precision = ((PRECISION) metadata).getPrecision();
69+
}
70+
71+
// If precision is 0 or less, we assume full precision
72+
if (precision < 0) {
73+
return NumberFormats.toStringFormat();
74+
} else if (precision == 0) {
75+
if (honorZeroPrecision) {
76+
return NumberFormats.precisionFormat(0);
77+
} else {
78+
return NumberFormats.toStringFormat();
79+
}
80+
} else {
81+
return NumberFormats.precisionFormat(precision);
82+
}
83+
}
84+
85+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/**
2+
* Copyright information and license terms for this software can be
3+
* found in the file LICENSE.TXT included with the distribution.
4+
*/
5+
package org.epics.gpclient.datasource.ca.types;
6+
7+
8+
import org.epics.gpclient.ReadCollector;
9+
import org.epics.gpclient.datasource.DataSourceTypeAdapter;
10+
import org.epics.gpclient.datasource.ca.CAConnectionPayload;
11+
import org.epics.gpclient.datasource.ca.CAMessagePayload;
12+
13+
import gov.aps.jca.Channel;
14+
import gov.aps.jca.dbr.DBR;
15+
import gov.aps.jca.dbr.DBRType;
16+
17+
abstract public class CATypeAdapter implements DataSourceTypeAdapter<CAConnectionPayload, CAMessagePayload> {
18+
19+
private final Class<?> typeClass;
20+
private final DBRType epicsValueType;
21+
private final DBRType epicsMetaType;
22+
private final Boolean array;
23+
24+
/**
25+
* Creates a new type adapter.
26+
*
27+
* @param typeClass the java type this adapter will create
28+
* @param epicsValueType the epics type used for the monitor
29+
* @param epicsMetaType the epics type for the get at connection time; null if no metadata is needed
30+
* @param array true whether this will require an array type
31+
*/
32+
public CATypeAdapter(Class<?> typeClass, DBRType epicsValueType, DBRType epicsMetaType, Boolean array) {
33+
this.typeClass = typeClass;
34+
this.epicsValueType = epicsValueType;
35+
this.epicsMetaType = epicsMetaType;
36+
this.array = array;
37+
}
38+
39+
40+
@Override
41+
public boolean match(ReadCollector<?, ?> cache, CAConnectionPayload connectionPayload) {
42+
43+
Channel channel = connectionPayload.getChannel();
44+
45+
// If the generated type can't be put in the cache, no match
46+
if (!cache.getType().isAssignableFrom(typeClass))
47+
return false;
48+
49+
// If the type of the channel does not match, no match
50+
if (!dbrTypeMatch(epicsValueType, connectionPayload.getFieldType()))
51+
return false;
52+
53+
// If processes array, but count is 1, no match
54+
if (array != null && array && channel.getElementCount() == 1)
55+
return false;
56+
57+
// If processes scalar, but the count is not 1, no match
58+
if (array != null && !array && channel.getElementCount() != 1)
59+
return false;
60+
61+
// Everything matches
62+
return true;
63+
}
64+
private static boolean dbrTypeMatch(DBRType aType, DBRType anotherType) {
65+
if (aType.getClass() == null && anotherType.getClass() != null) {
66+
return false;
67+
}
68+
if (aType.getClass() != null && anotherType.getClass() == null) {
69+
return false;
70+
}
71+
return aType.isBYTE() && anotherType.isBYTE() ||
72+
aType.isDOUBLE() && anotherType.isDOUBLE() ||
73+
aType.isENUM() && anotherType.isENUM() ||
74+
aType.isFLOAT() && anotherType.isFLOAT() ||
75+
aType.isINT() && anotherType.isINT() ||
76+
aType.isSHORT() && anotherType.isSHORT() ||
77+
aType.isSTRING() && anotherType.isSTRING();
78+
}
79+
@Override
80+
public Object getSubscriptionParameter(ReadCollector<?, ?> cache, CAConnectionPayload connection) {
81+
throw new UnsupportedOperationException("Not implemented: CAChannelHandler is multiplexed, will not use this method");
82+
83+
}
84+
85+
@Override
86+
public void updateCache(ReadCollector cache, CAConnectionPayload connection, CAMessagePayload message) {
87+
Channel channel = connection.getChannel();
88+
// If metadata is required and not present, no update
89+
if (epicsMetaType != null && message.getMetadata() == null)
90+
return;
91+
// If value is not present, no update
92+
if (message.getEvent() == null)
93+
return;
94+
cache.updateValue(createValue(message.getEvent().getDBR(), message.getMetadata(), connection));
95+
return;
96+
}
97+
98+
/**
99+
* Given the value create the new value.
100+
*
101+
* @param message the value taken from the monitor
102+
* @param metadata the value field metadata, optional
103+
* @param connPayload connection playload
104+
*
105+
* @return the new value
106+
*/
107+
public abstract Object createValue(DBR message, DBR metadata, CAConnectionPayload connPayload);
108+
109+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* Copyright information and license terms for this software can be
3+
* found in the file LICENSE.TXT included with the distribution.
4+
*/
5+
package org.epics.gpclient.datasource.ca.types;
6+
7+
import java.util.Collection;
8+
9+
import org.epics.gpclient.datasource.DataSourceTypeAdapterSet;
10+
11+
/**
12+
*
13+
* @author carcassi
14+
*/
15+
public interface CATypeAdapterSet extends DataSourceTypeAdapterSet {
16+
17+
@Override
18+
Collection<CATypeAdapter> getAdapters();
19+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Copyright information and license terms for this software can be
3+
* found in the file LICENSE.TXT included with the distribution.
4+
*/
5+
package org.epics.gpclient.datasource.ca.types;
6+
7+
import org.epics.gpclient.ReadCollector;
8+
import org.epics.gpclient.datasource.DataSourceTypeSupport;
9+
import org.epics.gpclient.datasource.ca.CAConnectionPayload;
10+
11+
/**
12+
* Given a set of {@link CATypeAdapter} prepares type support for the
13+
* JCA data source.
14+
*
15+
* @author carcassi
16+
*/
17+
public class CATypeSupport extends DataSourceTypeSupport {
18+
19+
private final CATypeAdapterSet adapters;
20+
21+
/**
22+
* A new type support for the jca type support.
23+
*
24+
* @param adapters a set of jca adapters
25+
*/
26+
public CATypeSupport(CATypeAdapterSet adapters) {
27+
this.adapters = adapters;
28+
}
29+
30+
/**
31+
* Returns a matching type adapter for the given
32+
* cache and channel.
33+
*
34+
* @param cache the cache that will store the data
35+
* @param connection the ca channel
36+
* @return the matched type adapter
37+
*/
38+
public CATypeAdapter find(ReadCollector<?, ?> cache, CAConnectionPayload connection) {
39+
return find(adapters.getAdapters(), cache, connection);
40+
}
41+
}

0 commit comments

Comments
 (0)