001package jmri.jmrix.dccpp;
002
003import jmri.JmriException;
004import jmri.managers.AbstractPowerManager;
005
006/**
007 * DCCppPowerManager.java
008 *
009 * PowerManager implementation for controlling layout power
010 *
011 * @author Bob Jacobsen Copyright (C) 2001
012 * @author Paul Bender Copyright (C) 2003-2010
013 * @author Mark Underwood Copyright (C) 2015
014  *
015 * Based on XNetPowerManager by Bob Jacobsen and Paul Bender
016 */
017public class DCCppPowerManager extends AbstractPowerManager<DCCppSystemConnectionMemo> implements DCCppListener {
018
019    private DCCppTrafficController tc = null;
020
021    /**
022     * Create a new DCCppPowerManager.
023     * Adds listener to connection.
024     * Requests power update from layout.
025     * @param memo the Connection.
026     */
027    public DCCppPowerManager(DCCppSystemConnectionMemo memo) {
028        super(memo);
029        // connect to the TrafficManager
030        tc = memo.getDCCppTrafficController();
031        tc.addDCCppListener(DCCppInterface.CS_INFO, this);
032        DCCppPowerManager.this.requestUpdateFromLayout();
033    }
034
035    /**
036     * Set the Power status.
037     * After sending to the layout, requests power status update.
038     * {@inheritDoc }
039     */
040    @Override
041    public void setPower(int v) throws JmriException {
042        int old = power;
043        power = UNKNOWN;
044        checkTC();
045        if (v == ON) {
046            // send TRACK_POWER_ON
047            tc.sendDCCppMessage(DCCppMessage.makeTrackPowerOnMsg(), this);
048        } else if (v == OFF) {
049            // send TRACK_POWER_OFF
050            tc.sendDCCppMessage(DCCppMessage.makeTrackPowerOffMsg(), this);
051        }
052        firePowerPropertyChange(old, power);
053        // Newer( > v5.5 / v5.6 ?? ) versions of DCC-EX only broadcast power state changes,
054        // so we request confirmation of power status.
055        requestUpdateFromLayout();
056    }
057
058    // to free resources when no longer used
059    @Override
060    public void dispose() throws JmriException {
061        tc.removeDCCppListener(DCCppInterface.CS_INFO, this);
062        tc = null;
063    }
064
065    private void checkTC() throws JmriException {
066        if (tc == null) {
067            throw new JmriException("attempt to use PowerManager after dispose");
068        }
069    }
070
071    // listen for power and status messages
072    @Override
073    public void message(DCCppReply m) {
074        if (m.isPowerReply()) {
075            log.debug("Power Reply message received: {}", m);
076            int old = power;
077            if (m.getPowerBool()) {
078                power = ON;
079            } else {
080                power = OFF;
081            }
082            firePowerPropertyChange(old, power);
083
084        // if status reply 's', then update the command station info (version, etc.)
085        } else if (m.isStatusReply()) {
086            log.debug("Version Info Received: {}", m);
087            tc.getCommandStation().setCommandStationInfo(m);
088        
089        // store trackmanager mode by index (0-7 for A-H) 
090        } else if (m.isTrackManagerReply()) {
091            log.debug("Track Manager Reply Received: {}", m);
092            int trackNum = m.getTrackManagerLetter() - 'A'; //get track number from track letter
093            tc.getCommandStation().setTrackMode(trackNum, m.getTrackManagerMode());
094        }
095    }
096
097    // listen for the messages to the CommandStation
098    @Override
099    public void message(DCCppMessage l) {
100    }
101
102    // Handle message timeout notification
103    // If the message still has retries available, reduce retries and send it back to the traffic controller.
104    @Override
105    public void notifyTimeout(DCCppMessage msg) {
106        log.debug("Notified of timeout on message '{}' , {} retries available.", msg, msg.getRetries());
107        if (msg.getRetries() > 0) {
108            msg.setRetries(msg.getRetries() - 1);
109            tc.sendDCCppMessage(msg, this);
110        }        
111    }
112
113    /**
114     * Request the current command station status and
115     * request the trackmanager configuration.
116     * {@inheritDoc }
117     */
118    @Override
119    public void requestUpdateFromLayout() {
120        // Request the current command station status.
121        tc.sendDCCppMessage(DCCppMessage.makeCSStatusMsg(), this);
122        // Request the trackmanager configuration.
123        tc.sendDCCppMessage(DCCppMessage.makeTrackManagerRequestMsg(), this);
124    }
125
126    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DCCppPowerManager.class);
127
128}