📄 onewirenetworkmonitor.java
字号:
package net.sf.dz.daemon.onewire.owapi;import java.util.Enumeration;import java.util.Map;import java.util.HashSet;import java.util.Iterator;import java.util.LinkedList;import java.util.List;import java.util.Set;import java.util.TreeMap;import org.freehold.jukebox.logger.LogChannel;import org.freehold.jukebox.sem.EventSemaphore;import org.freehold.jukebox.sem.RWLock;import org.freehold.jukebox.sem.SemaphoreTimeoutException;import org.freehold.jukebox.service.ActiveService;import com.dalsemi.onewire.adapter.DSPortAdapter;import com.dalsemi.onewire.container.OneWireContainer;import com.dalsemi.onewire.container.OneWireContainer1F;import com.dalsemi.onewire.container.SwitchContainer;import com.dalsemi.onewire.utils.OWPath;import net.sf.dz.daemon.onewire.OneWireNetworkEvent;import net.sf.dz.daemon.onewire.OneWireNetworkEventListener;/** * 1-Wire® network monitor. * * <p> * * The difference between this class and DalSemi's {@link * com.dalsemi.onewire.utils.NetworkMonitor NetworkMonitor} is that this * class not only searches the currently open branches, but manipulates the * MicroLAN couplers (DS2409) it finds in order to get a complete network * map. It may not be desirable for a generic network browser, but it is * perfectly OK in the context of this project. * * <p> * * Currently, the only devices that this monitor is looking for are family * 0x10 and 0x12 (temperature sensors and DS2406/DS2407 switches). However, * should the need arise, the modification is trivial. * * @author Copyright © <a href="mailto:vt@freehold.crocodile.org">Vadim Tkachenko</a> 2001-2002 * @version $Id: OneWireNetworkMonitor.java,v 1.2 2004/06/28 20:35:47 vtt Exp $ */public class OneWireNetworkMonitor extends ActiveService { public static final LogChannel CH_NM = new LogChannel("OWNetworkMonitor"); public static final LogChannel CH_LOCK = new LogChannel(CH_NM, "lock"); /** * Adapter to monitor. */ private DSPortAdapter adapter; /** * Lock to use for mutual exclusive access to the adapter. * * I hope there'll be a day when the adapter itself will provide this * lock... */ private RWLock lock; /** * Families we're interested in. * * Currently only 0x10 and 0x12. */ private byte families[] = { 0x10, 0x12 }; // DS1820, DS2406 /** * Device map. * * The key is the address as string, the value is the device container * for that address. */ private Map address2device = new TreeMap(); /** * Path map. * * The key is the address as string, the value is the path to the device * with that address. */ private Map address2path = new TreeMap(); /** * Listener set. */ private Set listenerSet = new HashSet(); /** * Rescan semaphore. */ private EventSemaphore rescan = new EventSemaphore(); /** * Rescan timeout. * * Default is 1 minute. */ private long timeout = 60000; public OneWireNetworkMonitor(DSPortAdapter adapter, RWLock lock) { if ( adapter == null || lock == null ) { throw new IllegalArgumentException("One of parameters is null: adapter: " + adapter + ", lock: " + lock); } this.adapter = adapter; this.lock = lock; } protected void startup() throws Throwable { } protected void execute() throws Throwable { while ( isEnabled() ) { try { browse(); // Currently, browse() takes 10+ seconds. Let's give them a break try { rescan.waitFor(timeout); complain(LOG_NOTICE, CH_NM, "Rescan requested"); } catch ( SemaphoreTimeoutException stex ) { // Don't do anything, this is a normal outcome when the // semaphore times out, which happens every time the // rescan() wasn't called. } } catch ( Throwable t ) { String message = t.getMessage(); if ( message != null && message.startsWith("Error short") ) { complain(LOG_ALERT, CH_NM, "1-Wire Network shorted out!!!", t); // VT: FIXME: This is a critical failure. All the // listeners must be notified immediately - this most // probably means loss of all sensors, and what's worse, // this means loss of control over HVAC actuator // devices, though the devices themselves have to be // powered and therefore keep their state - in other // words, if the HVAC is on, it will stay on. Very Bad // Thing (TM). // Well, and of course, it *has* to be this inconvenient // - the only place where a network short can be // detected is where you actually *write* something to // it. Both places are outside of normal control flow, // and they're asynchronous. handleShortCircuit(); // Now, the short circuit is a condition that is // detected at the very beginning of browse(), very // fast. Let to its own devices, this will cycle // indefinitely, so it would be a good idea to restrict // the cycle rate. Thread.sleep(1000); } else { complain(LOG_WARNING, CH_NM, "Browse failure:", t); } } } } protected void shutdown(Throwable cause) throws Throwable { } /** * Find all devices on 1-Wire® network. * * <p> * * This is an intrusive search that is going to shuffle all the MicroLAN * couplers on the network. */ private void browse() throws Throwable { long start = System.currentTimeMillis(); Map localAddress2device = new TreeMap(); Map localAddress2path = new TreeMap(); Object lockToken = null; try { lockToken = lock.getWriteLock(); complain(LOG_DEBUG, CH_LOCK, "Browse: got lock in " + (System.currentTimeMillis() - start) + "ms"); start = System.currentTimeMillis(); adapter.setSearchAllDevices(); adapter.targetAllFamilies(); OWPath rootPath = new OWPath(adapter); browse(rootPath, localAddress2device, localAddress2path); complain(LOG_DEBUG, CH_NM, "Browse: done in " + (System.currentTimeMillis() - start) + "ms"); } finally { lock.release(lockToken); complain(LOG_DEBUG, CH_LOCK, "Browse: complete in " + (System.currentTimeMillis() - start) + "ms"); } handleDepartures(localAddress2device, localAddress2path); handleArrivals(localAddress2device, localAddress2path); address2device = localAddress2device; address2path = localAddress2path; } /** * Browse the path. * * @param path Path to start browsing at. * * @param address2device Input/output parameter to fill out. The key is * the address as string, the value is the device container. * * @param address2path Inout/output parameter to fill out. The key is * the address as string, the value is the path to that address. */ private void browse(OWPath path, Map address2device, Map address2path) throws Throwable { closeAllPaths(); path.open(); List switchList = new LinkedList(); for ( Enumeration e = adapter.getAllDeviceContainers(); e.hasMoreElements(); ) { OneWireContainer owc = (OneWireContainer)e.nextElement(); String address = owc.getAddressAsString(); // This device might have been discovered already if ( address2device.get(address) != null ) { continue; } complain(LOG_DEBUG, CH_NM, "Found: " + owc.getName() + " " + address + " at " + path); address2device.put(address, owc); address2path.put(address, path); if ( owc instanceof OneWireContainer1F ) { OWPath channel1 = new OWPath(adapter, path); channel1.add(owc, 0); switchList.add(channel1); OWPath channel2 = new OWPath(adapter, path); channel2.add(owc, 1); switchList.add(channel1); } } for ( Iterator i = switchList.iterator(); i.hasNext(); ) { OWPath branchPath = (OWPath)i.next(); browse(branchPath, address2device, address2path); } } /** * Rescan the network now. * */ public void rescan() { rescan.post(); } private void handleArrivals(Map newDeviceMap, Map newPathMap) { for ( Iterator i = newDeviceMap.keySet().iterator(); i.hasNext(); ) { String address = i.next().toString(); if ( !address2device.containsKey(address) ) { complain(LOG_INFO, CH_NM, "Arrived: " + ((OneWireContainer)newDeviceMap.get(address)).getName() + " " + address + " on " + newPathMap.get(address)); OneWireNetworkEvent e = new OwapiNetworkEvent(this, adapter, address, (OWPath)newPathMap.get(address)); for ( Iterator li = listenerSet.iterator(); li.hasNext(); ) { ((OneWireNetworkEventListener)li.next()).networkArrival(e); } } } } private void handleDepartures(Map newDeviceMap, Map newPathMap) { for ( Iterator i = address2device.keySet().iterator(); i.hasNext(); ) { String address = i.next().toString(); OWPath oldPath = (OWPath)address2path.get(address); OWPath newPath = (OWPath)newPathMap.get(address); if ( oldPath == null ) { // This means that we're actually seeing the arrival, not // departure continue; } // A little shortcut: if the new path is null, this means that // the device has departed, so we're killing two hares with one // shot: if the new path is not null, this means that the device // has moved from one path to another if ( newPath == null || !oldPath.equals(newPath) ) { // The path has changed complain(LOG_INFO, CH_NM, "Departed: " + address + " from " + oldPath); OneWireNetworkEvent e = new OwapiNetworkEvent(this, adapter, address, oldPath); for ( Iterator li = listenerSet.iterator(); li.hasNext(); ) { ((OneWireNetworkEventListener)li.next()).networkDeparture(e); } } } } private void handleShortCircuit() { for ( Iterator i = address2device.keySet().iterator(); i.hasNext(); ) { String address = i.next().toString(); OneWireNetworkEvent e = new OwapiNetworkEvent(this, adapter, address, null); for ( Iterator li = listenerSet.iterator(); li.hasNext(); ) { ((OneWireNetworkEventListener)li.next()).networkFault(e, "1-Wire network short circuit"); } } } public void addListener(OneWireNetworkEventListener listener) { listenerSet.add(listener); } public void removeListener(OneWireNetworkEventListener listener) { listenerSet.remove(listener); } private void closeAllPaths() throws Throwable { // DS2409 specific - skip, all lines off adapter.reset(); adapter.putByte(0x00CC); adapter.putByte(0x0066); adapter.getByte(); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -