001 002package jmri.jmrit.withrottle; 003 004import java.beans.PropertyChangeListener; 005import java.util.TimeZone; 006 007import org.slf4j.Logger; 008import org.slf4j.LoggerFactory; 009 010import jmri.InstanceManager; 011import jmri.Timebase; 012 013/** 014 * Fast Clock interface for Wi-Fi throttles. 015 * <p> 016 * Fast Clock display on devices will be synchronized with hardware or software 017 * clock. Time is UTC seconds on Wi-Fi devices, Local milliseconds in JMRI. 018 * 019 * @author Brett Hoffman Copyright (C) 2018 020 */ 021public class FastClockController extends AbstractController { 022 023 private final Timebase fastClock; 024 private final PropertyChangeListener timeAndRateListener; 025 026 public FastClockController() { 027 028 fastClock = InstanceManager.getDefault(jmri.Timebase.class); 029 timeAndRateListener = new PropertyChangeListener() { 030 @Override 031 public void propertyChange(java.beans.PropertyChangeEvent e) { 032 //skip minutes updates on this listener, handled in minuteListener 033 log.trace("timeAndRateListener propertyChange for '{}' from '{}' to '{}'",e.getPropertyName(),e.getOldValue(),e.getNewValue()); 034 if (!e.getPropertyName().equals("minutes")) { 035 sendFastTimeAndRate(); 036 } 037 } 038 }; 039 040 isValid = true; 041 042 fastClock.addPropertyChangeListener(timeAndRateListener); 043 } 044 045 @Override 046 boolean verifyCreation() { 047 return isValid; 048 } 049 050 @Override 051 void handleMessage(String message, DeviceServer deviceServer) { 052 throw new UnsupportedOperationException("Not used."); 053 } 054 055 @Override 056 void register() { 057 throw new UnsupportedOperationException("Not used."); 058 } 059 060 @Override 061 void deregister() { 062 // cancel callback to update time 063 fastClock.removePropertyChangeListener(timeAndRateListener); 064 } 065 066 067 /** 068 * Fast clock should not have a time zone. 069 * <p> 070 * Add the offset to give straight UTC value, 071 * based on the fastclock's datetime 072 * @return Time, as UTC in seconds 073 */ 074 private long getAdjustedTime() { 075 long fastClockTime = fastClock.getTime().getTime(); //fastclock time as milliseconds 076 int timeZoneOffset = TimeZone.getDefault().getOffset(fastClockTime); //timezone offset in milliseconds 077 return ((fastClockTime + timeZoneOffset) / 1000); //returned adjusted time in seconds 078 } 079 080 /** 081 * Send Time and Rate. 082 * <p> 083 * Time on device will update to the value that is sent and rate will allow 084 * Fast Clock to keep its own time. A rate == 0 will tell the device to 085 * stop the clock. 086 */ 087 public void sendFastTimeAndRate() { 088 // Send the time and run rate whether running or not 089 if (listeners != null) { 090 for (ControllerInterface listener : listeners) { 091 listener.sendPacketToDevice("PFT" + getAdjustedTime() + "<;>" + fastClock.userGetRate()); 092 } 093 if (!fastClock.getRun()) { 094 // Not running, send rate of 0 095 // This will stop a running clock without changing stored rate 096 for (ControllerInterface listener : listeners) { 097 listener.sendPacketToDevice("PFT" + getAdjustedTime() + "<;>" + 0.0); 098 } 099 } 100 } 101 } 102 103 private final static Logger log = LoggerFactory.getLogger(FastClockController.class); 104}