001package jmri.jmrix.dccpp; 002 003import org.slf4j.Logger; 004import org.slf4j.LoggerFactory; 005 006/** 007 * Implement a feedback message cache for DCC++ turnouts. 008 * <p> 009 * 010 * @author Paul Bender Copyright (C) 2012 011 * @author Mark Underwood Copyright (C) 2015 012 * 013 * Based on XNetFeedbackMessageCache by Paul Bender 014 */ 015public class DCCppTurnoutReplyCache implements DCCppListener { 016 017 protected DCCppTrafficController tc = null; 018 019 private DCCppReply[] messageCache; // an to hold each of the 512 possible 020 // reply messages for the turnouts. 021 022 private Boolean[] messagePending; // hold pending status for each of 023 // the possible status request messages. 024 025 // ctor has to register for DCCpp events 026 public DCCppTurnoutReplyCache(DCCppTrafficController controller) { 027 // TODO: This is likely to be a sparse table. Consider refactoring as 028 // a list or something more memory efficient. 029 messageCache = new DCCppReply[DCCppConstants.MAX_TURNOUT_ADDRESS]; 030 for (int i = 0; i < DCCppConstants.MAX_TURNOUT_ADDRESS; i++) { 031 messageCache[i] = null; 032 } 033 messagePending = new Boolean[DCCppConstants.MAX_TURNOUT_ADDRESS]; 034 for (int i = 0; i < DCCppConstants.MAX_TURNOUT_ADDRESS; i++) { 035 messagePending[i] = false; 036 } 037 tc = controller; 038 tc.addDCCppListener(DCCppInterface.FEEDBACK, this); 039 } 040 041 // requestCachedStateFromLayout 042 // provide any cached state to the turnout. Otherwise, call the turnout's 043 // requestUpdateFromLayout() method. 044 // @param turnout the DCCppTurnout object we are requesting data for. 045 synchronized public void requestCachedStateFromLayout(DCCppTurnout turnout) { 046 int pNumber = turnout.getNumber(); 047 if (messagePending[pNumber]) { 048 return; 049 } 050 try { 051 if (messageCache[pNumber] != null) { 052 log.debug("Message for turnout {} cached.", pNumber); 053 turnout.message(messageCache[pNumber]); 054 } else { 055 // TODO: Make sure this doesn't break under a no-feedback model. 056 messagePending[pNumber] = true; 057 turnout.requestUpdateFromLayout(); // this does nothing. 058 } 059 } catch (java.lang.NullPointerException npe) { 060 // TODO: Make sure this doesn't break under a no-feedback model. 061 messagePending[pNumber] = true; 062 turnout.requestUpdateFromLayout(); 063 } 064 } 065 066 // requestCachedStateFromLayout 067 // provide any cached state a sensor. Otherwise, call the sensor's 068 // requestUpdateFromLayout() method. 069 // @param sensor the DCCppSensor object we are requesting data for. 070 // 071 // TODO: We don't have DCCppSensors yet. May never have them. 072 /* 073 synchronized public void requestCachedStateFromLayout(DCCppSensor sensor) { 074 int pNumber = sensor.getNumber(); 075 if (messagePending[sensor.getBaseAddress()][sensor.getNibble() >> 4]) { 076 return; 077 } 078 try { 079 if (messageCache[sensor.getBaseAddress()][sensor.getNibble() >> 4] != null) { 080 if (log.isDebugEnabled()) { 081 log.debug("Message for sensor " + pNumber + " cached."); 082 } 083 sensor.message(messageCache[sensor.getBaseAddress()][sensor.getNibble() >> 4]); 084 } else { 085 messagePending[sensor.getBaseAddress()][sensor.getNibble() >> 4] = true; 086 sensor.requestUpdateFromLayout(); 087 } 088 } catch (java.lang.NullPointerException npe) { 089 messagePending[sensor.getBaseAddress()][sensor.getNibble() >> 4] = true; 090 sensor.requestUpdateFromLayout(); 091 } 092 } 093 */ 094 095 // listen for turnouts, creating them as needed 096 @Override 097 synchronized public void message(DCCppReply l) { 098 if (l.isTurnoutReply()) { 099 log.debug("received message: {}", l); 100 // cache the message for later requests 101 messageCache[l.getTOIDInt()] = l; 102 messagePending[l.getTOIDInt()] = false; 103 } 104 } 105 106 // Listen for the outgoing messages (to the command station) 107 @Override 108 public void message(DCCppMessage l) { 109 } 110 111 // Handle a timeout notification 112 @Override 113 public void notifyTimeout(DCCppMessage msg) { 114 log.debug("Notified of timeout on message '{}'", msg); 115 } 116 117 private final static Logger log = LoggerFactory.getLogger(DCCppTurnoutReplyCache.class); 118 119} 120 121