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 * {@inheritDoc} 047 */ 048 @Override 049 public boolean hasExitReports() { 050 return true; 051 } 052 053 /** 054 * request an update from the layout. 055 */ 056 private void requestUpdateFromLayout(){ 057 _memo.getTrafficController().sendz21Message(Z21Message.getLanRailComGetDataRequestMessage(),this); 058 } 059 060 // the Z21 Listener interface 061 062 /** 063 * Member function that will be invoked by a z21Interface implementation to 064 * forward a z21 message from the layout. 065 * 066 * @param msg The received z21 reply. Note that this same object may be 067 * presented to multiple users. It should not be modified here. 068 */ 069 @Override 070 public void reply(Z21Reply msg){ 071 // for incoming messages all the reporter cares about is 072 // LAN_RAILCOM_DATACHANGED messages. 073 if(msg.isRailComDataChangedMessage()){ 074 // find out how many RailCom Transmitters the command 075 // station is telling us about (there is a maximum of 19). 076 int tags = msg.getNumRailComDataEntries(); 077 for(int i=0;i<tags;i++){ 078 // get the locomotive address from the message. 079 DccLocoAddress l = msg.getRailComLocoAddress(i); 080 // see if there is a tag for this address. 081 RailCom tag = (RailCom) InstanceManager.getDefault(RailComManager.class).provideIdTag("" + l.getNumber()); 082 tag.setActualSpeed(msg.getRailComSpeed(i)); 083 notify(tag); 084 if(!entrySet.contains(tag)){ 085 entrySet.add(tag); 086 } 087 } 088 if(tags == 0){ 089 notify(null); // clear the current report if no tags. 090 entrySet.clear(); 091 } 092 } 093 } 094 095 /** 096 * Member function that will be invoked by a z21Interface implementation to 097 * forward a z21 message sent to the layout. Normally, this function will do 098 * nothing. 099 * 100 * @param msg The received z21 message. Note that this same object may be 101 * presented to multiple users. It should not be modified here. 102 */ 103 @Override 104 public void message(Z21Message msg){ 105 // we don't need to handle outgoing messages, so just ignore them. 106 } 107 108 /** 109 * Set up the refreshTimer, and start it. 110 */ 111 private void refreshTimer() { 112 if (refreshTimer == null) { 113 refreshTimer = new javax.swing.Timer(refreshTimeoutValue, e -> { 114 // If the timer times out, send a request for status 115 requestUpdateFromLayout(); 116 }); 117 } 118 refreshTimer.stop(); 119 refreshTimer.setInitialDelay(refreshTimeoutValue); 120 refreshTimer.setRepeats(true); 121 refreshTimer.start(); 122 } 123 124 @Override 125 public Collection<Object> getCollection() { 126 return entrySet; 127 } 128 129 @Override 130 public void dispose(){ 131 super.dispose(); 132 refreshTimer.stop(); 133 } 134 135}