001package jmri.jmrix.roco.z21;
002
003import jmri.DccLocoAddress;
004import jmri.InstanceManager;
005import jmri.RailCom;
006import jmri.RailComManager;
007
008/**
009 * Z21Reporter implements the Reporter Manager interface
010 * for Roco Z21 systems.
011 * <p>
012 * Reports from this reporter are of the type jmri.RailCom.
013 *
014 * @author Paul Bender Copyright (C) 2016
015 */
016public class Z21Reporter extends jmri.implementation.AbstractRailComReporter implements Z21Listener {
017
018    private Z21SystemConnectionMemo _memo;
019
020    private javax.swing.Timer refreshTimer; // Timer used to periodically
021    // referesh the RailCom data (this does not appear to happen automatically).
022    private static final int refreshTimeoutValue = 15000; 
023
024    /**  
025     * Create a new Z21Reporter.
026     *
027     * @param systemName the system name of the new reporter.
028     * @param userName the user name of the new reporter.
029     * @param memo an instance of Z21SystemConnectionMemo this manager 
030     *             is associated with.
031     *
032     */
033    public Z21Reporter(String systemName,String userName,Z21SystemConnectionMemo memo){
034        super(systemName,userName);
035        _memo = memo;
036        _memo.getTrafficController().addz21Listener(this);
037        // request an update from the layout.
038       requestUpdateFromLayout();
039       refreshTimer();
040    }
041
042    /**
043     *     request an update from the layout.
044     */
045    private void requestUpdateFromLayout(){
046       _memo.getTrafficController().sendz21Message(Z21Message.getLanRailComGetDataRequestMessage(),this);
047    }
048
049    // the Z21 Listener interface
050
051    /**
052     * Member function that will be invoked by a z21Interface implementation to
053     * forward a z21 message from the layout.
054     *
055     * @param msg The received z21 reply. Note that this same object may be
056     * presented to multiple users. It should not be modified here.
057     */
058    @Override
059    public void reply(Z21Reply msg){
060         // for incoming messages all the reporter cares about is
061         // LAN_RAILCOM_DATACHANGED messages.
062         if(msg.isRailComDataChangedMessage()){
063             // find out how many RailCom Transmitters the command
064             // station is telling us about (there is a maximum of 19).
065             int tags = msg.getNumRailComDataEntries();
066             for(int i=0;i<tags;i++){
067                 // get the locomotive address from the message.
068                 DccLocoAddress l = msg.getRailComLocoAddress(i);
069                 // see if there is a tag for this address.
070                 RailCom tag = (RailCom) InstanceManager.getDefault(RailComManager.class).provideIdTag("" + l.getNumber());
071                 tag.setActualSpeed(msg.getRailComSpeed(i));
072                 notify(tag);
073             }
074             if(tags == 0){
075                 notify(null); // clear the current report if no tags.
076             }
077         }
078    }
079
080    /**
081     * Member function that will be invoked by a z21Interface implementation to
082     * forward a z21 message sent to the layout. Normally, this function will do
083     * nothing.
084     *
085     * @param msg The received z21 message. Note that this same object may be
086     * presented to multiple users. It should not be modified here.
087     */
088    @Override
089    public void message(Z21Message msg){
090         // we don't need to handle outgoing messages, so just ignore them.
091    }
092
093    /**
094     * Set up the refreshTimer, and start it.
095     */
096    private void refreshTimer() {
097        if (refreshTimer == null) {
098            refreshTimer = new javax.swing.Timer(refreshTimeoutValue, e -> {
099                // If the timer times out, send a request for status
100                requestUpdateFromLayout();
101            });
102        }
103        refreshTimer.stop();
104        refreshTimer.setInitialDelay(refreshTimeoutValue);
105        refreshTimer.setRepeats(true);
106        refreshTimer.start();
107    }
108
109    @Override
110    public void dispose(){
111        super.dispose();
112        refreshTimer.stop();
113    }
114
115}