001package jmri.jmrix.tmcc; 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; 011 012/** 013 * Provide an Ops Mode Programmer via a wrapper that works with the 014 * TMCC control interface 015 * <p> 016 * Functionally, this just creates packets to send via the Command Station. 017 * 018 * @see jmri.Programmer 019 * @author Bob Jacobsen Copyright (C) 2002, 2025 020 */ 021public class TmccOpsModeProgrammer extends TmccProgrammer implements AddressedProgrammer { 022 023 int mAddress; 024 boolean mLongAddr; 025 026 public TmccOpsModeProgrammer(int pAddress, boolean pLongAddr, TmccSystemConnectionMemo memo) { 027 super(memo); 028 mAddress = pAddress; 029 mLongAddr = pLongAddr; 030 } 031 032 033 /** 034 * {@inheritDoc} 035 */ 036 @Override 037 @Nonnull 038 public List<ProgrammingMode> getSupportedModes() { 039 List<ProgrammingMode> ret = new ArrayList<ProgrammingMode>(); 040 041 ret.add(TmccProgrammerManager.TMCCMODE1_ENGFEATURE); 042 ret.add(TmccProgrammerManager.TMCCMODE2_ENGFEATURE); 043 044 return ret; 045 } 046 047 048 int _cv; // points to "CV" input from Simple Programmer 049 int _val; // points to "Value" input from Simple Programmer 050 051 052 053 /** 054 * {@inheritDoc} 055 * 056 * Forward a write request to an ops-mode write operation. 057 */ 058 @Override 059 public synchronized void writeCV(String CVname, int val, ProgListener p) throws ProgrammerException { 060 final int CV = Integer.parseInt(CVname); 061 log.debug("write CV={} val={}", CV, val); 062 063 064 _cv = CV; // Value from Simple Programmer "CV" input 065 _val = val; // Value from Simple Programmer "Value" input 066 067 068 069 // validate CV == 2 for TMCC loco Feature programming 070 // validate ID#/address for TMCC is between 1-98 071 // validate Feature Type for TMCC 072 // format and send the TMCC loco Feature write message 073 // note: the argument is long containing 3 bytes 074 075 if (CV == 2) { 076 077 if (mAddress > 0 && mAddress < 99) { 078 079 // TMCC2 Feature Types 080 if (getMode() == TmccProgrammerManager.TMCCMODE2_ENGFEATURE) { 081 082 if (val == 0) { 083 SerialMessage m = new SerialMessage(); 084 m.setOpCode(0xF8); // set the first byte/TMCC2 opcode to 0xF8 085 m.putAsWord(((mAddress * 512) + 256) + 16); // set the second/third byte (address/numeric for TMCC2 val = 0) 086 tc.sendSerialMessage(m, null); 087 088 } else if (val == 1) { 089 SerialMessage m = new SerialMessage(); 090 m.setOpCode(0xF8); // set the first byte/TMCC2 opcode to 0xF8 091 m.putAsWord(((mAddress * 512) + 256) + 17); // set the second/third byte (address/numeric for TMCC2 val = 1) 092 tc.sendSerialMessage(m, null); 093 094 } else if (val == 2) { 095 SerialMessage m = new SerialMessage(); 096 m.setOpCode(0xF8); // set the first byte/TMCC2 opcode to 0xF8 097 m.putAsWord(((mAddress * 512) + 256) + 18); // set the second/third byte (address/numeric for TMCC2 val = 2) 098 tc.sendSerialMessage(m, null); 099 100 } else { 101 SerialMessage m = new SerialMessage(); 102 m.setOpCode(0x00); 103 m.putAsWord(00004); 104 tc.sendSerialMessage(m, null); 105 log.warn("Value Entered is Not a TMCC2 Feature Type"); 106 } 107 108 } 109 110 111 // TMCC1 Feature Types 112 if (getMode() == TmccProgrammerManager.TMCCMODE1_ENGFEATURE) { 113 114 if (val == 4) { 115 SerialMessage m = new SerialMessage(); 116 m.setOpCode(0xFE); // set the first byte/TMCC1 opcode to 0xFE 117 m.putAsWord((mAddress * 128) + 20); // set the second/third byte (address/numeric for TMCC1 val = 4) 118 tc.sendSerialMessage(m, null); 119 120 } else if (val == 5) { 121 SerialMessage m = new SerialMessage(); 122 m.setOpCode(0xFE); // set the first byte/TMCC1 opcode to 0xFE 123 m.putAsWord((mAddress * 128) + 21); // set the second/third byte (address/numeric for TMCC1 val = 5) 124 tc.sendSerialMessage(m, null); 125 126 } else if (val == 6) { 127 SerialMessage m = new SerialMessage(); 128 m.setOpCode(0xFE); // set the first byte/TMCC1 opcode to 0xFE 129 m.putAsWord((mAddress * 128) + 22); // set the second/third byte (address/numeric for TMCC1 val = 6) 130 tc.sendSerialMessage(m, null); 131 132 } else if (val == 8) { 133 SerialMessage m = new SerialMessage(); 134 m.setOpCode(0xFE); // set the first byte/TMCC1 opcode to 0xFE 135 m.putAsWord((mAddress * 128) + 24); // set the second/third byte (address/numeric for TMCC1 val = 8) 136 tc.sendSerialMessage(m, null); 137 138 } else if (val == 34) { 139 SerialMessage m = new SerialMessage(); 140 m.setOpCode(0xFE); // set the first byte/TMCC1 opcode to 0xFE 141 m.putAsWord((mAddress * 128) + 39); // set the second/third byte (address/numeric for TMCC1 val = 34) 142 tc.sendSerialMessage(m, null); 143 144 } else if (val == 36) { 145 SerialMessage m = new SerialMessage(); 146 m.setOpCode(0xFE); // set the first byte/TMCC1 opcode to 0xFE 147 m.putAsWord((mAddress * 128) + 41); // set the second/third byte (address/numeric for TMCC1 val = 36) 148 tc.sendSerialMessage(m, null); 149 150 } else if (val == 74) { 151 SerialMessage m = new SerialMessage(); 152 m.setOpCode(0xFE); // set the first byte/TMCC1 opcode to 0xFE 153 m.putAsWord((mAddress * 128) + 43); // set the second/third byte (address/numeric for TMCC1 val = 74) 154 tc.sendSerialMessage(m, null); 155 156 } else if (val == 75) { 157 SerialMessage m = new SerialMessage(); 158 m.setOpCode(0xFE); // set the first byte/TMCC1 opcode to 0xFE 159 m.putAsWord((mAddress * 128) + 44); // set the second/third byte (address/numeric for TMCC1 val = 75) 160 tc.sendSerialMessage(m, null); 161 162 } else if (val == 76) { 163 SerialMessage m = new SerialMessage(); 164 m.setOpCode(0xFE); // set the first byte/TMCC1 opcode to 0xFE 165 m.putAsWord((mAddress * 128) + 45); // set the second/third byte (address/numeric for TMCC1 val = 76) 166 tc.sendSerialMessage(m, null); 167 168 } else if (val == 740) { 169 SerialMessage m = new SerialMessage(); 170 m.setOpCode(0xFE); // set the first byte/TMCC1 opcode to 0xFE 171 m.putAsWord((mAddress * 128) + 59); // set the second/third byte (address/numeric for TMCC1 val = 740) 172 tc.sendSerialMessage(m, null); 173 174 } else if (val == 750) { 175 SerialMessage m = new SerialMessage(); 176 m.setOpCode(0xFE); // set the first byte/TMCC1 opcode to 0xFE 177 m.putAsWord((mAddress * 128) + 60); // set the second/third byte (address/numeric for TMCC1 val = 750) 178 tc.sendSerialMessage(m, null); 179 180 } else if (val == 760) { 181 SerialMessage m = new SerialMessage(); 182 m.setOpCode(0xFE); // set the first byte/TMCC1 opcode to 0xFE 183 m.putAsWord((mAddress * 128) + 61); // set the second/third byte (address/numeric for TMCC1 val = 760) 184 tc.sendSerialMessage(m, null); 185 186 } else { 187 SerialMessage m = new SerialMessage(); 188 m.setOpCode(0x00); 189 m.putAsWord(00003); 190 tc.sendSerialMessage(m, null); 191 log.warn("Value Entered is Not a TMCC1 Feature Type"); 192 } 193 194 } 195 196 } else { 197 SerialMessage m = new SerialMessage(); 198 m.setOpCode(0x00); 199 m.putAsWord(00000); 200 tc.sendSerialMessage(m, null); 201 log.warn("Address Must be Between 1-98 for TMCC"); 202 } 203 204 } else { 205 SerialMessage m = new SerialMessage(); 206 m.setOpCode(0x00); 207 m.putAsWord(00002); 208 tc.sendSerialMessage(m, null); 209 log.warn("CV Must Equal 2 for Programming TMCC Feature Type"); 210 211 } 212 213 // End the "writing..." process in SimpleProgrammer 214 notifyProgListenerEnd(p, _val, jmri.ProgListener.OK); 215 216 } 217 218 219 /** 220 * {@inheritDoc} 221 */ 222 @Override 223 public synchronized void readCV(String CVname, ProgListener p) throws ProgrammerException { 224 final int CV = Integer.parseInt(CVname); 225 log.debug("read CV={}", CV); 226 log.error("readCV not available in this protocol"); 227 throw new ProgrammerException(); 228 } 229 230 /** 231 * {@inheritDoc} 232 */ 233 @Override 234 public synchronized void confirmCV(String CV, int val, ProgListener p) throws ProgrammerException { 235 log.debug("confirm CV={}", CV); 236 log.error("confirmCV not available in this protocol"); 237 throw new ProgrammerException(); 238 } 239 240 /** 241 * {@inheritDoc} 242 * 243 * Can this ops-mode programmer read back values? For now, no, but maybe 244 * later. 245 * 246 * @return always false for now 247 */ 248 @Override 249 public boolean getCanRead() { 250 return false; 251 } 252 253 /** 254 * {@inheritDoc} 255 */ 256 @Override 257 public boolean getLongAddress() { 258 return mLongAddr; 259 } 260 261 /** 262 * {@inheritDoc} 263 */ 264 @Override 265 public int getAddressNumber() { 266 return mAddress; 267 } 268 269 /** 270 * {@inheritDoc} 271 */ 272 @Override 273 public String getAddress() { 274 return "" + getAddressNumber() + " " + getLongAddress(); 275 } 276 277 // initialize logging 278 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TmccOpsModeProgrammer.class); 279 280 281}