/** * 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.util.HashMap; import java.util.concurrent.locks.ReentrantLock; import org.openhab.binding.insteonplm.internal.device.InsteonAddress; import org.openhab.binding.insteonplm.internal.message.Msg; import org.openhab.binding.insteonplm.internal.message.MsgListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The driver class manages the modem ports. * XXX: at this time, only a single modem has ever been used. Expect * the worst if you connect multiple modems. When multiple modems * are required, this code needs to be tested and fixed. * * @author Bernd Pfrommer * @since 1.5.0 */ public class Driver { private static final Logger logger = LoggerFactory.getLogger(Driver.class); // maps device name to serial port, i.e /dev/insteon -> Port object private HashMap<String, Port> m_ports = new HashMap<String, Port>(); private DriverListener m_listener = null; // single listener for notifications private HashMap<InsteonAddress, ModemDBEntry> m_modemDBEntries = new HashMap<InsteonAddress, ModemDBEntry>(); private ReentrantLock m_modemDBEntriesLock = new ReentrantLock(); private int m_modemDBRetryTimeout = 120000; // in milliseconds public void setDriverListener(DriverListener listener) { m_listener = listener; } public void setModemDBRetryTimeout(int timeout) { m_modemDBRetryTimeout = timeout; for (Port p : m_ports.values()) { p.setModemDBRetryTimeout(m_modemDBRetryTimeout); } } public boolean isReady() { for (Port p : m_ports.values()) { if (!p.isRunning()) { return false; } } return true; } public HashMap<InsteonAddress, ModemDBEntry> lockModemDBEntries() { m_modemDBEntriesLock.lock(); return m_modemDBEntries; } public void unlockModemDBEntries() { m_modemDBEntriesLock.unlock(); } /** * Add new port (modem) to the driver * * @param name the name of the port (from the config file, e.g. port_0, port_1, etc * @param port the device name, e.g. /dev/insteon, /dev/ttyUSB0 etc */ public void addPort(String name, String port) { if (m_ports.keySet().contains(port)) { logger.warn("ignored attempt to add duplicate port: {} {}", name, port); } else { Port p = new Port(port, this); p.setModemDBRetryTimeout(m_modemDBRetryTimeout); m_ports.put(port, p); logger.debug("added new port: {} {}", name, port); } } /** * Register a message listener with a port * * @param listener the listener who wants to listen to port messages * @param port the port (e.g. /dev/ttyUSB0) to which the listener listens */ public void addMsgListener(MsgListener listener, String port) { if (m_ports.keySet().contains(port)) { m_ports.get(port).addListener(listener); } else { logger.error("referencing unknown port {}!", port); } } public void startAllPorts() { for (Port p : m_ports.values()) { p.start(); } } public void stopAllPorts() { for (Port p : m_ports.values()) { p.stop(); } } /** * Write message to a port * * @param port name of the port to write to (e.g. '/dev/ttyUSB0') * @param m the message to write * @throws IOException */ public void writeMessage(String port, Msg m) throws IOException { Port p = getPort(port); if (p == null) { logger.error("cannot write to unknown port {}", port); throw new IOException(); } p.writeMessage(m); } public String getDefaultPort() { return (m_ports.isEmpty() ? null : m_ports.keySet().iterator().next()); } public int getNumberOfPorts() { int n = 0; for (Port p : m_ports.values()) { if (p.isRunning()) { n++; } } return n; } public boolean isMsgForUs(InsteonAddress toAddr) { if (toAddr == null) { return false; } for (Port p : m_ports.values()) { if (p.getAddress().equals(toAddr)) { return true; } } return false; } /** * Get port object corresponding to device * * @param port device name of port (e.g. /dev/ttyUSB0) * @return corresponding Port object or null if not found */ public Port getPort(String port) { if (port.equalsIgnoreCase("DEFAULT")) { if (m_ports.isEmpty()) { logger.error("no default port found!"); return null; } return m_ports.values().iterator().next(); } if (!m_ports.containsKey(port)) { logger.error("no port of name {} found!", port); return null; } return m_ports.get(port); } public void modemDBComplete(Port port) { // check if all ports have a complete device list if (!isModemDBComplete()) { return; } // if yes, notify listener m_listener.driverCompletelyInitialized(); } public boolean isModemDBComplete() { // check if all ports have a complete device list for (Port p : m_ports.values()) { if (!p.isModemDBComplete()) { return false; } } return true; } }