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