001package jmri.jmrix.nce;
002
003import jmri.JmriException;
004import jmri.Sensor;
005import org.slf4j.Logger;
006import org.slf4j.LoggerFactory;
007
008/**
009 * Model an NCE AIU
010 * <p>
011 * These AIUs are numbered ala the cab bus, from 1 to 63. AIU number 1 carries
012 * sensors 1 to 14; AIU 2 from 17 to 30, etc.
013 * <p>
014 * The array of sensor states is used to update sensor known state only when
015 * there's a change on the cab bus. This allows for the sensor state to be
016 * updated within the program, keeping this updated state until the next change
017 * on the cab bus. E.g. you can manually change a state via an icon, and not
018 * have it change back the next time that AIU is polled.
019 *
020 * @author Bob Jacobsen Copyright (C) 2003, 2005
021 */
022public class NceAIU {
023
024    public NceAIU() {
025        for (int i = 0; i < 15; i++) {
026            sensorArray[i] = null;
027            sensorLastSetting[i] = Sensor.UNKNOWN;
028        }
029    }
030
031    Sensor[] sensorArray = new Sensor[15];
032    int[] sensorLastSetting = new int[15];
033    int lastAIUValue = 0xc000;      // can't ever take this value
034
035    /**
036     *
037     * @param bits int value of response from poll command
038     */
039    public void markChanges(int bits) {
040        if (bits != lastAIUValue) {
041            if (log.isDebugEnabled()) {
042                log.debug("sensor array change from {} to {}", Integer.toHexString(lastAIUValue), Integer.toHexString(bits));
043            }
044            lastAIUValue = bits;
045            for (int i = 0; i < 14; i++) {
046                if (sensorArray[i] != null) {
047                    boolean value = ((bits & 1) == 0) ^ sensorArray[i].getInverted();
048                    if (value) {
049                        sensorChange(i, Sensor.ACTIVE);
050                    } else {
051                        sensorChange(i, Sensor.INACTIVE);
052                    }
053                }
054                bits = bits / 2;
055            }
056        }
057    }
058
059    /**
060     * set state of a single sensor based on AIU input
061     *
062     * @param offset   sensor number within the current array
063     * @param newState new state (Sensor.ACTIVE / .INACTIVE)
064     */
065    public void sensorChange(int offset, int newState) {
066        if (sensorArray[offset] != null && sensorLastSetting[offset] != newState) {
067            sensorLastSetting[offset] = newState;
068            if (log.isDebugEnabled()) {
069                String newStateStr = "Active";
070                if (newState == Sensor.INACTIVE) {
071                    newStateStr = "Inactive";
072                }
073                log.debug("setting sensor {}: {}", sensorArray[offset].getSystemName(), newStateStr);
074            }
075            try {
076                sensorArray[offset].setKnownState(newState);
077            } catch (JmriException e) {
078                log.error("exception in sensorChange", e);
079            }
080        }
081    }
082
083    /**
084     * The numbers here are 0 to 15, not 1 to 16
085     * @param s bit within the AIU card
086     * @param i index for AIU card
087     *
088     */
089    public void registerSensor(Sensor s, int i) {
090        sensorArray[i] = s;
091    }
092
093    /**
094     * Return the sensor object for the specified AIU
095     *
096     * @param index AIU index (0..15)
097     * @return sensor object
098     */
099    public Sensor getSensor(int index) {
100        return sensorArray[index];
101    }
102
103    private final static Logger log = LoggerFactory.getLogger(NceAIU.class);
104}
105
106