Skip to main content
summaryrefslogtreecommitdiffstats
blob: 95a19095c2233bf6bdc0d630ca3305d7e3c42a50 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
/********************************************************************************
 * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
 *
 * See the NOTICE file(s) distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 ********************************************************************************/


package org.eclipse.mdm.api.base.model;

import static java.util.stream.IntStream.range;
import static org.eclipse.mdm.api.base.model.Value.readAt;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.stream.Collectors;

/**
 * Class represents a sequence of measured values.
 *
 * @since 1.0.0
 * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
 * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
 */
public final class MeasuredValues {

	// ======================================================================
	// Instance variables
	// ======================================================================

	private final ScalarType scalarType;
	private final Object values;
	private final boolean[] flags;

	/*
	 * TODO: - replace name and unit with the corresponding Channel & Unit
	 * entities - provide further information if required 
	 * - provide an overall offset for this value sequence
	 */

	private final String name;
	private final String unit;

	private final int length;
	
	private final SequenceRepresentation sequenceRepresentation;
	private final double[] generationParameters;
	private final boolean independent;
	private final AxisType axisType;

	// ======================================================================
	// Constructors
	// ======================================================================

	/**
	 * Constructor.
	 *
	 * @param scalarType
	 *            The {@link ScalarType} of this measured values.
	 * @param name
	 *            This is the name of the corresponding {@link Channel}.
	 * @param unit
	 *            Name of the unit the contained values are of.
	 * @param sequenceRepresentation
	 *            The {@link SequenceRepresentation} of the measured values.
	 * @param generationParameters
	 *            The generation parameters for the measured values.
	 * @param independent
	 *            The independent flag of the measured values.
	 * @param axisType
	 *            The {@link AxisType} of the measured values.
	 * @param values
	 *            The measured values.
	 * @param flags
	 *            The validity flags of the measured values.
	 * @throws IllegalArgumentException
	 *             Thrown if values or flags is null or length of values and
	 *             flags is not equal.
	 */
	MeasuredValues(ScalarType scalarType, String name, String unit, SequenceRepresentation sequenceRepresentation, double[] generationParameters, boolean independent, AxisType axisType, Object values, boolean[] flags) {
		this.name = name;
		this.unit = (unit == null ? "" : unit);
		this.scalarType = scalarType;
		this.sequenceRepresentation = sequenceRepresentation;
		this.generationParameters = generationParameters;
		this.independent = independent;
		this.axisType = axisType;
		this.values = values;

		if (values == null || flags == null) {
			throw new IllegalArgumentException("Neither values nor flags is allowed to be null.");
		} else if (Array.getLength(values) != flags.length) {
			throw new IllegalArgumentException("Length of values and flags is not equal.");
		}

		this.flags = Arrays.copyOf(flags, flags.length);
		length = flags.length;
	}

	// ======================================================================
	// Public methods
	// ======================================================================

	/**
	 * Returns the name of this measured values sequence.
	 *
	 * @return The name is returned.
	 */
	public String getName() {
		return name;
	}

	/**
	 * Returns the unit name for this measured values sequence.
	 *
	 * @return The unit name is returned.
	 */
	public String getUnit() {
		return unit;
	}

	/**
	 * Returns the {@link ScalarType} of this measured values sequence.
	 *
	 * @return The {@code ScalarType} is returned.
	 */
	public ScalarType getScalarType() {
		return scalarType;
	}

	/**
	 * Returns the number of values of this measured values sequence.
	 *
	 * @return The number of values is returned.
	 */
	public int getLength() {
		return length;
	}
	
	/**
	 * Returns the {@link SequenceRepresentation} of this measured values sequence.
	 *
	 * @return The {@code SequenceRepresentation} is returned.
	 */
	public SequenceRepresentation getSequenceRepresentation() {
		return sequenceRepresentation;
	}
	
	/**
	 * Returns the generation parameters for this measured values sequence.
	 *
	 * @return The generation parameters are returned.
	 */
	public double[] getGenerationParameters() {
		return generationParameters;
	}
	
	/**
	 * Returns the independent flag of this measured values sequence.
	 *
	 * @return The independent flag is returned.
	 */
	public boolean isIndependent() {
		return independent;
	}
	
	/**
	 * Returns the {@link AxisType} of this measured values sequence.
	 *
	 * @return The {@code AxisType} is returned.
	 */
	public AxisType getAxisType() {
		return axisType;
	}

	/**
	 * Returns a typed {@link ValueIterator}. Its usage is described below:
	 *
	 * <pre>
	 * // assume the measuredValues().getScalarType() == ScalarType.BYTE
	 * ValueIterator&lt;Byte&gt; valueIterator = measuredValues().iterator();
	 * while (valueIterator.hasNext()) {
	 * 	boolean isCurrentValid = valueIterator.isValid();
	 * 	Byte currentValue = valueIterator.next();
	 * }
	 * </pre>
	 *
	 * @param <E>
	 *            This type has to be derived from the {@link ScalarType} of
	 *            this measured values.
	 * @return A typed {@code ValueIterator} is returned.
	 */
	public <E> ValueIterator<E> iterator() {
		// TODO provide custom implementations for each type and typed
		// nextType() methods
		// idea: getScalarType().createIterator(values, flags); // <- package
		// private
		return new ValueIterator<E>() {
			private int index = 0;

			@Override
			public boolean hasNext() {
				return index < length;
			}
			@Override
			public boolean isValid() {
				return flags[index];
			}
			@Override
			@SuppressWarnings("unchecked")
			public E next() {
				if (hasNext()) {
					return (E) Array.get(values, index++);
				}
				throw new NoSuchElementException("Subsequent value is not available.");
			}
		};
	}

	/**
	 * Returns a human readable {@code String} representation of this measured
	 * values. If this sequence contains more than 10 values, only the first and
	 * last 5 values are written. If a value is marked as not valid, then 'XX'
	 * is written instead of its value.
	 *
	 * @return The {@code String} representation of this entity.
	 */
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder("MeasuredValues(ChannelName = ").append(getName());
		sb.append(", ScalarType = ").append(getScalarType());

		if (!getUnit().isEmpty()) {
			sb.append(", Unit = ").append(getUnit());
		}

		sb.append(", Values = [");
		String notValidMarker = "XX";
		if (getLength() > 10) {
			sb.append(range(0, 5).mapToObj(i -> flags[i] ? readAt(values, i) : notValidMarker)
					.collect(Collectors.joining(", ")));
			sb.append(", ..., ");
			sb.append(range(length - 5, length).mapToObj(i -> flags[i] ? readAt(values, i) : notValidMarker)
					.collect(Collectors.joining(", ")));
		} else if (getLength() > 0) {
			sb.append(range(0, length).mapToObj(i -> flags[i] ? readAt(values, i) : notValidMarker)
					.collect(Collectors.joining(", ")));
		}

		return sb.append("])").toString();
	}

	// ======================================================================
	// Inner Types
	// ======================================================================

	/**
	 * The measured values iterator.
	 *
	 * @param <E>
	 *            Type of the returned values.
	 * @since 1.0.0
	 * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
	 */
	public interface ValueIterator<E> extends Iterator<E> {

		/**
		 * Returns true if the current value is marked as valid.
		 *
		 * @return True if current value is valid.
		 */
		boolean isValid();

	}

}

Back to the top