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_SWID);
041        ret.add(TmccProgrammerManager.TMCCMODE1_ACCID);
042
043        return ret;
044
045    }
046
047
048    int _cv; // points to "CV" input from Simple Programmer
049    int _val; // points to "Value" input from Simple Programmer
050    int _func; // points to "SET" command for TMCC1 and TMCC2 loco ID numbers
051
052
053    /** 
054     * {@inheritDoc}
055     */
056    @Override
057    public synchronized void writeCV(String CVname, int val, jmri.ProgListener p) throws jmri.ProgrammerException {
058        final int CV = Integer.parseInt(CVname);
059
060        _cv = CV;  // Value from Simple Programmer "CV" input
061        _val = val; // Value from Simple Programmer "Value" input
062        _func = 0x00002B; // SET command for both TMCC1 and TMCC2
063
064        // validate CV == 1 for TMCC loco ID programming
065        // validate ID#/address for TMCC is between 1-98
066        // format and send the TMCC loco ID write message
067        // note: the argument is long containing 3 bytes
068
069        if (CV == 1) {
070            
071            if (val > 0 && val < 99) {
072
073                if (getMode() == TmccProgrammerManager.TMCCMODE1_ENGID) {
074                    SerialMessage m = new SerialMessage();
075                    m.setOpCode(0xFE); // set the first byte/TMCC1 opcode to 0xFE
076                    m.putAsWord((val * 128) + _func); // set the second/third byte (address/SET command for TMCC1)
077                    tc.sendSerialMessage(m, null);
078                }
079
080                if  (getMode() == TmccProgrammerManager.TMCCMODE2_ENGID) {
081                    SerialMessage m = new SerialMessage();
082                    m.setOpCode(0xF8); // set the first byte/TMCC2 opcode to 0xF8
083                    m.putAsWord(((val * 512) + 256) + _func); // set the second/third byte (address/SET command for TMCC2)
084                    tc.sendSerialMessage(m, null);
085                }
086                
087                if  (getMode() == TmccProgrammerManager.TMCCMODE1_SWID) {
088                    SerialMessage m = new SerialMessage();
089                    m.setOpCode(0xFE); // set the first byte/TMCC1 opcode to 0xFE
090                    m.putAsWord(((val * 128) + 16384) + _func); // set the second/third byte (address/SET command for TMCC2)
091                    tc.sendSerialMessage(m, null);
092                }
093                
094                if  (getMode() == TmccProgrammerManager.TMCCMODE1_ACCID) {
095                    SerialMessage m = new SerialMessage();
096                    m.setOpCode(0xFE); // set the first byte/TMCC1 opcode to 0xFE
097                    m.putAsWord(((val * 128) + 32768) + _func); // set the second/third byte (address/SET command for TMCC2)
098                    tc.sendSerialMessage(m, null);
099                }              
100
101
102            } else {
103                SerialMessage m = new SerialMessage();
104                m.setOpCode(0x00);
105                m.putAsWord(00000);
106                tc.sendSerialMessage(m, null);
107                log.warn("Address Must be Between 1-98 for TMCC");
108            }
109
110
111        } else {
112            SerialMessage m = new SerialMessage();
113            m.setOpCode(0x00);
114            m.putAsWord(00001);
115            tc.sendSerialMessage(m, null);
116            log.warn("CV Must Equal 1 for Programming TMCC Loco/Engine, Switch, Accessory ID#s");
117
118        }
119
120        // End the "writing..." process in SimpleProgrammer
121        notifyProgListenerEnd(p, _val, jmri.ProgListener.OK);
122 
123    }
124
125
126    /** 
127     * {@inheritDoc}
128     */
129    @Override
130    public synchronized void confirmCV(String CV, int val, jmri.ProgListener p) throws jmri.ProgrammerException {
131    }
132
133    /** 
134     * {@inheritDoc}
135     */
136    @Override
137    public synchronized void readCV(String CVname, jmri.ProgListener p) throws jmri.ProgrammerException {
138    }
139
140
141    /** 
142     * {@inheritDoc}
143     */
144    @Override
145    synchronized protected void timeout() {
146    }
147    
148    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TmccProgrammer.class);
149
150}