001package jmri.jmrix.dcc4pc;
002
003import java.beans.PropertyChangeListener;
004import java.util.List;
005import javax.annotation.Nonnull;
006import jmri.RailCom;
007import jmri.AddressedProgrammer;
008import jmri.AddressedProgrammerManager;
009import jmri.ProgListener;
010import jmri.Programmer;
011import jmri.ProgrammerException;
012import jmri.ProgrammingMode;
013
014/**
015 * Provides an Ops mode proxy programming interface for a RailCom Reader. This
016 * forwards the read request to the command station to forward on and handles
017 * sending back the CV reading results from the RailCom message
018 *
019 * @see jmri.Programmer
020 * @author Kevin Dickerson Copyright (C) 2012
021 */
022public class Dcc4PcOpsModeProgrammer extends jmri.jmrix.AbstractProgrammer implements PropertyChangeListener, AddressedProgrammer {
023
024    int pAddress = 0;
025    boolean pLongAddress;
026    int progState = 0;
027    RailCom rcTag;
028    int value;
029    int cv;
030    jmri.ProgListener progListener = null;
031
032    static protected final int DCC4PC_PROGRAMMER_TIMEOUT = 2000;
033
034    AddressedProgrammerManager defaultManager;
035    Programmer defaultProgrammer;
036
037    public Dcc4PcOpsModeProgrammer(boolean pLongAddress, int pAddress, AddressedProgrammerManager dp) {
038        defaultManager = dp;
039        defaultProgrammer = defaultManager.getAddressedProgrammer(pLongAddress, pAddress);
040        this.pAddress = pAddress;
041        this.pLongAddress = pLongAddress;
042        rcTag = (RailCom) jmri.InstanceManager.getDefault(jmri.RailComManager.class).provideIdTag("" + pAddress);
043    }
044
045    /**
046     * {@inheritDoc}
047     *
048     * Send an ops-mode write request to the XPressnet.
049     */
050    @Override
051    synchronized public void writeCV(String CVname, int val, ProgListener p) throws ProgrammerException {
052        final int CV = Integer.parseInt(CVname);
053        rcTag.setExpectedCv(CV);
054        progListener = p;
055        defaultProgrammer.writeCV(CVname, val, new ProxyProgList());
056    }
057
058    /**
059     * {@inheritDoc}
060     */
061    @Override
062    synchronized public void readCV(String CVname, ProgListener p) throws ProgrammerException {
063        final int CV = Integer.parseInt(CVname);
064        rcTag.addPropertyChangeListener(this);
065        rcTag.setExpectedCv(CV);
066        progListener = p;
067        this.cv = CV;
068        startLongTimer();
069        defaultProgrammer.readCV(CVname, new ProxyProgList());
070        notifyProgListenerEnd(progListener, CV, jmri.ProgListener.OK);  // this call seems seriously misplaced; is it an error?
071    }
072
073    static class ProxyProgList implements jmri.ProgListener {
074
075        ProxyProgList() {
076        }
077
078        @Override
079        public void programmingOpReply(int value, int status) {
080            /*if(status!=NotImplemented){
081                notifyProgListenerEnd(progListener, 0, status);
082             }
083             log.debug("Actual Command station returned " + status + " " + value);*/
084        }
085    }
086
087    /**
088     * {@inheritDoc}
089     */
090    @Override
091    public void confirmCV(String cvName, int val, ProgListener p) throws ProgrammerException {
092        int cvValue = Integer.parseInt(cvName);
093        rcTag.addPropertyChangeListener(this);
094        rcTag.setExpectedCv(cvValue);
095        synchronized (this) {
096            progListener = p;
097        }
098        this.cv = cvValue;
099        defaultProgrammer.confirmCV(cvName, val, new ProxyProgList());
100    }
101
102    /**
103     * {@inheritDoc}
104     *
105     * Types implemented here.
106     */
107    @Override
108    @Nonnull
109    public List<ProgrammingMode> getSupportedModes() {
110        return defaultProgrammer.getSupportedModes();
111    }
112
113    /**
114     * {@inheritDoc}
115     */
116    @Override
117    synchronized protected void timeout() {
118        rcTag.removePropertyChangeListener(this);
119        rcTag.setExpectedCv(-1);
120        notifyProgListenerEnd(progListener, 0, ProgListener.FailedTimeout);
121    }
122
123    /**
124     * {@inheritDoc}
125     */
126    @Override
127    public void propertyChange(java.beans.PropertyChangeEvent e) {
128        if (e.getSource() != rcTag) {
129            log.error("Unexpected source");
130        }
131        if (e.getPropertyName().equals("cvvalue")) {
132            int repliedCv = (Integer) e.getOldValue();
133            log.info("propertyChange {} {}", e.getOldValue(), e.getNewValue());
134            if (repliedCv == cv) {
135                int newValue = (Integer) e.getNewValue();
136                stopTimer();
137                rcTag.removePropertyChangeListener(this);
138                synchronized (this) {
139                    notifyProgListenerEnd(progListener, newValue, ProgListener.OK);
140                }
141            } else {
142                log.error("Unexpected cv {} returned, was expecting CV {}", repliedCv, cv);
143            }
144        }
145    }
146
147    /**
148     * {@inheritDoc}
149     */
150    @Override
151    public boolean getLongAddress() {
152        return pLongAddress;
153    }
154
155    /**
156     * {@inheritDoc}
157     */
158    @Override
159    public int getAddressNumber() {
160        return pAddress;
161    }
162
163    /**
164     * {@inheritDoc}
165     */
166    @Override
167    public String getAddress() {
168        return "" + getAddressNumber() + " " + getLongAddress();
169    }
170
171    // initialize logging
172    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Dcc4PcOpsModeProgrammer.class);
173
174}