001package jmri.jmrix.bachrus;
002
003import org.slf4j.Logger;
004import org.slf4j.LoggerFactory;
005
006/**
007 * Carries the reply to an SprogMessage
008 *
009 * The format of a KPF-Zeller message is <code>*0000;V3.0%\n</code>
010 * but because we terminate on ";", it comes across as
011 * <code>V3.0%\n*0000;</code>
012 *
013 * @author Bob Jacobsen Copyright (C) 2001
014 * @author Andrew Crosland Copyright (C) 2010
015 */
016public class SpeedoReply extends jmri.jmrix.AbstractMRReply {
017 // This should be an extension af AbstractMRReply and needs re-factoring
018
019    // create a new one
020    public SpeedoReply() {
021        super();
022    }
023
024    // copy one
025    public SpeedoReply(SpeedoReply m) {
026        this();
027        if (m == null) {
028            log.error("copy ctor of null message");
029            return;
030        }
031        _nDataChars = m._nDataChars;
032        if (m.isUnsolicited()) {
033            setUnsolicited();
034        }
035        for (int i = 0; i < _nDataChars; i++) {
036            _dataChars[i] = m._dataChars[i];
037        }
038    }
039
040    // from String
041    public SpeedoReply(String s) {
042        this();
043        _nDataChars = s.length();
044        for (int i = 0; i < _nDataChars; i++) {
045            _dataChars[i] = s.charAt(i);
046        }
047    }
048
049    public int getCount() {
050        log.debug("getCount of n= {} '{}'", _nDataChars, this);
051        // KPF-Zeller formatting
052        if (_nDataChars == 13) {
053            try {
054                log.trace("selected out '{}'", this.toString().substring(8, 12));
055                return Integer.parseInt(this.toString().substring(8, 12), 10);
056            } catch (NumberFormatException ex) {
057                log.trace("return 0 because of fault");
058                return 0;
059            }
060        }
061        // drM SPC200R
062        if (_nDataChars == 7 &&
063               (_dataChars[0] == 0x50 || _dataChars[0] == 0x51 || _dataChars[0] == 0x52 || _dataChars[0] == 0x53) ) {
064            // Check for invalid speed flag (0x2D = 45)
065            for (int i = 3; i <= 6; i++) {
066                if (_dataChars[i] == 0x2D) {
067                    return -1;
068                }
069            }      
070            int hundreds = _dataChars[3];
071            int tens = _dataChars[4];
072            int units = _dataChars[5];
073            int tenths = _dataChars[6];
074
075            // Basic range check (optional)
076            if (hundreds > 9 || tens > 9 || units > 9 || tenths > 9) {
077                return -1;
078            }
079
080            Float speed = hundreds * 100 + tens * 10 + units + tenths / 10.0f;
081            int scaled = Math.round(speed * 10); // e.g. 123.4 -> 1234
082            log.trace("Speed float {} int {}", speed, scaled);
083            return scaled; 
084        }
085        // bachrus formatting
086        // don't return 0 as it will cause an exception
087        if (_nDataChars < 9) {
088            return -1;
089        }
090        try {
091            return Integer.parseInt(this.toString().substring(2, 8), 16);
092        } catch (NumberFormatException ex) {
093            return 0;
094        }
095    }
096
097    /**
098     * Series numbers define the actual hardware, i.e. wheel circumference.
099     * <dl>
100     * <dt>0</dt><dd>none, ignore</dd>
101     * <dt>4</dt><dd>Reader 40</dd>
102     * <dt>5</dt><dd>Reader 50</dd>
103     * <dt>6</dt><dd>Reader 60</dd>
104     * <dt>103</dt><dd>KPR-Zeller</dd>
105     * <dt>200</dt><dd>drM SPC200R</dd>
106     * </dl>
107     * @return type code for specific reply content
108     */
109    public int getSeries() {
110        log.debug("getSeries of n= {} '{}'", _nDataChars, this);
111        // KPF-Zeller formatting
112        if (_nDataChars == 13) {
113            return 103;
114        }
115        // drM SPC200R formatting
116        if (_nDataChars == 7) {
117            return 200;
118        }
119        // bachrus formatting
120        if (_nDataChars < 7) {
121            return 0;
122        }
123        try {
124            return Integer.parseInt(this.toString().substring(1, 2));
125        } catch (NumberFormatException ex) {
126            return 0;
127        }
128    }
129
130    @Override
131    public int match(String s) {
132        // find a specific string in the reply
133        String rep = new String(_dataChars, 0, _nDataChars);
134        return rep.indexOf(s);
135    }
136
137    static public final int maxSize = 32;
138
139    @Override
140    public int maxSize() {
141        return maxSize;
142    }
143
144    /**
145     * skipPrefix is not used at this point in time, but is
146     * defined as abstract in AbstractMRReply
147     */
148    @Override
149    protected int skipPrefix(int index) {
150        return -1;
151    }
152
153    private final static Logger log = LoggerFactory.getLogger(SpeedoReply.class);
154
155}