001package jmri.jmrix.loconet; 002 003import jmri.Sensor; 004import jmri.implementation.AbstractSensor; 005import org.slf4j.Logger; 006import org.slf4j.LoggerFactory; 007 008/** 009 * Extend jmri.AbstractSensor for LocoNet layouts. 010 * <p> 011 * Some of the message formats used in this class are Copyright Digitrax, Inc. 012 * and used with permission as part of the JMRI project. That permission does 013 * not extend to uses in other software products. If you wish to use this code, 014 * algorithm or these message formats outside of JMRI, please contact Digitrax 015 * Inc for separate permission. 016 * 017 * @author Bob Jacobsen Copyright (C) 2001 018 */ 019public class LnSensor extends AbstractSensor { 020 021 private LnSensorAddress a; 022 023 public LnSensor(String systemName, String userName, LnTrafficController tc, String prefix) { 024 super(systemName, userName); 025 this.tc = tc; 026 init(systemName, prefix); 027 } 028 029 public LnSensor(String systemName, LnTrafficController tc, String prefix) { 030 super(systemName); 031 this.tc = tc; 032 init(systemName, prefix); 033 } 034 035 LnTrafficController tc; 036 037 /** 038 * Common initialization for both constructors 039 */ 040 private void init(String systemName, String prefix) { 041 // store address forms 042 a = new LnSensorAddress(systemName, prefix); 043 if (log.isDebugEnabled()) { 044 log.debug("create address {}", a); 045 } 046 } 047 048 /** 049 * Request an update on status by sending a LocoNet message. 050 * The only known way to do this from LocoNet is to request the 051 * status of _all_ devices, which is here considered too 052 * heavyweight. 053 * See LnSensorManager.updateAll() 054 */ 055 @Override 056 public void requestUpdateFromLayout() { 057 } 058 059 /** 060 * User request to set the state, which means that we need to broadcast the 061 * new state over the loconet so that other attached devices. The incoming message 062 * will in turn, be processed by the SensorManager. 063 */ 064 @Override 065 public void setKnownState(int s) throws jmri.JmriException { 066 // send OPC_INPUT_REP with new state to this address 067 LocoNetMessage l = new LocoNetMessage(4); 068 l.setOpCode(LnConstants.OPC_INPUT_REP); 069 a.insertAddress(l); 070 // set state 071 if ((s == Sensor.ACTIVE) ^ _inverted) { 072 l.setElement(2, l.getElement(2) | 0x10); 073 } // otherwise is already OK 074 l.setElement(2, l.getElement(2) | 0x40); 075 // send 076 tc.sendLocoNetMessage(l); 077 } 078 079 /** 080 * implementing classes will typically have a function/listener to get 081 * updates from the layout, which will then call public void 082 * firePropertyChange(String propertyName, Object oldValue, Object newValue) 083 * _once_ if anything has changed state (or set the commanded state 084 * directly) 085 * 086 * @param l LocoNet message from manager. 087 */ 088 public void messageFromManager(LocoNetMessage l) { 089 // parse message type 090 switch (l.getOpCode()) { 091 case LnConstants.OPC_INPUT_REP: { /* page 9 of LocoNet PE */ 092 093 int sw1 = l.getElement(1); 094 int sw2 = l.getElement(2); 095 if (a.matchAddress(sw1, sw2)) { 096 // save the state 097 boolean state = ((sw2 & 0x10) != 0) ^ _inverted; 098 if (log.isDebugEnabled()) { 099 log.debug("INPUT_REP received with valid address, old state {} new packet {}", getRawState(), state); // NOI18N 100 } 101 if (state && getRawState() != Sensor.ACTIVE) { 102 if (log.isDebugEnabled()) { 103 log.debug("Set ACTIVE"); // NOI18N 104 } 105 setOwnState(Sensor.ACTIVE); 106 } else if ((!state) && getRawState() != Sensor.INACTIVE) { 107 if (log.isDebugEnabled()) { 108 log.debug("Set INACTIVE"); // NOI18N 109 } 110 setOwnState(Sensor.INACTIVE); 111 } 112 } 113 return; 114 } 115 default: 116 return; 117 } 118 // reach here only in error 119 } 120 121 private final static Logger log = LoggerFactory.getLogger(LnSensor.class); 122 123}