001package jmri.jmrix.dccpp; 002 003import java.util.ArrayList; 004import java.util.List; 005import javax.annotation.Nonnull; 006 007import jmri.AddressedProgrammer; 008import jmri.ProgListener; 009import jmri.ProgrammerException; 010import jmri.ProgrammingMode; 011import org.slf4j.Logger; 012import org.slf4j.LoggerFactory; 013 014/** 015 * Provides an Ops mode programming interface for DCC++. Currently only Byte 016 * mode is implemented, though DCC++ also supports bit mode writes for POM 017 * 018 * @see jmri.Programmer 019 * @author Paul Bender Copyright (C) 2003-2010 020 * @author Girgio Terdina Copyright (C) 2007 021 * @author Mark Underwood Copyright (C) 2015 022 * 023 * Based on XNetOpsModeProgrammer by Paul Bender and Girgio Terdina 024 */ 025public class DCCppOpsModeProgrammer extends jmri.jmrix.AbstractProgrammer implements AddressedProgrammer { 026 027 int mAddressHigh; 028 int mAddressLow; 029 int mAddress; 030 int progState = 0; 031 int value; 032 ProgListener progListener = null; 033 034 protected DCCppTrafficController tc; 035 036 public DCCppOpsModeProgrammer(int pAddress, DCCppTrafficController controller) { 037 tc = controller; 038 if (log.isDebugEnabled()) { 039 log.debug("Creating Ops Mode Programmer for Address {}", pAddress); 040 } 041 mAddressLow = DCCppCommandStation.getDCCAddressLow(pAddress); 042 mAddressHigh = DCCppCommandStation.getDCCAddressHigh(pAddress); 043 mAddress = pAddress; 044 if (log.isDebugEnabled()) { 045 log.debug("High Address: {} Low Address: {}", mAddressHigh, mAddressLow); 046 } 047 } 048 049 /** 050 * {@inheritDoc} 051 * 052 * Send an ops-mode write request to the DCC++. 053 */ 054 @Override 055 synchronized public void writeCV(String CVname, int val, ProgListener p) throws ProgrammerException { 056 final int CV = Integer.parseInt(CVname); 057 DCCppMessage msg = DCCppMessage.makeWriteOpsModeCVMsg(mAddress, CV, val); 058 tc.sendDCCppMessage(msg, null); 059 /* we need to save the programmer and value so we can send messages 060 back to the programming screen when we receive something from the 061 command station */ 062 progListener = p; 063 value = val; 064 progState = DCCppProgrammer.REQUESTSENT; 065 assert msg != null; 066 restartTimer(msg.getTimeout()); 067 /* Issue #2423 (GitHub) -- DCC++ base station does not respond to Ops Mode 068 * writes, so waiting for a response just means JMRI times out after a long delay. 069 /* Proposed Fix: Don't go to REQUESTSENT state... just stay in NOTPROGRAMMING. 070 * Risk... the state change introduces a 250ms delay to keep the UI from sending 071 * write commands too frequently... so we'd have to do that here too. 072 */ 073 // Before we set the programmer state to not programming, 074 // delay for a short time to give the decoder a chance to 075 // process the request. 076 try { 077 this.wait(250); // Spotbugs not happy: WAIT_NOT_IN_LOOP 078 } catch (java.lang.InterruptedException ie) { 079 log.debug("Interrupted During Delay"); 080 } 081 progState = DCCppProgrammer.NOTPROGRAMMING; 082 stopTimer(); 083 notifyProgListenerEnd(progListener, value, ProgListener.OK); 084 } 085 086 /** 087 * {@inheritDoc} 088 */ 089 @Override 090 synchronized public void readCV(String CVname, ProgListener p) throws ProgrammerException { 091 notifyProgListenerEnd(p, Integer.parseInt(CVname), ProgListener.NotImplemented); 092 } 093 094 /** 095 * {@inheritDoc} 096 */ 097 @Override 098 public void confirmCV(String CV, int val, ProgListener p) throws ProgrammerException { 099 notifyProgListenerEnd(p, val, ProgListener.NotImplemented); 100 } 101 102 /** 103 * {@inheritDoc} 104 * 105 * Types implemented here. 106 */ 107 @Override 108 @Nonnull 109 public List<ProgrammingMode> getSupportedModes() { 110 List<ProgrammingMode> ret = new ArrayList<>(); 111 ret.add(ProgrammingMode.OPSBYTEMODE); 112 ret.add(ProgrammingMode.OPSBITMODE); 113 return ret; 114 } 115 116 /** 117 * {@inheritDoc} 118 */ 119 @Override 120 public boolean getLongAddress() { 121 return true; 122 } 123 124 /** 125 * {@inheritDoc} 126 */ 127 @Override 128 public int getAddressNumber() { 129 return mAddress; 130 } 131 132 /** 133 * {@inheritDoc} 134 */ 135 @Override 136 public String getAddress() { 137 return "" + getAddressNumber() + " " + getLongAddress(); 138 } 139 140 /** 141 * {@inheritDoc} 142 */ 143 @Override 144 synchronized protected void timeout() { 145 progState = DCCppProgrammer.NOTPROGRAMMING; 146 stopTimer(); 147 notifyProgListenerEnd(progListener, value, ProgListener.FailedTimeout); 148 } 149 150 // initialize logging 151 private final static Logger log = LoggerFactory.getLogger(DCCppOpsModeProgrammer.class); 152 153}