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