001package jmri.jmrit.symbolicprog;
002
003import java.util.HashMap;
004import javax.swing.JLabel;
005import org.slf4j.Logger;
006import org.slf4j.LoggerFactory;
007
008/**
009 * Representation of a short address (CV1).
010 * <p>
011 * This is a decimal value, extended to modify the other CVs when written. The
012 * CVs to be modified and their new values are stored in two arrays for
013 * simplicity.
014 * <p>
015 *
016 * The NMRA has decided that writing CV1 causes other CVs to update within the
017 * decoder (CV19 for consisting, CV29 for short/long address). We want DP to
018 * overwrite those _after_ writing CV1, so that the DP values are forced to be
019 * the correct ones.
020 *
021 * @author Bob Jacobsen Copyright (C) 2001, 2006, 2007
022 *
023 */
024public class ShortAddrVariableValue extends DecVariableValue {
025
026    public ShortAddrVariableValue(String name, String comment, String cvName,
027            boolean readOnly, boolean infoOnly, boolean writeOnly, boolean opsOnly,
028            String cvNum, String mask,
029            HashMap<String, CvValue> v, JLabel status, String stdname) {
030        // specify min, max value explicitly.
031        // short address 0 = alternate power source as per S9.2.2.
032        super(name, comment, cvName, readOnly, infoOnly, writeOnly, opsOnly, cvNum, mask, 0, 127, v, status, stdname);
033
034        // add default overwrites as per NMRA spec
035        firstFreeSpace = 0;
036        setModifiedCV("19");         // consisting
037        setModifiedCV("29");         // control bits
038    }
039
040    /**
041     * Register a CV to be modified regardless of current value.
042     * @param cvNum cv number string.
043     */
044    public void setModifiedCV(String cvNum) {
045        if (firstFreeSpace >= maxCVs) {
046            log.error("too many CVs registered for changes!");
047            return;
048        }
049        cvNumbers[firstFreeSpace] = cvNum;
050        newValues[firstFreeSpace] = -10;
051        firstFreeSpace++;
052    }
053
054    /**
055     * Change CV values due to change in short address
056     */
057    private void updateCvForAddrChange() {
058        for (int i = 0; i < firstFreeSpace; i++) {
059            CvValue cv = _cvMap.get(cvNumbers[i]);
060            if (cv == null) {
061                continue;  // if CV not present this decoder...
062            }
063            if (!cvNumbers[i].equals(cv.number())) {
064                log.error("CV numbers don't match: {} {}", cvNumbers[i], cv.number());
065            }
066            cv.setToWrite(true);
067            cv.setState(ValueState.EDITED);
068            if (log.isDebugEnabled()) {
069                log.debug("Mark to write {}", cv.number());
070            }
071        }
072    }
073
074    int firstFreeSpace = 0;
075    static final int maxCVs = 20;
076    String[] cvNumbers = new String[maxCVs];
077    int[] newValues = new int[maxCVs];
078
079    @Override
080    public void writeChanges() {
081        if (getReadOnly()) {
082            log.error("unexpected writeChanges operation when readOnly is set");
083        }
084        setBusy(true);  // will be reset when value changes
085        // mark other CVs as possibly needing write
086        updateCvForAddrChange();
087        // and change the value of this one
088        _cvMap.get(getCvNum()).write(_status);
089    }
090
091    @Override
092    public void writeAll() {
093        if (getReadOnly()) {
094            log.error("unexpected writeAll operation when readOnly is set");
095        }
096        setBusy(true);  // will be reset when value changes
097        // mark other CVs as possibly needing write
098        updateCvForAddrChange();
099        // and change the value of this one
100        _cvMap.get(getCvNum()).write(_status);
101    }
102
103    // clean up connections when done
104    @Override
105    public void dispose() {
106        super.dispose();
107    }
108
109    // initialize logging
110    private final static Logger log = LoggerFactory.getLogger(ShortAddrVariableValue.class);
111
112}