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