📄 onewireserver.java
字号:
package net.sf.dz.daemon.onewire.owapi;import java.io.IOException;import java.util.Enumeration;import java.util.HashMap;import java.util.HashSet;import java.util.Iterator;import java.util.Map;import java.util.NoSuchElementException;import java.util.Set;import java.util.TreeMap;import java.util.TreeSet;import com.dalsemi.onewire.OneWireAccessProvider;import com.dalsemi.onewire.OneWireException;import com.dalsemi.onewire.adapter.DSPortAdapter;import com.dalsemi.onewire.adapter.OneWireIOException;import com.dalsemi.onewire.container.OneWireContainer;import com.dalsemi.onewire.container.OneWireContainer09;import com.dalsemi.onewire.container.SwitchContainer;import com.dalsemi.onewire.container.TemperatureContainer;import com.dalsemi.onewire.utils.OWPath;import org.freehold.jukebox.conf.Configuration;import org.freehold.jukebox.logger.LogChannel;import org.freehold.jukebox.sem.RWLock;import org.freehold.jukebox.service.ActiveService;import net.sf.dz.daemon.Server;import net.sf.dz.daemon.ServerModule;import net.sf.dz.daemon.onewire.DeviceContainer;import net.sf.dz.daemon.onewire.OneWireContainerListener;import net.sf.dz.daemon.onewire.OneWireNetworkEvent;import net.sf.dz.daemon.onewire.OneWireNetworkEventListener;import net.sf.dz.daemon.onewire.TemperatureContainerListener;/** * The 1-Wire® server. * * <p> * * Communicates with the 1-Wire® devices and allows to broadcast the * data from these devices, as well as to control them, from the other * applications using a protocol adapter. * * <p> * * This approach is necessitated by the fact that the 1-Wire® adapter * (at least the serial one) is not really thread safe, and the sharing on * the hardware level is not supported either. * * <p> * * In fact, this class can be considered a glorified 1-Wire® adapter * driver. * * <p> * * Even though a similar approach is implemented in the <a * href="http://www.ibutton.com/software/1wire/1wire_api.html" * target="_top">1-Wire API for Java</a>, it is not really usable at the * moment of writing, because it suffers from thread safety and locking * problems. * * <p> * * All in all, this has to be considered as a quick and dirty hack, mostly * because the underlying implementation is not perfect. However, important * thing is: it's working reliably. * * @author Copyright © <a href="mailto:vt@freehold.crocodile.org">Vadim Tkachenko</a> 2001-2002 * @version $Id: OneWireServer.java,v 1.2 2004/06/28 20:35:47 vtt Exp $ */public class OneWireServer extends ActiveService implements ServerModule, OneWireNetworkEventListener, net.sf.dz.daemon.onewire.OneWireServer { public static final LogChannel CH_ONEWIRE = new LogChannel("1-Wire"); public static final LogChannel CH_DATA = new LogChannel(CH_ONEWIRE, "data"); public static final LogChannel CH_LOCK = new LogChannel(CH_ONEWIRE, "lock"); /** * The server this module is attached to. */ private Server server; /** * Read/write lock controlling the exclusive access to the 1-Wire * devices. * * <p> * * This seems to be a better idea than using * <code>beginExclusive()/endExclusive()</code>. OneWire API uses * <code>Thread.sleep(50)</code>, which doesn't guarantee first come, * first served order, but rather a random order depending on the thread * timings. This can produce the wait times for the DS2406 handler as * long as 120 seconds, and I suspect it could be worse. * * <p> * * On the contrary, while the <code>RWLock</code> still doesn't * guarantee the FIFO order, it does provide access as soon as the * resource is free - the timings are significantly better. Next step * would be to modify the <code>RWLock</code> to guarantee the FIFO * order, whether it makes sense to do it or not - let's wait and see. */ private RWLock lock = new RWLock(); /** * The 1-Wire® adapter. */ private DSPortAdapter adapter; /** * Adapter port. * * There is no default. If the value is not specified, the module will * fail to initialize. This may be less convenient for USB adapters in * case there's just one, but a) this encourages exactness and b) this * will properly handle the case where there is more than one USB * adapter. */ private String adapterPort = null; /** * Adapter speed. * * Defaults to {@link DSPortAdapter#SPEED_REGULAR SPEED_REGULAR}. */ private int adapterSpeed = DSPortAdapter.SPEED_REGULAR; /** * Device map. * * The key is the address, the value is the device container. */ private Map address2device = new TreeMap(); /** * Device map. * * <p> * * The key is the device path, the value is a sorted map where the key * is the hardware address, and the value is the device container. Such * a complication is required to optimize the access by opening the * minimal number of paths and eliminating redundancy. */ private Map path2device = new HashMap(); /** * Data map. * * <p> * * The key is the device address, the value is the device state. */ private Map dataMap = new TreeMap(); /** * Low-level state map. * * The key is the device address, the value is last known state obtained * using <code>readDevice()</code>. */ private Map stateMap = new TreeMap(); /** * The listener set. */ private Set listenerSet = new HashSet(); /** * The network monitor. */ private OneWireNetworkMonitor monitor; public RWLock getLock() { return lock; } public void attach(Server server) { if ( this.server != null ) { throw new IllegalStateException("Already attached to the server"); } this.server = server; } /** * Configure the service. * * All the configuration problems have to be detected at this stage. */ protected void configure() throws Throwable { String cfroot = getConfigurationRoot(); Configuration cf = getConfiguration(); configureOneWire(cfroot, cf); } /** * Configure the 1-Wire® subsystem. * * @param cfroot Configuration root. * * @param cf The configuration object. */ private void configureOneWire(String cfroot, Configuration cf) throws Throwable { // Figure out what speed do we want try { String cfspeed = cf.getString(cfroot + ".onewire_server.serial.speed"); if ( "overdrive".equalsIgnoreCase(cfspeed) ) { adapterSpeed = DSPortAdapter.SPEED_OVERDRIVE; } else if ( "hyperdrive".equalsIgnoreCase(cfspeed) ) { adapterSpeed = DSPortAdapter.SPEED_HYPERDRIVE; } else if ( "flex".equalsIgnoreCase(cfspeed) ) { adapterSpeed = DSPortAdapter.SPEED_FLEX; } else if ( "regular".equalsIgnoreCase(cfspeed) ) { adapterSpeed = DSPortAdapter.SPEED_REGULAR; } else { if ( cfspeed != null ) { throw new IllegalArgumentException("Invalid value for " + getConfigurationRoot() + ".onewire_server.serial.speed: '" + cfspeed + "'"); } } } catch ( NoSuchElementException nseex ) { // No big deal, default is already set complain(LOG_NOTICE, CH_ONEWIRE, "No configuration value for " + cfroot + ".onewire_server.serial.speed found, using default (speed_regular)"); } // Since there's no default, there's no sense to wrap it into a // try/catch adapterPort = cf.getString(cfroot + ".onewire_server.serial.port"); } protected void startup() throws Throwable { Set portsAvailable = new TreeSet(); for ( Enumeration adapters = OneWireAccessProvider.enumerateAllAdapters(); adapters.hasMoreElements(); ) { DSPortAdapter a = (DSPortAdapter)adapters.nextElement(); complain(LOG_DEBUG, CH_ONEWIRE, "Adapter found: " + a.getAdapterName()); for ( Enumeration ports = a.getPortNames(); ports.hasMoreElements(); ) { String portName = (String)ports.nextElement(); complain(LOG_DEBUG, CH_ONEWIRE, "Port found: " + portName); if ( adapterPort.equals(portName) ) { adapter = a; // Let's not break here, to collect all available port // names } portsAvailable.add(portName); } } if ( adapter == null ) { throw new IllegalArgumentException("Port '" + adapterPort + "' unavailable, valid values: " + portsAvailable); } if ( !adapter.selectPort(adapterPort) ) { // VT: NOTE: Having succeeded at selecting the port doesn't // necessarily mean that we'll be fine. Serial based adapters // don't seem to be accessed during selectPort(), and it's quite // possible to successfully select a non-existing port. // Additional test is required to make sure we're OK. throw new IllegalArgumentException("Unable to select port '" + adapterPort + "', make sure it's the right one (available: " + portsAvailable + ")"); } try { // Now, *this* should take care of it... adapter.reset(); } catch ( OneWireIOException ex ) { if ( "Error communicating with adapter".equals(ex.getMessage()) ) { throw new IOException("Port '" + adapterPort + "' doesn't seem to have adapter connected, check others: " + portsAvailable); } } complain(LOG_INFO, CH_ONEWIRE, "Adapter class: " + adapter.getClass().getName()); complain(LOG_INFO, CH_ONEWIRE, "Adapter port: " + adapterPort); // VT: NOTE: It is not necessary to use the lock at this point // because the service is not yet started try { adapter.setSpeed(adapterSpeed); complain(LOG_INFO, CH_ONEWIRE, "set adapter speed to " + adapterSpeed); } catch ( Throwable t ) { complain(LOG_ERR, CH_ONEWIRE, "Failed to set adapter speed, cause:", t); } monitor = new OneWireNetworkMonitor(adapter, lock); monitor.setLogger(getLogger()); monitor.start(); monitor.addListener(this); monitor.getSemUp().waitFor(); } /** * Keep polling the device state until stopped. */ protected void execute() throws Throwable { while ( isEnabled() ) { try { poll(); } catch ( java.util.ConcurrentModificationException cmex ) { // No big deal complain(LOG_DEBUG, CH_ONEWIRE, "Arrival/departure during poll, ignored"); } catch ( Throwable t ) { complain(LOG_ERR, CH_ONEWIRE, "Poll broken:", t); // Possibly, the cause of this was a network departure. // Let's refresh the device map monitor.rescan(); } } } protected void shutdown(Throwable cause) throws Throwable { complain(LOG_INFO, CH_ONEWIRE, "Shutting down..."); monitor.removeListener(this); monitor.stop().waitFor(); // VT: FIXME: Should I close the adapter? // VT: FIXME: The freePort() call seems to be doing something nasty // to the virtual machine, commented out so far - it shuts down just // fine... Wonder what's happening there? //adapter.freePort(); complain(LOG_INFO, CH_ONEWIRE, "Shut down"); } private void poll() throws Throwable { Map localDataMap = new TreeMap(); Object lockToken = null; long start = System.currentTimeMillis();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -