]> git.basschouten.com Git - openhab-addons.git/blob
7159ea3bff3cf3536f0c6d040146210c77e18859
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.dsmr.internal.device.connector;
14
15 import java.io.BufferedInputStream;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.util.Optional;
19
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 /**
26  * Base class for connectors. Reads data from an input stream. Subclasses should implement connection specific methods
27  * and trigger the reading of the data.
28  *
29  * @author M. Volaart - Initial contribution
30  * @author Hilbrand Bouwkamp - Major refactoring. Code moved around from other classes.
31  */
32 @NonNullByDefault
33 class DSMRBaseConnector {
34
35     private final Logger logger = LoggerFactory.getLogger(DSMRBaseConnector.class);
36
37     /**
38      * Listener to send received data and errors to.
39      */
40     private final DSMRConnectorListener dsmrConnectorListener;
41
42     /**
43      * 1Kbyte buffer for storing received data.
44      */
45     private final byte[] buffer = new byte[1024]; // 1K
46
47     /**
48      * Read lock to have 1 process reading at a time.
49      */
50     private final Object readLock = new Object();
51
52     /**
53      * Keeps track of the open state of the connector.
54      */
55     private boolean open;
56
57     public DSMRBaseConnector(final DSMRConnectorListener connectorListener) {
58         this.dsmrConnectorListener = connectorListener;
59     }
60
61     /**
62      * Input stream reading the Serial port.
63      */
64     private @Nullable BufferedInputStream inputStream;
65
66     /**
67      * Opens the connector with the given stream to read data from.
68      *
69      * @param inputStream input stream to read data from
70      * @throws IOException throws exception in case input stream is null
71      */
72     protected void open(@Nullable final InputStream inputStream) throws IOException {
73         if (inputStream == null) {
74             throw new IOException("Inputstream is null");
75         }
76         this.inputStream = new BufferedInputStream(inputStream);
77         open = true;
78     }
79
80     /**
81      * @return Returns true if connector is in state open
82      */
83     protected boolean isOpen() {
84         return open;
85     }
86
87     /**
88      * Closes the connector.
89      */
90     protected void close() {
91         open = false;
92         if (inputStream != null) {
93             try {
94                 inputStream.close();
95             } catch (final IOException ioe) {
96                 logger.debug("Failed to close reader", ioe);
97             }
98         }
99         inputStream = null;
100     }
101
102     /**
103      * Reads available data from the input stream.
104      */
105     protected void handleDataAvailable() {
106         try {
107             synchronized (readLock) {
108                 final BufferedInputStream localInputStream = inputStream;
109
110                 if (localInputStream != null) {
111                     int bytesAvailable = localInputStream.available();
112                     while (bytesAvailable > 0) {
113                         final int bytesAvailableRead = localInputStream.read(buffer, 0,
114                                 Math.min(bytesAvailable, buffer.length));
115
116                         if (open && bytesAvailableRead > 0) {
117                             dsmrConnectorListener.handleData(buffer, bytesAvailableRead);
118                         } else {
119                             logger.debug("Expected bytes {} to read, but {} bytes were read", bytesAvailable,
120                                     bytesAvailableRead);
121                         }
122                         bytesAvailable = localInputStream.available();
123                     }
124                 }
125             }
126         } catch (final IOException e) {
127             dsmrConnectorListener.handleError(DSMRErrorStatus.SERIAL_DATA_READ_ERROR,
128                     Optional.ofNullable(e.getMessage()).orElse(""));
129             logger.debug("Exception on read data", e);
130         }
131     }
132 }