001package jmri.jmrix.openlcb; 002 003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 004import jmri.DccLocoAddress; 005import jmri.LocoAddress; 006import jmri.jmrix.AbstractThrottle; 007import jmri.SystemConnectionMemo; 008import org.openlcb.OlcbInterface; 009import org.openlcb.implementations.throttle.ThrottleImplementation; 010import org.slf4j.Logger; 011import org.slf4j.LoggerFactory; 012 013/** 014 * An implementation of DccThrottle for OpenLCB. 015 * 016 * @author Bob Jacobsen Copyright (C) 2012 017 */ 018public class OlcbThrottle extends AbstractThrottle { 019 020 /** 021 * Constructor 022 * @param address Dcc loco address 023 * @param memo system connection memo 024 */ 025 public OlcbThrottle(DccLocoAddress address, SystemConnectionMemo memo) { 026 super(memo); 027 OlcbInterface iface = memo.get(OlcbInterface.class); 028 029 // cache settings. It would be better to read the 030 // actual state, but I don't know how to do this 031 this.speedSetting = 0; 032 // Functions default to false 033 this.isForward = true; 034 035 this.address = address; 036 037 // create OpenLCB library object that does the magic & activate 038 if (iface.getNodeStore() == null) { 039 log.error("Failed to access Mimic Node Store"); 040 } 041 if (iface.getDatagramService() == null) { 042 log.error("Failed to access Datagram Service"); 043 } 044 if (address instanceof OpenLcbLocoAddress) { 045 oti = new ThrottleImplementation( 046 ((OpenLcbLocoAddress) address).getNode(), 047 iface.getNodeStore(), 048 iface.getDatagramService() 049 ); 050 } else { 051 oti = new ThrottleImplementation( 052 this.address.getNumber(), 053 this.address.isLongAddress(), 054 iface.getNodeStore(), 055 iface.getDatagramService() 056 ); 057 } 058 oti.start(); 059 } 060 061 final ThrottleImplementation oti; 062 063 final DccLocoAddress address; 064 065 /** 066 * {@inheritDoc} 067 */ 068 @Override 069 public LocoAddress getLocoAddress() { 070 return address; 071 } 072 073 /** 074 * {@inheritDoc} 075 */ 076 @Override 077 public String toString() { 078 return getLocoAddress().toString(); 079 } 080 081 /** 082 * Set the speed and direction 083 * <p> 084 * This intentionally skips the emergency stop value of 1. 085 * 086 * @param speed Number from 0 to 1; less than zero is emergency stop 087 */ 088 @SuppressFBWarnings(value = "FE_FLOATING_POINT_EQUALITY") // OK to compare floating point, notify on any change 089 @Override 090 public void setSpeedSetting(float speed) { 091 float oldSpeed = this.speedSetting; 092 if (speed > 1.0) { 093 log.warn("Speed was set too high: {}", speed); 094 } 095 this.speedSetting = speed; 096 097 // send to OpenLCB 098 if (speed >= 0.0) { 099 oti.setSpeed(speed * 100.0, isForward); 100 } else { 101 oti.doEmergencyStop(); 102 } 103 104 // notify 105 firePropertyChange(SPEEDSETTING, oldSpeed, this.speedSetting); 106 record(speed); 107 } 108 109 /** 110 * {@inheritDoc} 111 */ 112 @Override 113 public void setIsForward(boolean forward) { 114 boolean old = isForward; 115 isForward = forward; 116 setSpeedSetting(speedSetting); // send the command 117 firePropertyChange(ISFORWARD, old, isForward); 118 } 119 120 /** 121 * {@inheritDoc} 122 */ 123 @Override 124 public void setFunction(int functionNum, boolean newState) { 125 updateFunction(functionNum, newState); 126 // send to OpenLCB 127 oti.setFunction(functionNum, (newState ? 1 : 0)); 128 } 129 130 /** 131 * {@inheritDoc} 132 */ 133 @Override 134 protected void throttleDispose() { 135 log.debug("throttleDispose() called"); 136 finishRecord(); 137 } 138 139 // initialize logging 140 private final static Logger log = LoggerFactory.getLogger(OlcbThrottle.class); 141 142}