001package jmri.jmrix.powerline.cp290;
002
003import jmri.jmrix.powerline.SerialMessage;
004import jmri.jmrix.powerline.X10Sequence;
005
006/**
007 * Contains the data payload of a serial packet.
008 * <p>
009 * The transmission protocol can come in one of several forms:
010 * <ul>
011 * <li>If the interlocked parameter is false (default), the packet is just sent.
012 * If the response length is not zero, a reply of that length is expected.
013 * <li>If the interlocked parameter is true, the transmission will require a CRC
014 * interlock, which will be automatically added. (Design note: this is done to
015 * make sure that the messages remain atomic)
016 * </ul>
017 *
018 * @author Bob Jacobsen Copyright (C) 2001,2003, 2006, 2007, 2008
019 */
020public class SpecificMessage extends SerialMessage {
021    // is this logically an abstract class?
022
023    public SpecificMessage(int l) {
024        super(l);
025        setResponseLength(0);  // only polls require a response
026        setBinary(true);
027        setTimeout(5000);
028    }
029
030    /**
031     * This ctor interprets the String as the exact sequence to send,
032     * byte-for-byte.
033     *
034     * @param m message
035     * @param l response length in bytes
036     */
037    public SpecificMessage(String m, int l) {
038        super(m, l);
039    }
040
041    /**
042     * This ctor interprets the byte array as a sequence of characters to send.
043     *
044     * @param a Array of bytes to send
045     * @param l length of expected reply
046     */
047    public SpecificMessage(byte[] a, int l) {
048        super(a, l);
049    }
050
051    /**
052     * Find 1st byte that's not 0xFF, or -1 if none
053     * @return -1 or index of first valid byte
054     */
055    int startIndex() {
056        int len = getNumDataElements();
057        for (int i = 0; i < len; i++) {
058            if ((getElement(i) & 0xFF) != 0xFF) {
059                return i;
060            }
061        }
062        return -1;
063    }
064
065    /**
066     * Translate packet to text
067     */
068    @Override
069    public String toMonitorString() {
070        String test = Constants.toMonitorString(this);
071//        // check for valid length
072//     String val = "???";
073//     int len = getNumDataElements();
074//     boolean goodSync = true;
075//     boolean goodCheckSum = true;
076//     int sum = 0;
077//     String cmd;
078//     String stat;
079//     String hCode;
080//     String bCode;
081//     String dev;
082//        switch (len) {
083//        case 7:
084//         for (int i = 0; i < 6; i++) {
085//          if ((getElement(i) & 0xFF) != 0xFF) {
086//           goodSync = false;
087//          }
088//         }
089//         val = Constants.statusToText(getElement(6));
090//         break;
091//        case 12:
092//         for (int i = 0; i < 6; i++) {
093//          if ((getElement(i) & 0xFF) != 0xFF) {
094//           goodSync = false;
095//          }
096//         }
097//         for (int i = 7; i < 12; i++) {
098//          sum = (sum + (getElement(i) &0xFF)) & 0xFF;
099//         }
100//         stat = Constants.statusToText(getElement(6));
101//         cmd = Constants.commandToText(getElement(7) & 0x0F, -1);
102//         hCode = Constants.houseCodeToText((getElement(7) >> 4) & 0x0F);
103//         dev = Constants.deviceToText(getElement(8), getElement(9));
104//         bCode = Constants.houseCodeToText((getElement(10) >> 4) & 0x0F);
105//         if (sum != (getElement(12) & 0xFF)) {
106//          goodCheckSum = false;
107//         }
108//         val = "Cmd Echo: " + cmd + " stat: " + stat + " House: " + hCode + " Device:" + dev + " base: " + bCode;
109//         if (!goodSync) {
110//          val = val + " BAD SYNC";
111//         }
112//         if (!goodCheckSum) {
113//          val = val + " BAD CHECKSUM: " + (getElement(11) & 0xFF) + " vs " + sum;
114//         }
115//         break;
116//        case 22:
117//         for (int i = 0; i < 16; i++) {
118//          if ((getElement(i) & 0xFF) != 0xFF) {
119//           goodSync = false;
120//          }
121//         }
122//         for (int i = 17; i < 21; i++) {
123//          sum = (sum + (getElement(i) &0xFF)) & 0xFF;
124//         }
125//         cmd = Constants.commandToText((getElement(17) & 0x0F), ((getElement(17) & 0xF0) >> 4));
126//         hCode = Constants.houseCodeToText((getElement(18) >> 4) & 0x0F);
127//         dev = Constants.deviceToText(getElement(19), getElement(20));
128//         if (sum != (getElement(21) & 0xFF)) {
129//          goodCheckSum = false;
130//         }
131//         val = cmd + " House: " + hCode + " Device:" + dev;
132//         if (!goodSync) {
133//          val = val + " BAD SYNC";
134//         }
135//         if (!goodCheckSum) {
136//          val = val + " BAD CHECKSUM: " + (getElement(21) & 0xFF) + " vs " + sum;
137//         }
138//         break;
139//        default:
140//         val = "UNK " + toString();
141//         break;
142//        }
143        return "Send[" + getNumDataElements() + "]: " + test + "\n";
144    }
145
146    int responseLength = -1;  // -1 is an invalid value, indicating it hasn't been set
147
148    @Override
149    public void setResponseLength(int l) {
150        responseLength = l;
151    }
152
153    @Override
154    public int getResponseLength() {
155        return responseLength;
156    }
157
158    // static methods to recognize a message
159    @Override
160    public boolean isPoll() {
161        return getElement(1) == 48;
162    }
163
164    @Override
165    public boolean isXmt() {
166        return getElement(1) == 17;
167    }
168
169    @Override
170    public int getAddr() {
171        return getElement(0);
172    }
173
174    // static methods to return a formatted message
175    static public SerialMessage getPoll(int addr) {
176        // eventually this will have to include logic for reading
177        // various bytes on the card, but our supported
178        // cards don't require that yet
179        // SerialMessage m = new SerialMessage(1);
180        // m.setResponseLength(2);
181        // m.setElement(0, addr);
182        //  m.setTimeout(SHORT_TIMEOUT);    // minumum reasonable timeout
183
184        // Powerline implementation does not currently poll
185        return null;
186    }
187
188    static public SpecificMessage getAddress(int housecode, int devicecode) {
189        SpecificMessage m = new SpecificMessage(2);
190        m.setElement(0, 0x04);
191        m.setElement(1, (X10Sequence.encode(housecode) << 4) + X10Sequence.encode(devicecode));
192        return m;
193    }
194
195    static public SpecificMessage getAddressDim(int housecode, int devicecode, int dimcode) {
196        SpecificMessage m = new SpecificMessage(2);
197        if (dimcode > 0) {
198            m.setElement(0, 0x04 | ((dimcode & 0x1f) << 3));
199        } else {
200            m.setElement(0, 0x04);
201        }
202        m.setElement(1, (X10Sequence.encode(housecode) << 4) + X10Sequence.encode(devicecode));
203        return m;
204    }
205
206    static public SpecificMessage getFunctionDim(int housecode, int function, int dimcode) {
207        SpecificMessage m = new SpecificMessage(2);
208        if (dimcode > 0) {
209            m.setElement(0, 0x06 | ((dimcode & 0x1f) << 3));
210        } else {
211            m.setElement(0, 0x06);
212        }
213        m.setElement(1, (X10Sequence.encode(housecode) << 4) + function);
214        return m;
215    }
216
217    static public SpecificMessage getFunction(int housecode, int function) {
218        SpecificMessage m = new SpecificMessage(2);
219        m.setElement(0, 0x06);
220        m.setElement(1, (X10Sequence.encode(housecode) << 4) + function);
221        return m;
222    }
223}
224
225