001package jmri.jmrix.bidib;
002
003import jmri.JmriException;
004import jmri.PowerManager;
005
006import java.beans.PropertyChangeListener;
007import org.bidib.jbidibc.messages.AddressData;
008import org.bidib.jbidibc.core.DefaultMessageListener;
009import org.bidib.jbidibc.core.MessageListener;
010import org.bidib.jbidibc.messages.enums.BoosterState;
011import org.bidib.jbidibc.messages.enums.CommandStationState;
012import org.bidib.jbidibc.messages.Node;
013import org.bidib.jbidibc.messages.StringData;
014import org.bidib.jbidibc.messages.enums.BoosterControl;
015import org.bidib.jbidibc.messages.message.BoostOnMessage;
016import org.bidib.jbidibc.messages.message.BoostOffMessage;
017import org.bidib.jbidibc.messages.message.BoostQueryMessage;
018import org.bidib.jbidibc.messages.message.CommandStationSetStateMessage;
019import org.slf4j.Logger;
020import org.slf4j.LoggerFactory;
021
022/**
023 * BiDiBPowerManager.java
024 *
025 * Description: PowerManager implementation for controlling layout power
026 *
027 * @author Bob Jacobsen Copyright (C) 2001
028 * @author Eckart Meyer Copyright (C) 2019-2023
029 *
030 */
031public class BiDiBPowerManager implements PowerManager {
032
033    BiDiBTrafficController tc = null;
034    String userName = "BiDiB";
035    int power = UNKNOWN;
036    MessageListener messageListener = null;
037
038    public BiDiBPowerManager(BiDiBSystemConnectionMemo memo) {
039        tc = memo.getBiDiBTrafficController();
040        userName = memo.getUserName();
041        createBoosterListener();
042        // ask BiDiB for current booster status
043        tc.sendBiDiBMessage(new BoostQueryMessage(), tc.getFirstBoosterNode());
044    }
045
046    @Override
047    public String getUserName() {
048        return userName;
049    }
050
051
052    @Override
053    public void setPower(int v) throws JmriException {
054        int old = power;
055        power = UNKNOWN;
056        checkTC();
057        Node csnode = tc.getFirstCommandStationNode();
058        if (v == ON) {
059            // send TRACK_POWER_ON
060            // At first MSG_BOOST_ON(0), then powering on the DCC generator: all booster will be switched on,
061            // except those where the FEATURE_BST_INHIBIT_AUTOSTART is set.
062            tc.sendBiDiBMessage(new BoostOnMessage(BoostOnMessage.BROADCAST_MESSAGE), tc.getRootNode());
063            if (csnode != null) {
064                tc.sendBiDiBMessage(new CommandStationSetStateMessage(CommandStationState.GO), tc.getFirstCommandStationNode());
065            }
066
067        } else if (v == OFF) {
068            // send TRACK_POWER_OFF
069            if (csnode != null) {
070                tc.sendBiDiBMessage(new CommandStationSetStateMessage(CommandStationState.OFF), csnode);
071            }
072            tc.sendBiDiBMessage(new BoostOffMessage(BoostOffMessage.BROADCAST_MESSAGE), tc.getRootNode());
073        }
074        firePropertyChange(POWER, old, power);
075    }
076
077    /**
078     * {@inheritDoc}
079     */
080    @Override
081    public int getPower() {
082        return power;
083    }
084
085    /**
086     * {@inheritDoc}
087     * 
088     * Remove the Message Listener for this power manager
089     */
090    @Override
091    public void dispose() throws JmriException {
092        if (messageListener != null) {
093            tc.removeMessageListener(messageListener);        
094            messageListener = null;
095        }
096        tc = null;
097    }
098
099    /**
100     * @throws JmriException if we don't have a valid Traffic Controller
101     */
102    private void checkTC() throws JmriException {
103        if (tc == null) {
104            throw new JmriException("attempt to use PowerManager after dispose");
105        }
106    }
107
108    // to hear of changes
109    java.beans.PropertyChangeSupport pcs = new java.beans.PropertyChangeSupport(this);
110
111    /**
112     * {@inheritDoc}
113     */
114    @Override
115    public synchronized void addPropertyChangeListener(java.beans.PropertyChangeListener l) {
116        pcs.addPropertyChangeListener(l);
117    }
118
119    protected void firePropertyChange(String p, Object old, Object n) {
120        pcs.firePropertyChange(p, old, n);
121    }
122
123    /**
124     * {@inheritDoc}
125     */
126    @Override
127    public synchronized void removePropertyChangeListener(java.beans.PropertyChangeListener l) {
128        pcs.removePropertyChangeListener(l);
129    }
130
131    /**
132     * {@inheritDoc}
133     */
134    @Override
135    public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
136        pcs.addPropertyChangeListener(propertyName, listener);
137    }
138
139    /**
140     * {@inheritDoc}
141     */
142    @Override
143    public PropertyChangeListener[] getPropertyChangeListeners() {
144        return pcs.getPropertyChangeListeners();
145    }
146
147    /**
148     * {@inheritDoc}
149     */
150    @Override
151    public PropertyChangeListener[] getPropertyChangeListeners(String propertyName) {
152        return pcs.getPropertyChangeListeners(propertyName);
153    }
154
155    /**
156     * {@inheritDoc}
157     */
158    @Override
159    public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
160        pcs.removePropertyChangeListener(propertyName, listener);
161    }
162
163    private void createBoosterListener() {
164        // to listen to messages related to track power.
165        messageListener = new DefaultMessageListener() {
166            @Override
167            public void boosterState(byte[] address, int messageNum, BoosterState state, BoosterControl control) {//ByteUtils
168                Node node = tc.getNodeByAddr(address); //the sending node
169                log.info("POWER booster state was signalled: {}, control: {}, node: {}", state, control, node);
170                if (state == BoosterState.OFF_SHORT) {
171                    log.warn("Short circuit detected on booster {} ({})", node.getStoredString(StringData.INDEX_USERNAME), node);
172                }
173                else if (state == BoosterState.OFF_HOT) {
174                    log.warn("Overtemperature detected on booster {} ({})", node.getStoredString(StringData.INDEX_USERNAME), node);
175                }
176                if (node.equals(tc.getFirstBoosterNode())) {
177                    int old = power;
178                    power = BoosterState.isOnState(state) ? ON : OFF;
179                    log.info("change {} from {} to {}", POWER, old, power);
180                    firePropertyChange(POWER, old, power);
181                }
182            }
183            @Override
184            public void speed(byte[] address, int messageNum, AddressData addressData, int speed) {
185                //Node node = tc.getFirstCommandStationNode();
186                //log.trace("speed: node UID: {}, node addr: {}, msg node addr: {}, address: {}, speed: {}", node.getUniqueId(), node.getAddr(), address, addressData, speed);
187                //if (NodeUtils.isAddressEqual(node.getAddr(), address)) {
188                    //log.debug("SPEED was signalled, node addr: {}, speed: {}, loco: {}", node.getAddr(), speed, addressData);
189                //}
190            }
191        };
192        tc.addMessageListener(messageListener);        
193    }
194
195    // Initialize logging information
196    private static final Logger log = LoggerFactory.getLogger(BiDiBPowerManager.class);
197
198}
199
200
201