/**
* Copyright (c) 2010-2016 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.binding.insteonplm.internal.driver;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.openhab.binding.insteonplm.internal.driver.hub.HubIOStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstract class for implementation for I/O stream with anything that looks
* like a PLM (e.g. the insteon hubs, serial/usb connection etc)
*
* @author Bernd Pfrommer
* @author Daniel Pfrommer
* @since 1.7.0
*/
public abstract class IOStream {
private static final Logger logger = LoggerFactory.getLogger(IOStream.class);
protected InputStream m_in = null;
protected OutputStream m_out = null;
/**
* read data from iostream
*
* @param b byte array (output)
* @param offset offset for placement into byte array
* @param readSize size to read
* @return number of bytes read
*/
public int read(byte[] b, int offset, int readSize) throws InterruptedException {
int len = 0;
while (len < 1) {
try {
len = m_in.read(b, offset, readSize);
if (Thread.interrupted()) {
throw new InterruptedException();
}
} catch (IOException e) {
logger.trace("got exception while reading: {}", e.getMessage());
while (!reconnect()) {
logger.trace("sleeping before reconnecting");
Thread.sleep(10000);
}
}
}
return (len);
}
/**
* Write data to iostream
*
* @param b byte array to write
*/
public void write(byte[] b) {
try {
m_out.write(b);
} catch (IOException e) {
logger.trace("got exception while writing: {}", e.getMessage());
while (!reconnect()) {
try {
logger.trace("sleeping before reconnecting");
Thread.sleep(10000);
} catch (InterruptedException ie) {
logger.warn("interrupted while sleeping on write reconnect");
}
}
}
}
/**
* Opens the IOStream
*
* @return true if open was successful, false if not
*/
public abstract boolean open();
/**
* Closes the IOStream
*/
public abstract void close();
/**
* reconnects the stream
*
* @return true if reconnect succeeded
*/
private synchronized boolean reconnect() {
close();
return (open());
}
/**
* Creates an IOStream from an allowed config string:
*
* /dev/ttyXYZ (serial port like e.g. usb: /dev/ttyUSB0 or alias /dev/insteon)
*
* /hub2/user:password@myinsteonhub.mydomain.com:25105,poll_time=1000 (insteon hub2 (2014))
*
* /hub/myinsteonhub.mydomain.com:9761
*
* /tcp/serialportserver.mydomain.com:port (serial port exposed via tcp, eg. ser2net)
*
* @param config
* @return reference to IOStream
*/
public static IOStream s_create(String config) {
if (config.startsWith("/hub2/")) {
return makeHub2014Stream(config);
} else if (config.startsWith("/hub/") || config.startsWith("/tcp/")) {
return makeTCPStream(config);
} else {
return new SerialIOStream(config);
}
}
private static HubIOStream makeHub2014Stream(String config) {
config = config.substring(6); // Get rid of the /hub2/ part
String user = null;
String pass = null;
int pollTime = 1000; // poll time in milliseconds
String[] parts = config.split(","); // split off options at the end
// Parse the first part, the address
String[] adr = parts[0].split("@");
String[] hostPort;
if (adr.length > 1) {
String[] userPass = adr[0].split(":");
user = userPass[0];
pass = userPass[1];
hostPort = adr[1].split(":");
} else {
hostPort = parts[0].split(":");
}
HostPort hp = new HostPort(hostPort, 25105);
// check if additional options are given
if (parts.length > 1) {
if (parts[1].trim().startsWith("poll_time")) {
pollTime = Integer.parseInt(parts[1].split("=")[1].trim());
}
}
return new HubIOStream(hp.host, hp.port, pollTime, user, pass);
}
private static TcpIOStream makeTCPStream(String config) {
config = config.substring(5); // Get rid of the /hub/ part
String[] parts = config.split(","); // split off options at the end, if any
String[] hostPort = parts[0].split(":");
HostPort hp = new HostPort(hostPort, 9761);
return new TcpIOStream(hp.host, hp.port);
}
private static class HostPort {
public String host = "localhost";
public int port = -1;
HostPort(String[] hostPort, int defaultPort) {
port = defaultPort;
host = hostPort[0];
try {
if (hostPort.length > 1) {
port = Integer.parseInt(hostPort[1]);
}
} catch (NumberFormatException e) {
logger.error("bad format for port {} ", hostPort[1], e);
}
}
}
}