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