001package jmri.jmrix.tams;
002
003/**
004 * Encodes a message to a Tams MasterControl command station.
005 * <p>
006 * The {@link TamsReply} class handles the response from the command station.
007 * <p>
008 * Based on work by Bob Jacobsen and Kevin Dickerson
009 *
010 * @author Jan Boen
011 */
012public class TamsMessage extends jmri.jmrix.AbstractMRMessage {
013
014    static private final int TamsProgrammingTimeout = 5000;//ms
015
016    //The oneByteReply is used to tell TamsReply if one or more bytes are expected
017    //The lastByteReply is gives the value of the last byte to be expected, for sensors this is always 0x00
018    //Has been set to sensor value as we expect this to the most common binary type of reply
019    //Is used in conjunction with isBinary() = true
020    //When receiving an ASCII reply we scan for ] which indicates end of reply. Anything after this can be ignored
021    // accessor to get one element of the TamsMessage
022    @Override
023    public int getElement(int n) {
024        return _dataChars[n];
025    }
026
027    //Extend the class with extra Tams Specific variables
028    private char _replyType = 'X'; //C(ommand Station), S(ensor), T(urnout), P(ower), L(oco), X(Undefined), M(anual) via PacketGen
029
030    public char getReplyType() {
031        return _replyType;
032    }
033
034    public void setReplyType(char rt) {
035        _replyType = rt;
036    }
037
038    private boolean _replyOneByte = true;//Will it be a single byte reply?
039
040    public boolean getReplyOneByte() {
041        return _replyOneByte;
042    }
043
044    public void setReplyOneByte(boolean rob) {
045        _replyOneByte = rob;
046    }
047
048    private int _replyLastByte = TamsConstants.EOM00;//What will be the last byte of a multi byte reply?
049
050    public int getReplyLastByte() {
051        return _replyLastByte;
052    }
053
054    public void setReplyLastByte(int rlb) {
055        _replyLastByte = rlb;
056    }
057
058    public TamsMessage() {
059        super();
060    }
061
062    // create a new one
063    public TamsMessage(int i) {
064        super(i);
065    }
066
067    // copy one
068    public TamsMessage(TamsMessage m) {
069        super(m);
070    }
071
072    // from String
073    public TamsMessage(String m) {
074        super(m);
075        setBinary(false);
076    }
077
078    // from binary
079    public TamsMessage(int[] m) {//an array of int will be interpreted as binary
080        this((m.length));
081        //int i = 0; // counter of byte in output message
082        int j = 0; // counter of byte in input packet
083        // add each byte of the input message
084        for (j = 0; j < m.length; j++) {
085            this.setElement(j, m[j]);//changed i to j
086            //i++;
087        }
088        setBinary(true);//Is a binary reply
089        setReplyOneByte(false);//By default we set false and then check if we must change
090        if ((this.getElement(1) == (TamsConstants.XSTATUS & TamsConstants.MASKFF)) || (this.getElement(1) == (TamsConstants.XEVENT & TamsConstants.MASKFF))) {
091            setReplyOneByte(true);
092        }
093        setReplyLastByte(TamsConstants.EOM00);//By default we set 0x00 and then check if we must change
094        if (this.getElement(1) == (TamsConstants.XEVTLOK & TamsConstants.MASKFF)) {
095            setReplyLastByte(TamsConstants.EOM80);
096        }
097        //log.info(jmri.util.StringUtil.appendTwoHexFromInt(this.getElement(1),""));
098        setRetries(5);
099        //log.info("Binary reply will be: one byte= " + getReplyOneByte() + ", last byte= " + getReplyLastByte());
100    }
101
102    static public final int POLLTIMEOUT = 100;
103
104    // static methods to return a formatted message
105    //Binary messages
106    //Set power OFF via XPwrOff (0xA6)
107    static public TamsMessage setXPwrOff() {
108        TamsMessage m = new TamsMessage(2);
109        m.setElement(0, TamsConstants.LEADINGX & TamsConstants.MASKFF);
110        m.setElement(1, TamsConstants.XPWROFF & TamsConstants.MASKFF);
111        m.setBinary(true);
112        m.setReplyOneByte(true);
113        m.setReplyType('P');
114        //log.info("Preformatted Tams message = " + Integer.toHexString(m.getElement(0)) + " " + Integer.toHexString(m.getElement(1)));
115        return m;
116    }
117
118    //Set power ON via XPwrOn (0xA7)
119    static public TamsMessage setXPwrOn() {
120        TamsMessage m = new TamsMessage(2);
121        m.setElement(0, TamsConstants.LEADINGX & TamsConstants.MASKFF);
122        m.setElement(1, TamsConstants.XPWRON & TamsConstants.MASKFF);
123        m.setBinary(true);
124        m.setReplyOneByte(true);
125        m.setReplyType('P');
126        //log.info("Preformatted Tams message = " + Integer.toHexString(m.getElement(0)) + " " + Integer.toHexString(m.getElement(1)));
127        return m;
128    }
129
130    //Get power status via XStatus (0xA2)
131    static public TamsMessage getXStatus() {
132        TamsMessage m = new TamsMessage(2);
133        m.setElement(0, TamsConstants.LEADINGX & TamsConstants.MASKFF);
134        m.setElement(1, TamsConstants.XSTATUS & TamsConstants.MASKFF);
135        m.setBinary(true);
136        m.setReplyOneByte(true);
137        m.setReplyType('P');
138        //log.info("Preformatted Tams getXStatus = " + Integer.toHexString(m.getElement(0)) + " " + Integer.toHexString(m.getElement(1)));
139        //log.info("isBinary= " + m.isBinary() + ", one byte reply " + m.getReplyOneByte() +  ", reply type " + m.getReplyType());
140        return m;
141    }
142
143    //Get sensor status via XEvtSen (0xCB)
144    //Only reports changes since last poll
145    static public TamsMessage getXEvtSen() {
146        TamsMessage m = new TamsMessage(2);
147        m.setElement(0, TamsConstants.LEADINGX & TamsConstants.MASKFF);
148        m.setElement(1, TamsConstants.XEVTSEN & TamsConstants.MASKFF);
149        m.setBinary(true);
150        m.setReplyOneByte(false);
151        m.setReplyLastByte(TamsConstants.EOM00);//No more sensor data is following
152        m.setReplyType('S');
153        //log.info("Preformatted Tams message = " + Integer.toHexString(m.getElement(0)) + " " + Integer.toHexString(m.getElement(1)));
154        return m;
155    }
156
157    //Get loco changes via XEvtLok (0xC9)
158    //Only reports changes which have not been initiated from PC
159    static public TamsMessage getXEvtLok() {
160        TamsMessage m = new TamsMessage(2);
161        m.setElement(0, TamsConstants.LEADINGX & TamsConstants.MASKFF);
162        m.setElement(1, TamsConstants.XEVTLOK & TamsConstants.MASKFF);
163        m.setBinary(true);
164        m.setReplyOneByte(false);
165        m.setReplyLastByte(TamsConstants.EOM80);//No more loco data is following
166        m.setReplyType('L');
167        //log.info("Preformatted Tams message = " + Integer.toHexString(m.getElement(0)) + " " + Integer.toHexString(m.getElement(1)));
168        return m;
169    }
170
171    //Get turnout changes via XEvtTrn (0xCA)
172    //Only reports changes which have not been initiated from PC
173    static public TamsMessage getXEvtTrn() {
174        TamsMessage m = new TamsMessage(2);
175        m.setElement(0, TamsConstants.LEADINGX & 0xFF);
176        m.setElement(1, TamsConstants.XEVTTRN & 0xFF);
177        m.setBinary(true);
178        m.setReplyOneByte(false);
179        m.setReplyType('T');
180        //log.info("Preformatted Tams message = " + Integer.toHexString(m.getElement(0)) + " " + Integer.toHexString(m.getElement(1)));
181        return m;
182    }
183
184    //Set Tams MC to report only sensors which have been changed on polling
185    static public TamsMessage setXSR() {
186        TamsMessage m = new TamsMessage("xSR 1");
187        m.setBinary(false);
188        m.setReplyOneByte(false);
189        m.setReplyType('S');
190        return m;
191    }
192
193    //Set Tams MC so that a sensor module with at least 1 bit set is reporting its status
194    static public TamsMessage setXSensOff() {
195        TamsMessage m = new TamsMessage(2);
196        m.setElement(0, TamsConstants.LEADINGX & 0xFF);
197        m.setElement(1, TamsConstants.XSENSOFF & 0xFF);
198        m.setBinary(true);
199        m.setReplyOneByte(false);
200        m.setReplyType('S');
201        return m;
202    }
203
204    //Command Station messages
205    static public TamsMessage getReadPagedCV(int cv) { //Rxxx
206        TamsMessage m = new TamsMessage("xPTRP " + cv);
207        m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE);
208        m.setTimeout(TamsProgrammingTimeout);
209        m.setBinary(false);
210        m.setReplyType('C');
211        return m;
212    }
213
214    static public TamsMessage getWritePagedCV(int cv, int val) { //Pxxx xxx
215        TamsMessage m = new TamsMessage("xPTWP " + cv + ", " + val);
216        m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE);
217        m.setTimeout(TamsProgrammingTimeout);
218        m.setBinary(false);
219        m.setReplyType('C');
220        return m;
221    }
222
223    static public TamsMessage getReadRegister(int reg) { //Vx
224        TamsMessage m = new TamsMessage("xPTRR " + reg);
225        m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE);
226        m.setTimeout(TamsProgrammingTimeout);
227        m.setBinary(false);
228        m.setReplyType('C');
229        return m;
230    }
231
232    static public TamsMessage getWriteRegister(int reg, int val) { //Sx xxx
233        TamsMessage m = new TamsMessage("xPTWR " + reg + ", " + val);
234        m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE);
235        m.setTimeout(TamsProgrammingTimeout);
236        m.setBinary(false);
237        m.setReplyType('C');
238        return m;
239    }
240
241    static public TamsMessage getReadDirectByteCV(int cv) { //Rxxx
242        TamsMessage m = new TamsMessage("xPTRD " + cv);
243        m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE);
244        m.setTimeout(TamsProgrammingTimeout);
245        m.setBinary(false);
246        m.setReplyType('C');
247        return m;
248    }
249
250    static public TamsMessage getWriteDirectByteCV(int cv, int val) { //Pxxx xxx
251        TamsMessage m = new TamsMessage("xPTWD " + cv + ", " + val);
252        m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE);
253        m.setTimeout(TamsProgrammingTimeout);
254        m.setBinary(false);
255        m.setReplyType('C');
256        return m;
257    }
258
259    static public TamsMessage getReadDirectBitCV(int cv) { //Rxxx
260        TamsMessage m = new TamsMessage("xPTRB " + cv);
261        m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE);
262        m.setTimeout(TamsProgrammingTimeout);
263        m.setBinary(false);
264        m.setReplyType('C');
265        return m;
266    }
267
268    static public TamsMessage getWriteDirectBitCV(int cv, int bit, int val) { //Pxxx xxx
269        TamsMessage m = new TamsMessage("xPTWB " + cv + ", " + bit + ", " + val);
270        m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE);
271        m.setTimeout(TamsProgrammingTimeout);
272        m.setBinary(false);
273        m.setReplyType('C');
274        return m;
275    }
276
277    static public TamsMessage getWriteOpsModeCVMsg(int adr, int cv, int val) { //Pxxx xxx
278        TamsMessage m = new TamsMessage("xPD " + adr + ", " + cv + ", " + val);
279        m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE);
280        m.setTimeout(TamsProgrammingTimeout);
281        m.setBinary(false);
282        m.setReplyType('C');
283        return m;
284    }
285
286    static public TamsMessage getWriteOpsModeAccCVMsg(int adr, int cv, int val) { //Pxxx xxx
287        TamsMessage m = new TamsMessage("xPA " + adr + ", " + cv + ", " + val);
288        m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE);
289        m.setTimeout(TamsProgrammingTimeout);
290        m.setBinary(false);
291        m.setReplyType('C');
292        return m;
293    }
294}