001package jmri.jmrix.can.cbus;
002
003import jmri.AddressedProgrammer;
004import jmri.Programmer;
005import jmri.jmrix.can.CanSystemConnectionMemo;
006import jmri.jmrix.can.ConfigurationManager;
007import jmri.jmrix.can.cbus.swing.modeswitcher.SprogCbusSprog3PlusModeSwitcherFrame;
008import jmri.managers.DefaultProgrammerManager;
009
010import org.slf4j.Logger;
011import org.slf4j.LoggerFactory;
012
013/**
014 * Extend DefaultProgrammerManager to provide programmers for CBUS systems
015 *
016 * Added methods to manipulate the programmer availability to support hardware
017 * that can redirect ops mode or service mode packets to a particular interface.
018 * 
019 * @see jmri.managers.DefaultProgrammerManager
020 * @author Andrew crosland Copyright (C) 2009, 2020
021 */
022public class CbusDccProgrammerManager extends DefaultProgrammerManager {
023
024    private boolean _isAddressedModePossible = true;
025    private boolean _isGlobalProgrammerAvailable = true;
026    
027    private final CbusPreferences prefs;
028
029    public CbusDccProgrammerManager(Programmer serviceModeProgrammer, CanSystemConnectionMemo memo) {
030        super(serviceModeProgrammer, memo);
031        tc = memo.getTrafficController();
032        prefs = memo.get(jmri.jmrix.can.cbus.CbusPreferences.class);
033        log.info("Preferences for programmers start as: global {} addressed {}", prefs.isGlobalProgrammerAvailable(), prefs.isAddressedModePossible());
034        validateProgrammingModes(memo);
035        log.info("Preferences for programmers now: global {} addressed {}", prefs.isGlobalProgrammerAvailable(), prefs.isAddressedModePossible());
036        log.info("ProgModeSwitch is {}", memo.getProgModeSwitch());
037    }
038
039    jmri.jmrix.can.TrafficController tc;
040
041    /**
042     * Check that the programming mode preferences, which may be default values for a new connection
043     * or if they have never been set, are consistent with the programmer modes for
044     * the connected hardware
045     * 
046     * @param memo CAN system connection emo
047     */
048    protected final void validateProgrammingModes(CanSystemConnectionMemo memo) {
049        boolean igpa = prefs.isGlobalProgrammerAvailable();
050        boolean iamp = prefs.isAddressedModePossible();
051        int ptm = prefs.getProgTrackMode();
052        ConfigurationManager.ProgModeSwitch pms = memo.getProgModeSwitch();
053        switch (pms) {
054            default:
055            case NONE:
056                // Force both programmers available, e.g. for CANCMD that has no mode switching
057                igpa = true;
058                iamp = true;
059                break;
060                
061            case EITHER:
062                if ((igpa && iamp) || (!igpa && !iamp)) {
063                    // Default to global (service) mode if inconsistent prefs
064                    igpa = true;
065                    iamp = false;
066                } // else prefs are OK
067                break;
068                
069            case SPROG3PLUS:
070                if (ptm == SprogCbusSprog3PlusModeSwitcherFrame.PROG_AR_MODE) {
071                    // No global (service) mode if using auto-reverse
072                    igpa = false;
073                    iamp = true;
074                } else {
075                    // Both modes are available global (service) mode
076                    igpa = true;
077                    iamp = true;
078                }
079                break;
080        }
081        prefs.setProgrammersAvailable(igpa, iamp);
082        mySetGlobalProgrammerAvailable(igpa);
083        mySetAddressedModePossible(iamp);
084    }
085    
086    /**
087     * CBUS DCC Programmer has hardware support for ops mode
088     *
089     * @return true
090     */
091    public boolean isAddressedModeHardwareAvailable() {
092        return true;
093    }
094
095    /**
096     * CBUS DCC Programmer has hardware support for service mode
097     *
098     * @return true if available
099     */
100    public boolean isGlobalProgrammerHardwareAvailable() {
101        return true;
102    }
103    
104    /**
105     * Does Programmer currently support ops mode
106     *
107     * @return true if possible
108     */
109    @Override
110    public boolean isAddressedModePossible() {
111        return _isAddressedModePossible;
112    }
113
114    /**
115     * Set availability of addressed (ops mode) programmer.
116     * To avoid calling overridable method from constructor
117     * 
118     * @param state true if possible
119     */
120    public final void mySetAddressedModePossible(boolean state) {
121        boolean old = _isAddressedModePossible;
122        _isAddressedModePossible = state;
123        firePropertyChange("addressedModePossible", old, state);
124    }
125
126    /**
127     * Set availability of addressed (ops mode) programmer.
128     * 
129     * @param state true if available
130     */
131    public void setAddressedModePossible(boolean state) {
132        mySetAddressedModePossible(state);
133    }
134
135    /**
136     * Programmer currently support service mode
137     *
138     * @return true if available
139     */
140    @Override
141    public boolean isGlobalProgrammerAvailable() {
142        return _isGlobalProgrammerAvailable;
143    }
144    
145    /**
146     * Set availability of global (service mode) programmer.
147     * To avoid calling overridable method from constructor
148     * 
149     * @param state true if available
150     */
151    public final void mySetGlobalProgrammerAvailable(boolean state) {
152        boolean old = _isGlobalProgrammerAvailable;
153        _isGlobalProgrammerAvailable = state;
154        firePropertyChange("globalProgrammerAvailable", old, state);
155    }
156
157    /**
158     * Set availability of global (service mode) programmer.
159     * 
160     * @param state true if available
161     */
162    public void setGlobalProgrammerAvailable(boolean state) {
163        mySetGlobalProgrammerAvailable(state);
164    }
165
166    @Override
167    public AddressedProgrammer getAddressedProgrammer(boolean pLongAddress, int pAddress) {
168        return new CbusDccOpsModeProgrammer(pAddress, pLongAddress, tc);
169    }
170
171    @Override
172    public AddressedProgrammer reserveAddressedProgrammer(boolean pLongAddress, int pAddress) {
173        return null;
174    }
175    
176    private final static Logger log = LoggerFactory.getLogger(CbusDccProgrammerManager.class);
177    
178}