001package jmri.implementation; 002 003import javax.annotation.CheckForNull; 004import javax.annotation.Nonnull; 005import javax.annotation.CheckReturnValue; 006import jmri.JmriException; 007import jmri.NamedBean; 008import jmri.AnalogIO; 009 010/** 011 * Base implementation of the AnalogIO interface. 012 * 013 * @author Daniel Bergqvist Copyright (c) 2018 014 */ 015public abstract class AbstractAnalogIO extends AbstractNamedBean implements AnalogIO { 016 017 private final boolean _commandedValueSetsKnownValue; 018 private double _commandedValue = 0.0; 019 private double _knownValue = 0.0; 020 021 /** 022 * Abstract constructor for new AnalogIO with system name 023 * 024 * @param systemName AnalogIO system name 025 * @param commandedValueSetsKnownValue true if setCommandedValue() also sets 026 * known value, false othervise 027 */ 028 public AbstractAnalogIO(@Nonnull String systemName, boolean commandedValueSetsKnownValue) { 029 super(systemName); 030 this._commandedValueSetsKnownValue = commandedValueSetsKnownValue; 031 } 032 033 /** 034 * Abstract constructor for new AnalogIO with system name and user name 035 * 036 * @param systemName AnalogIO system name 037 * @param userName AnalogIO user name 038 * @param commandedValueSetsKnownValue true if setCommandedValue() also sets 039 * known value, false othervise 040 */ 041 public AbstractAnalogIO(@Nonnull String systemName, @CheckForNull String userName, boolean commandedValueSetsKnownValue) { 042 super(systemName, userName); 043 this._commandedValueSetsKnownValue = commandedValueSetsKnownValue; 044 } 045 046 /** 047 * Sends the string to the layout. 048 * The string [u]must not[/u] be longer than the value of getMaximumLength() 049 * unless that value is zero. Some microcomputers have little memory and 050 * it's very important that this method is never called with too long strings. 051 * 052 * @param value the desired string value 053 * @throws jmri.JmriException general error when setting the value fails 054 */ 055 abstract protected void sendValueToLayout(double value) throws JmriException; 056 057 /** 058 * Set the value of this AnalogIO. Called from the implementation class 059 * when the layout updates this AnalogIO. 060 * 061 * @param newValue the new value 062 */ 063 protected void setValue(double newValue) { 064 Object _old = this._knownValue; 065 this._knownValue = newValue; 066 firePropertyChange(PROPERTY_STATE, _old, _knownValue); //NOI18N 067 } 068 069 /** {@inheritDoc} */ 070 @Override 071 public void setCommandedAnalogValue(double value) throws JmriException { 072 if (value == Double.NEGATIVE_INFINITY) { 073 throw new IllegalArgumentException("value is negative infinity"); 074 } 075 if (value == Double.POSITIVE_INFINITY) { 076 throw new IllegalArgumentException("value is positive infinity"); 077 } 078 if (Double.isNaN(value)) { 079 throw new IllegalArgumentException("value is not-a-number"); 080 } 081 082 double min = getMin(); 083 double max = getMax(); 084 085 if (value < min) { 086 if (cutOutOfBoundsValues()) value = min; 087 else throw new JmriException("value out of bounds"); 088 } 089 if (value > max) { 090 if (cutOutOfBoundsValues()) value = max; 091 else throw new JmriException("value out of bounds"); 092 } 093 _commandedValue = value; 094 095 if (_commandedValueSetsKnownValue) { 096 setValue(_commandedValue); 097 } 098 sendValueToLayout(_commandedValue); 099 } 100 101 /** {@inheritDoc} */ 102 @Override 103 public double getCommandedAnalogValue() { 104 return _commandedValue; 105 } 106 107 /** {@inheritDoc} */ 108 @Override 109 public double getKnownAnalogValue() { 110 return _knownValue; 111 } 112 113 /** 114 * Cut out of bounds values instead of throwing an exception? 115 * For example, if the AnalogIO is a display, it could be desired to 116 * accept too long strings. 117 * On the other hand, if the AnalogIO is used to send a command, a too 118 * long string is an error. 119 * 120 * @return true if long strings should be cut 121 */ 122 abstract protected boolean cutOutOfBoundsValues(); 123 124 /** {@inheritDoc} */ 125 @Override 126 public double getState(double v) { 127 return getCommandedAnalogValue(); 128 } 129 130 /** {@inheritDoc} */ 131 @Override 132 public void setState(double value) throws JmriException { 133 setCommandedAnalogValue(value); 134 } 135 136 /** {@inheritDoc} */ 137 @Override 138 @Nonnull 139 public String getBeanType() { 140 return Bundle.getMessage("BeanNameAnalogIO"); 141 } 142 143 /** 144 * {@inheritDoc} 145 * 146 * Do a string comparison. 147 */ 148 @CheckReturnValue 149 @Override 150 public int compareSystemNameSuffix(@Nonnull String suffix1, @Nonnull String suffix2, @Nonnull NamedBean n) { 151 return suffix1.compareTo(suffix2); 152 } 153 154}