001package jmri.jmrix.can.cbus.node;
002
003import javax.annotation.CheckForNull;
004
005import jmri.PowerManager;
006import jmri.jmrix.can.CanSystemConnectionMemo;
007import jmri.jmrix.can.cbus.CbusPowerManager;
008
009import org.slf4j.Logger;
010import org.slf4j.LoggerFactory;
011
012/**
013 * Class to represent a node.
014 *
015 * @author Steve Young Copyright (C) 2019
016 */
017public class CbusBasicNodeWithMgrsCommandStation extends CbusBasicNodeWithManagers {
018
019    private int _csNum;
020    private boolean _StatResponseFlagsAccurate;
021    private int _csFlags;
022
023    /**
024     * Create a new CbusBasicNode with Managers and Command Station
025     *
026     * @param connmemo   The CAN Connection to use
027     * @param nodenumber The Node Number
028     */
029    public CbusBasicNodeWithMgrsCommandStation( @CheckForNull CanSystemConnectionMemo connmemo, int nodenumber) {
030        super(connmemo, nodenumber);
031        _csNum = -1;
032        _csFlags = -1;
033        _StatResponseFlagsAccurate = false;
034    }
035
036    /**
037     * Set a Command Station Number for this Node
038     *
039     * @param csnum Command station Number, normally 0 if using a single command
040     *              station
041     */
042    public void setCsNum(int csnum) {
043        _csNum = csnum;
044    }
045
046    /**
047     * Get Command station number.
048     * <p>
049     * 0 is normally default for a command station
050     *
051     * @return -1 if node is NOT a Command Station, else CS Number.
052     */
053    public int getCsNum() {
054        return _csNum;
055    }
056
057    /**
058     * Set the flags reported by a Command Station
059     * <p>
060     * This will update Track Power On / Off, etc. as per the values passed.
061     * Currently unused by CANCMD v4 which sets the
062     * setStatResponseFlagsAccurate(false)
063     *
064     * @param flags the int value of the Command Station flags
065     */
066    public void setCsFlags(int flags) {
067        log.debug("flags value {}", flags);
068
069        // flags value in STAT response not accurate for CANCMD v4
070        if (!getStatResponseFlagsAccurate()) {
071            return;
072        }
073        _csFlags = flags;
074
075        // 0 - Hardware Error (self test)
076        // 1 - Track Error
077        // 2 - Track On/ Off
078        // 3 - Bus On/ Halted
079        // 4 - EM. Stop all performed
080        // 5 - Reset done
081        // 6 - Service mode (programming) On/ Off
082        checkSingleFlag(0, "Command Station {} Reporting Hardware Error (self test)");
083        checkSingleFlag(1, "Command Station {} Reporting Track Error");
084
085        // flag 2 handled by CbusPowerManager
086        // listening for RSTAT flag bit 2 here rather than power manager in case in future 
087        // we can direct to power zones rather than whole layout power
088        // it's also a per command station report than a per layout report
089        // TODO: JMRI has multiple PowerManagers so let the correct PowerManager
090        // just handle this correctly instead of assuming that the default
091        // is a CbusPowerManager
092        setTrackPower(((flags >> 2) & 1) == 1);
093
094        checkSingleFlag(3, "Command Station {} Reporting Bus Halted");
095
096    }
097
098    private void setTrackPower(boolean powerOn) {
099        CbusPowerManager pm = (CbusPowerManager) _memo.get(PowerManager.class);
100        pm.updatePower(powerOn ? PowerManager.ON : PowerManager.OFF);
101    }
102
103    private void checkSingleFlag(int flagNum, String errorText) {
104        if (((_csFlags >> flagNum) & 1) == 1) {
105            log.error("{} CS{} Node {}",errorText, getCsNum(), getNodeNumber());
106        }
107    }
108
109    /**
110     * Set Disable Command Station Flag Reporting
111     *
112     * @param accurate set false to ignore the Command Station Flags
113     */
114    public void setStatResponseFlagsAccurate(boolean accurate) {
115        _StatResponseFlagsAccurate = accurate;
116    }
117
118    /**
119     * Get if Command Station Flag Reporting is accurate. Defaults to false
120     *
121     * @return true if accurate, else false
122     */
123    public boolean getStatResponseFlagsAccurate() {
124        return _StatResponseFlagsAccurate;
125    }
126
127    private static final Logger log = LoggerFactory.getLogger(CbusBasicNodeWithMgrsCommandStation.class);
128
129}