1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.chabala.brick.controllab;
20
21 import org.chabala.brick.controllab.sensor.*;
22 import org.junit.Ignore;
23 import org.junit.Test;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 import java.io.IOException;
28 import java.lang.invoke.MethodHandles;
29 import java.util.*;
30 import java.util.concurrent.atomic.AtomicBoolean;
31 import java.util.stream.Collectors;
32
33 import static javax.management.timer.Timer.ONE_SECOND;
34 import static org.awaitility.Awaitility.await;
35 import static org.chabala.brick.controllab.PortChooser.choosePort;
36 import static org.hamcrest.Matchers.*;
37 import static org.junit.Assert.*;
38 import static org.junit.Assume.assumeNoException;
39
40
41
42
43
44
45
46 @SuppressWarnings({"squid:S2699","squid:S2925"})
47 public class ControlLabIT {
48 private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
49
50 @Test
51 public void testTurnOutputOff() throws Exception {
52 try (ControlLab controlLab = ControlLab.newControlLab()) {
53 try {
54 controlLab.open(choosePort(controlLab));
55 } catch (IOException e) {
56 assumeNoException(e);
57 }
58 Thread.sleep(ONE_SECOND * 3);
59 controlLab.turnOutputOn(OutputId.ALL);
60 Thread.sleep(ONE_SECOND * 3);
61 controlLab.turnOutputOff(EnumSet.range(OutputId.A, OutputId.D));
62 Thread.sleep(ONE_SECOND * 3);
63 }
64 }
65
66 @Test
67 public void testControlLabOutputs() throws Exception {
68 try (ControlLab controlLab = ControlLab.newControlLab()) {
69 try {
70 controlLab.open(choosePort(controlLab));
71 } catch (IOException e) {
72 assumeNoException(e);
73 }
74 Thread.sleep(ONE_SECOND);
75
76 controlLab.turnOutputOn(OutputId.ALL);
77 Thread.sleep(ONE_SECOND);
78
79 controlLab.setOutputDirection(Direction.LEFT, EnumSet.of(OutputId.E, OutputId.F));
80 Thread.sleep(ONE_SECOND);
81
82 controlLab.getOutput(EnumSet.range(OutputId.E, OutputId.H)).reverseDirection();
83 Thread.sleep(ONE_SECOND);
84
85 controlLab.getOutput(OutputId.H).setDirection(Direction.RIGHT);
86 Thread.sleep(ONE_SECOND);
87
88 for (OutputId o : descendingRange(OutputId.H, OutputId.E)) {
89 controlLab.getOutput(o).turnOff();
90 Thread.sleep(ONE_SECOND);
91 }
92
93 controlLab.turnOutputOff(EnumSet.range(OutputId.A, OutputId.D));
94 Thread.sleep(ONE_SECOND * 5);
95 }
96 }
97
98 @Test
99 public void testFluentOutputControl() throws Exception {
100 try (ControlLab controlLab = ControlLab.newControlLab()) {
101 try {
102 controlLab.open(choosePort(controlLab));
103 } catch (IOException e) {
104 assumeNoException(e);
105 }
106 Output output = controlLab.getOutput(OutputId.A);
107 output.setDirection(Direction.LEFT).setPowerLevel(PowerLevel.P2).turnOn();
108 Thread.sleep(ONE_SECOND * 5);
109
110 output.reverseDirection().setPowerLevel(PowerLevel.P8);
111 Thread.sleep(ONE_SECOND * 5);
112 }
113 }
114
115 @Ignore("Requires interaction with stop button to complete, only run manually")
116 @Test
117 public void testControlLabInputs() throws Exception {
118 AtomicBoolean stop = new AtomicBoolean(false);
119 try (ControlLab controlLab = ControlLab.newControlLab()) {
120 try {
121 controlLab.open(choosePort(controlLab));
122 } catch (IOException e) {
123 assumeNoException(e);
124 }
125 controlLab.getStopButton().addListener(stopButtonEvent -> stop.set(true));
126 Map<InputId, String> lastTouchValues = Collections.synchronizedMap(new EnumMap<>(InputId.class));
127 List<InputId> passiveInputs = Arrays.stream(InputId.values())
128 .filter(i -> i.getInputType().equals(InputType.PASSIVE))
129 .collect(Collectors.toList());
130 passiveInputs.forEach(i -> lastTouchValues.put(i, ""));
131 TouchSensorListener touchSensorListener = sensorEvent -> {
132 InputId input = sensorEvent.getInput();
133 String newValue = sensorEvent.getValue().touchStatus();
134 if ("".equals(newValue)) {
135 return;
136 }
137 String oldValue = lastTouchValues.put(input, newValue);
138 if (!newValue.equals(oldValue)) {
139 log.info("{} value changed: {}", input, newValue);
140 }
141 };
142 for (InputId passiveInput : passiveInputs) {
143 controlLab.getInput(passiveInput).addListener(touchSensorListener);
144 }
145 LightSensorListener lightSensorListener = sensorEvent -> {
146 InputId input = sensorEvent.getInput();
147 log.info("{} value changed: {}", input, sensorEvent.getValue());
148 };
149 Arrays.stream(InputId.values())
150 .filter(i -> i.getInputType().equals(InputType.ACTIVE))
151 .map(controlLab::getInput)
152 .forEach(i -> i.addListener(lightSensorListener));
153
154 await().forever().until(stop::get);
155 }
156 }
157
158 @Ignore("Requires interaction with stop button to complete, only run manually")
159 @Test
160 public void testControlLabInputsRaw() throws Exception {
161 AtomicBoolean stop = new AtomicBoolean(false);
162 try (ControlLab controlLab = ControlLab.newControlLab()) {
163 try {
164 controlLab.open(choosePort(controlLab));
165 } catch (IOException e) {
166 assumeNoException(e);
167 }
168 controlLab.getStopButton().addListener(stopButtonEvent -> stop.set(true));
169 SensorListener sensorListener = sensorEvent ->
170 log.info("{} value changed: {}", sensorEvent.getInput(), sensorEvent.getValue());
171 Arrays.stream(InputId.values())
172 .map(controlLab::getInput)
173 .forEach(i -> i.addListener(sensorListener));
174
175 await().forever().until(stop::get);
176 }
177 }
178
179 @Test
180 public void testOutputPowerLevels() throws Exception {
181 try (ControlLab controlLab = ControlLab.newControlLab()) {
182 try {
183 controlLab.open(choosePort(controlLab));
184 } catch (IOException e) {
185 assumeNoException(e);
186 }
187 Thread.sleep(ONE_SECOND);
188
189 Output output = controlLab.getOutput(OutputId.A);
190 output.setPowerLevel(PowerLevel.P1).turnOn();
191 Thread.sleep(ONE_SECOND);
192
193 for (PowerLevel p : EnumSet.range(PowerLevel.P2, PowerLevel.P8)) {
194 output.setPowerLevel(p);
195 Thread.sleep(ONE_SECOND);
196 }
197
198 output.setPowerLevel(PowerLevel.P0);
199 Thread.sleep(ONE_SECOND);
200
201 output.turnOn();
202 Thread.sleep(ONE_SECOND);
203 }
204 }
205
206 @Ignore("Requires interaction with stop button to complete, only run manually")
207 @Test
208 public void testRunUntilStopButtonPressed() throws Exception {
209 AtomicBoolean stop = new AtomicBoolean(false);
210 try (ControlLab controlLab = ControlLab.newControlLab()) {
211 try {
212 controlLab.open(choosePort(controlLab));
213 } catch (IOException e) {
214 assumeNoException(e);
215 }
216 controlLab.getStopButton().addListener(stopButtonEvent -> stop.set(true));
217 await().forever().until(stop::get);
218 }
219 }
220
221
222
223
224
225
226
227
228 @Ignore("Requires interaction with Input 1 to complete, only run manually")
229 @Test
230 public void testMotorInBothDirections() throws Exception {
231 AtomicBoolean stop = new AtomicBoolean(false);
232 try (ControlLab controlLab = ControlLab.newControlLab()) {
233 try {
234 controlLab.open(choosePort(controlLab));
235 } catch (IOException e) {
236 assumeNoException(e);
237 }
238 Thread.sleep(ONE_SECOND);
239 controlLab.getInput(InputId.I1).addListener((TouchSensorListener) sensorEvent -> stop.set(true));
240 Output outputs = controlLab.getOutput(OutputId.ALL);
241 while (!stop.get()) {
242 outputs.setPowerLevel(PowerLevel.P8).setDirection(Direction.RIGHT).turnOn();
243 Thread.sleep(ONE_SECOND);
244 if (stop.get()) {
245 return;
246 }
247
248 for (PowerLevel p : descendingRange(PowerLevel.P7, PowerLevel.P1)) {
249 outputs.setPowerLevel(p);
250 Thread.sleep(ONE_SECOND);
251 if (stop.get()) {
252 return;
253 }
254 }
255
256 outputs.reverseDirection();
257 Thread.sleep(ONE_SECOND);
258 if (stop.get()) {
259 return;
260 }
261
262 for (PowerLevel p : EnumSet.range(PowerLevel.P2, PowerLevel.P8)) {
263 outputs.setPowerLevel(p);
264 Thread.sleep(ONE_SECOND);
265 if (stop.get()) {
266 return;
267 }
268 }
269 }
270 }
271 }
272
273
274
275
276
277
278 private <E extends Enum<E>> List<E> descendingRange(E from, E to) {
279 EnumSet<E> rangeSet;
280 if (from.compareTo(to) > 0) {
281 rangeSet = EnumSet.range(to, from);
282 } else {
283 rangeSet = EnumSet.range(from, to);
284 }
285 List<E> rangeList = new ArrayList<>(rangeSet);
286 Collections.reverse(rangeList);
287 return rangeList;
288 }
289
290 @Test
291 public void testDescendingRange() throws Exception {
292 List<PowerLevel> powerLevelList = new ArrayList<>(EnumSet.range(PowerLevel.P1, PowerLevel.P3));
293 assertThat(powerLevelList, contains(PowerLevel.P1, PowerLevel.P2, PowerLevel.P3));
294 assertThat(powerLevelList.get(0), is(PowerLevel.P1));
295 assertThat(powerLevelList.get(2), is(PowerLevel.P3));
296
297 powerLevelList = descendingRange(PowerLevel.P1, PowerLevel.P3);
298 assertThat(powerLevelList, contains(PowerLevel.P3, PowerLevel.P2, PowerLevel.P1));
299 assertThat(powerLevelList.get(0), is(PowerLevel.P3));
300 assertThat(powerLevelList.get(2), is(PowerLevel.P1));
301
302 powerLevelList = descendingRange(PowerLevel.P3, PowerLevel.P1);
303 assertThat(powerLevelList, contains(PowerLevel.P3, PowerLevel.P2, PowerLevel.P1));
304 assertThat(powerLevelList.get(0), is(PowerLevel.P3));
305 assertThat(powerLevelList.get(2), is(PowerLevel.P1));
306 }
307 }