001package jmri.jmrix.tmcc; 002 003import java.util.ArrayList; 004import java.util.List; 005import javax.annotation.Nonnull; 006 007import jmri.ProgrammingMode; 008import jmri.jmrix.AbstractProgrammer; 009 010 011/** 012 * Implements the jmri.Programmer interface via commands for the TMCC 013 * control interface. 014 * 015 * Made from the EasyDCC programmer 016 * 017 * @author Bob Jacobsen Copyright (C) 2001, 2025 018 * with edits/additions by 019 * @author Timothy Jump Copyright (C) 2025 020 */ 021public class TmccProgrammer extends AbstractProgrammer { 022 023 public TmccProgrammer(TmccSystemConnectionMemo memo) { 024 tc = memo.getTrafficController(); 025 } 026 027 protected SerialTrafficController tc = null; 028 029 /** 030 * {@inheritDoc} 031 */ 032 @Override 033 @Nonnull 034 public List<ProgrammingMode> getSupportedModes() { 035 List<ProgrammingMode> ret = new ArrayList<ProgrammingMode>(); 036 037 ret.add(TmccProgrammerManager.TMCCMODE1_ENGID); 038 ret.add(TmccProgrammerManager.TMCCMODE2_ENGID); 039 040 ret.add(TmccProgrammerManager.TMCCMODE1_TRKID); 041 ret.add(TmccProgrammerManager.TMCCMODE2_TRKID); 042 043 ret.add(TmccProgrammerManager.TMCCMODE1_SWID); 044 ret.add(TmccProgrammerManager.TMCCMODE1_ACCID); 045 046 return ret; 047 048 } 049 050 051 int _cv; // points to "CV" input from Simple Programmer 052 int _val; // points to "Value" input from Simple Programmer 053 int _func; // points to "SET" command for TMCC1 and TMCC2 loco and track ID numbers 054 055 056 /** 057 * {@inheritDoc} 058 */ 059 @Override 060 public synchronized void writeCV(String CVname, int val, jmri.ProgListener p) throws jmri.ProgrammerException { 061 final int CV = Integer.parseInt(CVname); 062 063 _cv = CV; // Value from Simple Programmer "CV" input 064 _val = val; // Value from Simple Programmer "Value" input 065 _func = 0x00002B; // SET command for both TMCC1 and TMCC2 066 067 // validate CV == 1 for TMCC loco ID programming 068 // validate ID#/address for TMCC is between 1-98 069 // format and send the TMCC loco ID write message 070 // note: the argument is long containing 3 bytes 071 072 if (CV == 1) { 073 074 if (val > 0 && val < 99) { 075 076 if (getMode() == TmccProgrammerManager.TMCCMODE1_ENGID) { 077 SerialMessage m = new SerialMessage(); 078 m.setOpCode(0xFE); // set the first byte/TMCC1 opcode to 0xFE 079 m.putAsWord((val * 128) + _func); // set the second/third byte (address/SET command for TMCC1) 080 tc.sendSerialMessage(m, null); 081 } 082 083 if (getMode() == TmccProgrammerManager.TMCCMODE2_ENGID) { 084 SerialMessage m = new SerialMessage(); 085 m.setOpCode(0xF8); // set the first byte/TMCC2 opcode to 0xF8 for ENGID 086 m.putAsWord(((val * 512) + 256) + _func); // set the second/third byte (address/SET command for TMCC2) 087 tc.sendSerialMessage(m, null); 088 } 089 090 if (getMode() == TmccProgrammerManager.TMCCMODE1_TRKID) { 091 if (val < 10) { 092 SerialMessage m = new SerialMessage(); 093 m.setOpCode(0xFE); // set the first byte/TMCC1 opcode to 0xFE 094 m.putAsWord(((val * 128) + 51200)+ _func); // set the second/third byte (address/SET command for TMCC1) 095 tc.sendSerialMessage(m, null); 096 097 } else { 098 SerialMessage m = new SerialMessage(); 099 m.setOpCode(0x00); 100 m.putAsWord(00000); 101 tc.sendSerialMessage(m, null); 102 log.warn("Address Must be Between 1-9 for TMCC1_TRK"); 103 } 104 } 105 106 if (getMode() == TmccProgrammerManager.TMCCMODE2_TRKID) { 107 SerialMessage m = new SerialMessage(); 108 m.setOpCode(0xF9); // set the first byte/TMCC2 opcode to 0xF9 for TRKID 109 m.putAsWord(((val * 512) + 256) + _func); // set the second/third byte (address/SET command for TMCC2) 110 tc.sendSerialMessage(m, null); 111 } 112 113 if (getMode() == TmccProgrammerManager.TMCCMODE1_SWID) { 114 SerialMessage m = new SerialMessage(); 115 m.setOpCode(0xFE); // set the first byte/TMCC1 opcode to 0xFE 116 m.putAsWord(((val * 128) + 16384) + _func); // set the second/third byte (address/SET command for TMCC2) 117 tc.sendSerialMessage(m, null); 118 } 119 120 if (getMode() == TmccProgrammerManager.TMCCMODE1_ACCID) { 121 SerialMessage m = new SerialMessage(); 122 m.setOpCode(0xFE); // set the first byte/TMCC1 opcode to 0xFE 123 m.putAsWord(((val * 128) + 32768) + _func); // set the second/third byte (address/SET command for TMCC2) 124 tc.sendSerialMessage(m, null); 125 } 126 127 } else { 128 SerialMessage m = new SerialMessage(); 129 m.setOpCode(0x00); 130 m.putAsWord(00000); 131 tc.sendSerialMessage(m, null); 132 log.warn("Address Must be Between 1-98 for TMCC"); 133 } 134 135 } else { 136 SerialMessage m = new SerialMessage(); 137 m.setOpCode(0x00); 138 m.putAsWord(00001); 139 tc.sendSerialMessage(m, null); 140 log.warn("CV Must Equal 1 for Programming TMCC Loco/Engine, Switch, Accessory ID#s"); 141 } 142 143 // End the "writing..." process in SimpleProgrammer 144 notifyProgListenerEnd(p, _val, jmri.ProgListener.OK); 145 146 } 147 148 149 /** 150 * {@inheritDoc} 151 */ 152 @Override 153 public synchronized void confirmCV(String CV, int val, jmri.ProgListener p) throws jmri.ProgrammerException { 154 } 155 156 /** 157 * {@inheritDoc} 158 */ 159 @Override 160 public synchronized void readCV(String CVname, jmri.ProgListener p) throws jmri.ProgrammerException { 161 } 162 163 164 /** 165 * {@inheritDoc} 166 */ 167 @Override 168 synchronized protected void timeout() { 169 } 170 171 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TmccProgrammer.class); 172 173}