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.IOException;
25  import java.util.concurrent.CountDownLatch;
26  import java.util.concurrent.TimeUnit;
27  
28  import static java.nio.charset.StandardCharsets.ISO_8859_1;
29  
30  /**
31   * Handles serial events.
32   */
33  class SerialListener implements SerialPortEventListener {
34  
35      private final Logger log = LoggerFactory.getLogger(getClass());
36      private final SerialPort serialPort;
37      private final InputManager inputManager;
38      private final boolean ignoreBadHandshake;
39  
40      private boolean handshakeSeen = false;
41      private CountDownLatch handshakeLatch = new CountDownLatch(1);
42      private StringBuilder handshakeBuilder = new StringBuilder();
43  
44      SerialListener(SerialPort serialPort, InputManager inputManager) {
45          this.serialPort = serialPort;
46          this.inputManager = inputManager;
47          ignoreBadHandshake = Boolean.valueOf(
48                  System.getProperty("brick-control-lab.ignoreBadHandshake", "false"));
49      }
50  
51      @Override
52      public boolean isHandshakeSeen() {
53          boolean returnedEarly = false;
54          try {
55              returnedEarly = handshakeLatch.await(1, TimeUnit.SECONDS);
56          } catch (InterruptedException e) {
57              log.error(e.getMessage(), e);
58              Thread.currentThread().interrupt();
59          }
60          return handshakeSeen || returnedEarly;
61      }
62  
63      private void setHandshakeSeen() {
64          handshakeSeen = true;
65          handshakeLatch.countDown();
66          handshakeBuilder = null;
67      }
68  
69      /** {@inheritDoc} */
70      @Override
71      public void serialEventRXCHAR(int availableBytes) {
72          if (!handshakeSeen) {
73              processHandshake(availableBytes);
74          } else {
75              if (availableBytes >= Protocol.FRAME_SIZE) {
76                  try {
77                      byte[] buffer = serialPort.readBytes(Protocol.FRAME_SIZE);
78                      inputManager.processInputSensors(buffer);
79                  } catch (IOException e) {
80                      log.error(e.getMessage(), e);
81                  }
82              }
83          }
84      }
85  
86      private void processHandshake(int availableBytes) {
87          try {
88              while (!handshakeSeen && availableBytes > 0) {
89                  availableBytes--;
90                  handshakeBuilder.append(new String(serialPort.readBytes(1), ISO_8859_1));
91                  if (handshakeBuilder.length() >= Protocol.HANDSHAKE_RESPONSE.length()) {
92                      String handshake = handshakeBuilder.toString();
93                      if (handshake.endsWith(Protocol.HANDSHAKE_RESPONSE)) {
94                          log.info("RX <- {}", handshake);
95                          setHandshakeSeen();
96                      } else {
97                          log.error("Bad handshake: {}", handshake);
98                          if (ignoreBadHandshake) {
99                              setHandshakeSeen();
100                         } else {
101                             serialPort.close();
102                             return;
103                         }
104                     }
105                 }
106             }
107             if (!handshakeSeen) {
108                 log.debug("Current handshake: {}", handshakeBuilder);
109             }
110         } catch (IOException e) {
111             log.error(e.getMessage(), e);
112         }
113     }
114 }