001package jmri.jmrix.nce; 002 003import java.util.ArrayList; 004import java.util.List; 005import javax.annotation.Nonnull; 006 007import jmri.AddressedProgrammer; 008import jmri.NmraPacket; 009import jmri.ProgListener; 010import jmri.ProgrammerException; 011import jmri.ProgrammingMode; 012 013/** 014 * Provide an Ops Mode Programmer via a wrapper what works with the NCE command 015 * station object. 016 * <p> 017 * Functionally, this just creates packets to send via the command station. 018 * 019 * @see jmri.Programmer 020 * @author Bob Jacobsen Copyright (C) 2002, 2014 021 * @author kcameron Copyright (C) 2014 022 */ 023public class NceOpsModeProgrammer extends NceProgrammer implements AddressedProgrammer { 024 025 int mAddress; 026 boolean mLongAddr; 027 028 public NceOpsModeProgrammer(NceTrafficController tc, int pAddress, boolean pLongAddr) { 029 super(tc); 030 log.debug("NCE ops mode programmer {} {}", pAddress, pLongAddr); 031 mAddress = pAddress; 032 mLongAddr = pLongAddr; 033 setMode(ProgrammingMode.OPSBYTEMODE); 034 } 035 036 /** 037 * {@inheritDoc} 038 * 039 * Forward a write request to an ops-mode write operation 040 */ 041 @Override 042 public synchronized void writeCV(String CVname, int val, ProgListener p) throws ProgrammerException { 043 final int CV = Integer.parseInt(CVname); 044 if (log.isDebugEnabled()) { 045 log.debug("write CV={} val={}", CV, val); 046 } 047 NceMessage msg; 048 // USB can't send a NMRA packet, must use new ops mode command 049 if (tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_POWERCAB 050 || tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB3 051 || tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB5 052 || tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_TWIN) { 053 int locoAddr = mAddress; 054 if (mLongAddr) { 055 locoAddr += 0xC000; 056 } 057 byte[] bl = NceBinaryCommand.usbOpsModeLoco(tc, locoAddr, CV, val); 058 msg = NceMessage.createBinaryMessage(tc, bl); 059 060 } else { 061 // create the message and fill it, 062 byte[] contents = NmraPacket.opsCvWriteByte(mAddress, mLongAddr, 063 CV, val); 064 if (contents == null) { 065 throw new ProgrammerException(); 066 } 067 msg = NceMessage.sendPacketMessage(tc, contents, 5); // retry 5 times 068 } 069 // record state. COMMANDSENT is just waiting for a reply... 070 useProgrammer(p); 071 _progRead = false; 072 progState = COMMANDSENT_2; 073 _val = val; 074 _cv = CV; 075 076 // start the error timer 077 startShortTimer(); 078 079 // send it twice (2x5) so NCE CS will send at least two consecutive commands to decoder 080 tc.sendNceMessage(msg, this); 081 tc.sendNceMessage(msg, this); 082 } 083 084 /** 085 * {@inheritDoc} 086 */ 087 @Override 088 public synchronized void readCV(String CVname, ProgListener p) throws ProgrammerException { 089 final int CV = Integer.parseInt(CVname); 090 if (log.isDebugEnabled()) { 091 log.debug("read CV={}", CV); 092 } 093 log.error("readCV not available in this protocol"); 094 throw new ProgrammerException(); 095 } 096 097 /** 098 * {@inheritDoc} 099 */ 100 @Override 101 public synchronized void confirmCV(String CV, int val, ProgListener p) throws ProgrammerException { 102 if (log.isDebugEnabled()) { 103 log.debug("confirm CV={}", CV); 104 } 105 log.error("confirmCV not available in this protocol"); 106 throw new ProgrammerException(); 107 } 108 109 /** 110 * {@inheritDoc} 111 * 112 * add 200mSec between commands, so NCE command station queue doesn't get overrun 113 */ 114 @Override 115 protected void notifyProgListenerEnd(int value, int status) { 116 if (log.isDebugEnabled()) { 117 log.debug("NceOpsModeProgrammer adds 200mSec delay to response"); 118 } 119 try { 120 wait(200); 121 } catch (InterruptedException e) { 122 log.debug("unexpected exception", e); 123 } 124 super.notifyProgListenerEnd(value, status); 125 } 126 127 /** 128 * {@inheritDoc} 129 * 130 * Types implemented here. 131 */ 132 @Override 133 @Nonnull 134 public List<ProgrammingMode> getSupportedModes() { 135 List<ProgrammingMode> ret = new ArrayList<ProgrammingMode>(); 136 ret.add(ProgrammingMode.OPSBYTEMODE); 137 return ret; 138 } 139 140 /** 141 * {@inheritDoc} 142 * 143 * Can this ops-mode programmer read back values? For now, no, but maybe 144 * later. 145 * 146 * @return always false for now 147 */ 148 @Override 149 public boolean getCanRead() { 150 return false; 151 } 152 153 /** 154 * {@inheritDoc} 155 * 156 * Ops-mode programming doesn't put the command station in programming mode, 157 * so we don't have to send an exit-programming command at end. Therefore, 158 * this routine does nothing except to replace the parent routine that does 159 * something. 160 */ 161 @Override 162 void cleanup() { 163 } 164 165 /** 166 * {@inheritDoc} 167 */ 168 @Override 169 public boolean getLongAddress() { 170 return mLongAddr; 171 } 172 173 /** 174 * {@inheritDoc} 175 */ 176 @Override 177 public int getAddressNumber() { 178 return mAddress; 179 } 180 181 /** 182 * {@inheritDoc} 183 */ 184 @Override 185 public String getAddress() { 186 return "" + getAddressNumber() + " " + getLongAddress(); 187 } 188 189 // initialize logging 190 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NceOpsModeProgrammer.class); 191 192}