View Javadoc
1   /*
2    * Copyright © 2016 Greg Chabala
3    *
4    * This file is part of brick-control-lab.
5    *
6    * brick-control-lab is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU Lesser General Public License as
8    * published by the Free Software Foundation, either version 3 of the
9    * License, or (at your option) any later version.
10   *
11   * brick-control-lab is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU Lesser General Public License for more details.
15   *
16   * You should have received a copy of the GNU Lesser General Public License
17   * along with brick-control-lab.  If not, see http://www.gnu.org/licenses/.
18   */
19  package org.chabala.brick.controllab;
20  
21  import org.slf4j.Logger;
22  import org.slf4j.LoggerFactory;
23  
24  import java.io.Closeable;
25  import java.io.IOException;
26  
27  import static java.nio.charset.StandardCharsets.ISO_8859_1;
28  
29  /**
30   * Owner of all writing activity for a serial port. Manages consistent logging
31   * and ownership of the keep alive monitor for the port.
32   */
33  class SerialPortWriter implements Closeable {
34      /**
35       * When sending commands longer than this threshold, log them as strings
36       * instead of hex values. In practice, this is only needed for the initial
37       * handshake, which makes more sense to show as a string.
38       */
39      private static final int STRING_LOGGING_THRESHOLD = 10;
40      private final Logger log = LoggerFactory.getLogger(getClass());
41      private final SerialPort serialPort;
42      private KeepAliveMonitor keepAliveMonitor;
43  
44      SerialPortWriter(SerialPort serialPort) {
45          this.serialPort = serialPort;
46      }
47  
48      void startKeepAlives() {
49          keepAliveMonitor = new KeepAliveMonitor(this);
50      }
51  
52      String getPortName() {
53          return serialPort.getPortName();
54      }
55  
56      void sendCommand(byte[] bytes, Logger log) throws IOException {
57          if (serialPort == null) {
58              throw new IOException("Not connected to control lab");
59          }
60          if (keepAliveMonitor != null) {
61              keepAliveMonitor.reset();
62          }
63          if (serialPort.isOpen()) {
64              if (log.isInfoEnabled()) {
65                  if (bytes.length > STRING_LOGGING_THRESHOLD) {
66                      String portName = serialPort.getPortName();
67                      log.info("{} TX -> {}", portName, new String(bytes, ISO_8859_1));
68                  } else if (log.isDebugEnabled()) {
69                      String portName = serialPort.getPortName();
70                      StringBuilder sb = new StringBuilder();
71                      for (byte b : bytes) {
72                          sb.append(String.format("0x%02X ", b));
73                      }
74                      log.debug("{} TX -> {}", portName, sb);
75                  }
76              }
77              serialPort.write(bytes);
78          }
79      }
80  
81      void sendCommand(byte[] bytes) throws IOException {
82          sendCommand(bytes, log);
83      }
84  
85      void sendCommand(byte b) throws IOException {
86          sendCommand(new byte[]{b});
87      }
88  
89      void sendCommand(byte b, Logger log) throws IOException {
90          sendCommand(new byte[]{b}, log);
91      }
92  
93      void sendCommand(byte b1, byte b2) throws IOException {
94          sendCommand(new byte[]{b1, b2});
95      }
96  
97      @Override
98      public void close() {
99          if (keepAliveMonitor != null) {
100             keepAliveMonitor.close();
101             keepAliveMonitor = null;
102         }
103     }
104 }