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.slf4j.Logger;
22
23 import java.io.IOException;
24 import java.util.*;
25 import java.util.function.BiFunction;
26 import java.util.function.Function;
27 import java.util.stream.Collectors;
28
29 import static java.nio.charset.StandardCharsets.ISO_8859_1;
30
31
32
33
34 class ControlLabImpl implements ControlLab {
35 private final Logger log;
36 private final SerialPortFactory portFactory;
37 private SerialPort serialPort;
38 private final InputManager inputManager;
39 private final BiFunction<SerialPort, InputManager, SerialPortEventListener> listenerFactory;
40 private final Map<OutputId, Output> outputMap;
41 private final StopButton stopButton;
42 private final Map<InputId, Input> inputMap;
43 private SerialPortWriter serialPortWriter;
44
45
46
47
48 ControlLabImpl(Logger log) {
49 this(log, new JsscSerialPortFactory(), new InputManager(), SerialListener::new);
50 }
51
52 ControlLabImpl(Logger log,
53 SerialPortFactory portFactory,
54 InputManager inputManager,
55 BiFunction<SerialPort, InputManager, SerialPortEventListener> listenerFactory) {
56 this.log = log;
57 this.portFactory = portFactory;
58 this.inputManager = inputManager;
59 this.listenerFactory = listenerFactory;
60 outputMap = Collections.unmodifiableMap(new EnumMap<>(
61 Arrays.stream(OutputId.values()).collect(
62 Collectors.toMap(Function.identity(), id -> new Output(this, id)))));
63 stopButton = new StopButton(inputManager);
64 inputMap = Collections.unmodifiableMap(new EnumMap<>(
65 Arrays.stream(InputId.values()).collect(
66 Collectors.toMap(Function.identity(), id -> new Input(inputManager, id)))));
67 }
68
69 @Override
70 public void open(String portName) throws IOException {
71 serialPort = portFactory.getSerialPort(portName);
72 log.info("Opening port {}", serialPort.getPortName());
73 serialPort.openPort();
74 SerialPortEventListener serialListener = listenerFactory.apply(serialPort, inputManager);
75 serialPort.addEventListener(serialListener);
76
77 serialPortWriter = new SerialPortWriter(serialPort);
78 serialPortWriter.sendCommand(Protocol.HANDSHAKE_CHALLENGE.getBytes(ISO_8859_1), log);
79 if (!serialListener.isHandshakeSeen()) {
80 close();
81 throw new IOException("No response to handshake");
82 }
83 serialPortWriter.startKeepAlives();
84 }
85
86
87 @Override
88 public void turnOutputOff(Set<OutputId> outputs) throws IOException {
89 serialPortWriter.sendCommand(Protocol.OUTPUT_OFF, OutputId.encodeSetToByte(outputs));
90 }
91
92
93 @Override
94 public void turnOutputOn(Set<OutputId> outputs) throws IOException {
95 serialPortWriter.sendCommand(Protocol.OUTPUT_ON, OutputId.encodeSetToByte(outputs));
96 }
97
98
99 @Override
100 public void setOutputDirection(Direction direction, Set<OutputId> outputs) throws IOException {
101 serialPortWriter.sendCommand(direction.getCode(), OutputId.encodeSetToByte(outputs));
102 }
103
104
105 @Override
106 public void setOutputPowerLevel(PowerLevel powerLevel, Set<OutputId> outputs) throws IOException {
107 serialPortWriter.sendCommand(powerLevel.getCode(), OutputId.encodeSetToByte(outputs));
108 }
109
110
111 @Override
112 public Output getOutput(OutputId outputId) {
113 return outputMap.get(outputId);
114 }
115
116
117 @Override
118 public Output getOutput(Set<OutputId> outputs) {
119 if (outputs.size() == 1) {
120 return getOutput(outputs.iterator().next());
121 }
122 return new Output(this, outputs);
123 }
124
125
126 @Override
127 public StopButton getStopButton() {
128 return stopButton;
129 }
130
131
132 @Override
133 public Input getInput(InputId inputId) {
134 return inputMap.get(inputId);
135 }
136
137
138 @Override
139 public List<String> getAvailablePorts() {
140 return portFactory.getAvailablePorts();
141 }
142
143
144 @Override
145 public String getConnectedPortName() {
146 if (serialPort != null) {
147 return serialPort.getPortName();
148 } else {
149 return "";
150 }
151 }
152
153
154 @Override
155 public void close() throws IOException {
156 if (serialPortWriter != null) {
157 if (serialPort != null) {
158 serialPortWriter.sendCommand(Protocol.DISCONNECT);
159 }
160 serialPortWriter.close();
161 serialPortWriter = null;
162 }
163 if (serialPort != null) {
164 serialPort.close();
165 serialPort = null;
166 }
167 }
168
169 @Override
170 public String toString() {
171 return "ControlLabImpl{" +
172 "serialPort=" + serialPort +
173 "}@" +
174 System.identityHashCode(this);
175 }
176 }