Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
232 changes: 97 additions & 135 deletions core/pv-pva/src/main/java/org/phoebus/pv/pva/PVAStructureHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,6 @@
******************************************************************************/
package org.phoebus.pv.pva;

import static java.util.stream.Collectors.toList;
import static java.util.stream.IntStream.range;
import static org.phoebus.pv.pva.Decoders.decodeAlarm;
import static org.phoebus.pv.pva.Decoders.decodeTime;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import org.epics.pva.data.PVAArray;
import org.epics.pva.data.PVABool;
import org.epics.pva.data.PVABoolArray;
Expand Down Expand Up @@ -56,49 +46,51 @@
import org.epics.vtype.VTable;
import org.epics.vtype.VType;

/** Helper for handling 'structure' type PVA data */
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import static java.util.stream.Collectors.toList;
import static java.util.stream.IntStream.range;
import static org.phoebus.pv.pva.Decoders.decodeAlarm;
import static org.phoebus.pv.pva.Decoders.decodeTime;

/**
* Helper for handling 'structure' type PVA data
*/
@SuppressWarnings("nls")
public class PVAStructureHelper
{
/** @param struct Structure
* @param name_helper {@link PVNameHelper}
* @return Decoded VType
* @throws Exception on error
public class PVAStructureHelper {
/**
* @param struct Structure
* @param name_helper {@link PVNameHelper}
* @return Decoded VType
* @throws Exception on error
*/
public static VType getVType(final PVAStructure struct, final PVNameHelper name_helper) throws Exception
{
public static VType getVType(final PVAStructure struct, final PVNameHelper name_helper) throws Exception {
PVAStructure actual = struct;

final Optional<Integer> elementIndex = name_helper.getElementIndex();

if (! name_helper.getField().equals("value"))
{ // Fetch data from a sub-(sub-sub-)field
if (!name_helper.getField().equals("value")) { // Fetch data from a sub-(sub-sub-)field
final PVAData field = struct.locate(name_helper.getField());
if (field instanceof PVAStructure)
actual = (PVAStructure) field;
else if (field instanceof PVANumber)
return Decoders.decodeNumber(struct, (PVANumber) field);
else if (field instanceof PVABool)
return Decoders.decodeBool(struct, (PVABool) field);
else if (field instanceof PVAStructureArray)
{
if (elementIndex.isPresent())
{
else if (field instanceof PVAStructureArray) {
if (elementIndex.isPresent()) {
actual = ((PVAStructureArray) field).get()[elementIndex.get()];
}
}
else if (field instanceof PVAArray)
{
if (elementIndex.isPresent())
{
} else if (field instanceof PVAArray) {
if (elementIndex.isPresent()) {
return decodeNTArray(struct, elementIndex.get());
}
else
{
} else {
return Decoders.decodeArray(struct, (PVAArray) field);
}
}
else if (field instanceof PVAString)
} else if (field instanceof PVAString)
return Decoders.decodeString(struct, (PVAString) field);
}

Expand All @@ -110,57 +102,59 @@ else if (field instanceof PVAString)
return decodeScalar(actual);
if (type.equals("NTEnum:1.0"))
return Decoders.decodeEnum(actual);
if (type.equals("NTScalarArray:1.0"))
return decodeNTArray(actual);
if (type.equals("NTScalarArray:1.0")) {
if (elementIndex.isPresent()) {
return decodeNTArray(actual, elementIndex.get());
} else {
return decodeNTArray(actual);
}
}
if (type.equals("NTNDArray:1.0"))
return ImageDecoder.decode(actual);
if (type.equals("NTTable:1.0"))
return decodeNTTable(actual);

// Handle data that contains a "value", even though not marked as NT*
final PVAData field = actual.get("value");
if (field instanceof PVANumber ||
field instanceof PVAString)
if (field instanceof PVANumber ||
field instanceof PVAString)
return decodeScalar(actual);
else if (field instanceof PVAArray)
return decodeNTArray(actual);
else if (field instanceof PVAUnion)
{ // Decode the currently selected variant of the union
else if (field instanceof PVAUnion) { // Decode the currently selected variant of the union
final PVAData union_field = ((PVAUnion) field).get();
if (union_field instanceof PVANumber ||
union_field instanceof PVAString)
if (union_field instanceof PVANumber ||
union_field instanceof PVAString)
return decodeScalarField(struct, union_field);
else if (union_field instanceof PVAArray)
return decodeNTArrayField(struct, union_field);
}
else if (field instanceof PVABool)
{
} else if (field instanceof PVABool) {
final PVABool bool = (PVABool) field;
return VBoolean.of(bool.get(), Alarm.none(), Time.now());
}
// TODO: not really sure how to handle arbitrary structures -- no solid use cases yet...

// Create string that indicates name of unknown type
return VString.of(actual.format(),
Alarm.of(AlarmSeverity.UNDEFINED, AlarmStatus.CLIENT, "Unknown type"),
Time.now());
Alarm.of(AlarmSeverity.UNDEFINED, AlarmStatus.CLIENT, "Unknown type"),
Time.now());
}

/** Attempt to decode a scalar {@link VType}
* @param struct PVA data for a scalar
* @return Value
* @throws Exception on error decoding the scalar
/**
* Attempt to decode a scalar {@link VType}
*
* @param struct PVA data for a scalar
* @return Value
* @throws Exception on error decoding the scalar
*/
private static VType decodeScalar(final PVAStructure struct) throws Exception
{
private static VType decodeScalar(final PVAStructure struct) throws Exception {
final VType result = decodeScalarField(struct, struct.get("value"));
if (result != null)
return result;
throw new Exception("Expected struct with scalar 'value', got " + struct);
}

private static VType decodeScalarField(final PVAStructure struct, final PVAData field) throws Exception
{
private static VType decodeScalarField(final PVAStructure struct, final PVAData field) throws Exception {
if (field instanceof PVANumber)
return Decoders.decodeNumber(struct, (PVANumber) field);
if (field instanceof PVABool)
Expand All @@ -170,104 +164,87 @@ private static VType decodeScalarField(final PVAStructure struct, final PVAData
return null;
}

/** Decode table from NTTable
* @param struct
* @return
* @throws Exception
/**
* Decode table from NTTable
*
* @param struct
* @return
* @throws Exception
*/
private static VType decodeNTTable(final PVAStructure struct) throws Exception
{
private static VType decodeNTTable(final PVAStructure struct) throws Exception {
final PVAStringArray labels_array = struct.get("labels");
final List<String> names = new ArrayList<>(Arrays.asList(labels_array.get()));
final List<String> names = new ArrayList<>(Arrays.asList(labels_array.get()));

final List<Class<?>> types = new ArrayList<>(names.size());
final List<Object> values = new ArrayList<>(names.size());
final PVAStructure value_struct = struct.get("value");
for (PVAData column : value_struct.get())
{
if (column instanceof PVADoubleArray)
{
final PVADoubleArray typed = (PVADoubleArray)column;
for (PVAData column : value_struct.get()) {
if (column instanceof PVADoubleArray) {
final PVADoubleArray typed = (PVADoubleArray) column;
types.add(Double.TYPE);
values.add(ArrayDouble.of(typed.get()));
}
else if (column instanceof PVAFloatArray)
{
final PVAFloatArray typed = (PVAFloatArray)column;
} else if (column instanceof PVAFloatArray) {
final PVAFloatArray typed = (PVAFloatArray) column;
types.add(Float.TYPE);
values.add(ArrayFloat.of(typed.get()));
}
else if (column instanceof PVAIntArray)
{
final PVAIntArray typed = (PVAIntArray)column;
} else if (column instanceof PVAIntArray) {
final PVAIntArray typed = (PVAIntArray) column;
types.add(Integer.TYPE);
if (typed.isUnsigned())
values.add(ArrayUInteger.of(typed.get()));
else
values.add(ArrayInteger.of(typed.get()));
}
else if (column instanceof PVAStringArray)
{
final PVAStringArray typed = (PVAStringArray)column;
} else if (column instanceof PVAStringArray) {
final PVAStringArray typed = (PVAStringArray) column;
types.add(String.class);
values.add(Arrays.asList(typed.get()));
}
else if (column instanceof PVAShortArray)
{
final PVAShortArray typed = (PVAShortArray)column;
} else if (column instanceof PVAShortArray) {
final PVAShortArray typed = (PVAShortArray) column;
types.add(Short.TYPE);
if (typed.isUnsigned())
values.add(ArrayUShort.of(typed.get()));
else
values.add(ArrayShort.of(typed.get()));
}
else if (column instanceof PVALongArray)
{
final PVALongArray typed = (PVALongArray)column;
} else if (column instanceof PVALongArray) {
final PVALongArray typed = (PVALongArray) column;
types.add(Long.TYPE);
if (typed.isUnsigned())
values.add(ArrayULong.of(typed.get()));
else
values.add(ArrayLong.of(typed.get()));
}
else if (column instanceof PVAByteArray)
{
final PVAByteArray typed = (PVAByteArray)column;
} else if (column instanceof PVAByteArray) {
final PVAByteArray typed = (PVAByteArray) column;
types.add(Byte.TYPE);
if (typed.isUnsigned())
values.add(ArrayUByte.of(typed.get()));
else
values.add(ArrayByte.of(typed.get()));
}
else if (column instanceof PVABoolArray)
{
final PVABoolArray typed = (PVABoolArray)column;
} else if (column instanceof PVABoolArray) {
final PVABoolArray typed = (PVABoolArray) column;
types.add(Boolean.TYPE);
boolean[] data = typed.get();
// Convert to boxed Integer to add to List
values.add(range(0, data.length).mapToObj(i -> data[i]).collect(toList()));
}
else
{
throw new IllegalArgumentException("Could not decode table column of type: " + column.getClass());
} else {
throw new IllegalArgumentException("Could not decode table column of type: " + column.getClass());
}
}

return VTable.of(types, names, values);
}

/** Decode 'value', 'timeStamp', 'alarm' of NTArray
* @param struct
* @return
* @throws Exception
/**
* Decode 'value', 'timeStamp', 'alarm' of NTArray
*
* @param struct
* @return
* @throws Exception
*/
private static VType decodeNTArray(final PVAStructure struct) throws Exception
{
private static VType decodeNTArray(final PVAStructure struct) throws Exception {
return decodeNTArrayField(struct, struct.get("value"));
}

private static VType decodeNTArrayField(final PVAStructure struct, final PVAData field) throws Exception
{
private static VType decodeNTArrayField(final PVAStructure struct, final PVAData field) throws Exception {
if (field instanceof PVADoubleArray)
return Decoders.decodeDoubleArray(struct, (PVADoubleArray) field);
if (field instanceof PVAFloatArray)
Expand All @@ -283,70 +260,55 @@ private static VType decodeNTArrayField(final PVAStructure struct, final PVAData
if (field instanceof PVAStringArray)
return Decoders.decodeStringArray(struct, (PVAStringArray) field);
return VString.of(struct.format(),
Alarm.of(AlarmSeverity.UNDEFINED, AlarmStatus.CLIENT, "Unknown array type"),
Time.now());
Alarm.of(AlarmSeverity.UNDEFINED, AlarmStatus.CLIENT, "Unknown array type"),
Time.now());
}

/**
* Decode 'value', 'timeStamp', 'alarm' of NTArray and extract the value at index
*
* @param struct
* @param index
* @return {@link VType}
* @throws Exception
*/
private static VType decodeNTArray(PVAStructure struct, Integer index) throws Exception
{
private static VType decodeNTArray(PVAStructure struct, Integer index) throws Exception {
final PVAData field = struct.get("value");
if (field instanceof PVADoubleArray)
{
if (field instanceof PVADoubleArray) {
return VNumber.of(((VNumberArray) Decoders.decodeDoubleArray(struct, (PVADoubleArray) field)).getData().getDouble(index),
decodeAlarm(struct),
decodeTime(struct),
Display.none());
}
else if (field instanceof PVAFloatArray)
{
} else if (field instanceof PVAFloatArray) {
return VNumber.of(((VNumberArray) Decoders.decodeFloatArray(struct, (PVAFloatArray) field)).getData().getFloat(index),
decodeAlarm(struct),
decodeTime(struct),
Display.none());
}
else if (field instanceof PVALongArray)
{
} else if (field instanceof PVALongArray) {
return VNumber.of(((VNumberArray) Decoders.decodeLongArray(struct, (PVALongArray) field)).getData().getLong(index),
decodeAlarm(struct),
decodeTime(struct),
Display.none());
}
else if (field instanceof PVAIntArray)
{
} else if (field instanceof PVAIntArray) {
return VNumber.of(((VNumberArray) Decoders.decodeIntArray(struct, (PVAIntArray) field)).getData().getInt(index),
decodeAlarm(struct),
decodeTime(struct),
Display.none());
}
else if (field instanceof PVAShortArray)
{
} else if (field instanceof PVAShortArray) {
return VNumber.of(((VNumberArray) Decoders.decodeShortArray(struct, (PVAShortArray) field)).getData().getShort(index),
decodeAlarm(struct),
decodeTime(struct),
Display.none());
}
else if (field instanceof PVAByteArray)
{
} else if (field instanceof PVAByteArray) {
return VNumber.of(((VNumberArray) Decoders.decodeByteArray(struct, (PVAByteArray) field)).getData().getByte(index),
decodeAlarm(struct),
decodeTime(struct),
Display.none());
}
else if (field instanceof PVAStringArray)
{
} else if (field instanceof PVAStringArray) {
return VString.of(((VStringArray) Decoders.decodeStringArray(struct, (PVAStringArray) field)).getData().get(index),
decodeAlarm(struct),
decodeTime(struct));
}
else
{
} else {
return VString.of(struct.format(),
Alarm.of(AlarmSeverity.UNDEFINED, AlarmStatus.CLIENT, "Unknown array type"),
Time.now());
Expand Down