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    @Deprecated( since="5.13.5", forRemoval=true) // deprecated super
048    public SpecificMessage(byte[] a, int l) {
049        super(a, l);
050    }
051
052    /**
053     * Find 1st byte that's not 0xFF, or -1 if none
054     * @return -1 or index of first valid byte
055     */
056    int startIndex() {
057        int len = getNumDataElements();
058        for (int i = 0; i < len; i++) {
059            if ((getElement(i) & 0xFF) != 0xFF) {
060                return i;
061            }
062        }
063        return -1;
064    }
065
066    /**
067     * Translate packet to text
068     */
069    @Override
070    public String toMonitorString() {
071        String test = Constants.toMonitorString(this);
072//        // check for valid length
073//     String val = "???";
074//     int len = getNumDataElements();
075//     boolean goodSync = true;
076//     boolean goodCheckSum = true;
077//     int sum = 0;
078//     String cmd;
079//     String stat;
080//     String hCode;
081//     String bCode;
082//     String dev;
083//        switch (len) {
084//        case 7:
085//         for (int i = 0; i < 6; i++) {
086//          if ((getElement(i) & 0xFF) != 0xFF) {
087//           goodSync = false;
088//          }
089//         }
090//         val = Constants.statusToText(getElement(6));
091//         break;
092//        case 12:
093//         for (int i = 0; i < 6; i++) {
094//          if ((getElement(i) & 0xFF) != 0xFF) {
095//           goodSync = false;
096//          }
097//         }
098//         for (int i = 7; i < 12; i++) {
099//          sum = (sum + (getElement(i) &0xFF)) & 0xFF;
100//         }
101//         stat = Constants.statusToText(getElement(6));
102//         cmd = Constants.commandToText(getElement(7) & 0x0F, -1);
103//         hCode = Constants.houseCodeToText((getElement(7) >> 4) & 0x0F);
104//         dev = Constants.deviceToText(getElement(8), getElement(9));
105//         bCode = Constants.houseCodeToText((getElement(10) >> 4) & 0x0F);
106//         if (sum != (getElement(12) & 0xFF)) {
107//          goodCheckSum = false;
108//         }
109//         val = "Cmd Echo: " + cmd + " stat: " + stat + " House: " + hCode + " Device:" + dev + " base: " + bCode;
110//         if (!goodSync) {
111//          val = val + " BAD SYNC";
112//         }
113//         if (!goodCheckSum) {
114//          val = val + " BAD CHECKSUM: " + (getElement(11) & 0xFF) + " vs " + sum;
115//         }
116//         break;
117//        case 22:
118//         for (int i = 0; i < 16; i++) {
119//          if ((getElement(i) & 0xFF) != 0xFF) {
120//           goodSync = false;
121//          }
122//         }
123//         for (int i = 17; i < 21; i++) {
124//          sum = (sum + (getElement(i) &0xFF)) & 0xFF;
125//         }
126//         cmd = Constants.commandToText((getElement(17) & 0x0F), ((getElement(17) & 0xF0) >> 4));
127//         hCode = Constants.houseCodeToText((getElement(18) >> 4) & 0x0F);
128//         dev = Constants.deviceToText(getElement(19), getElement(20));
129//         if (sum != (getElement(21) & 0xFF)) {
130//          goodCheckSum = false;
131//         }
132//         val = cmd + " House: " + hCode + " Device:" + dev;
133//         if (!goodSync) {
134//          val = val + " BAD SYNC";
135//         }
136//         if (!goodCheckSum) {
137//          val = val + " BAD CHECKSUM: " + (getElement(21) & 0xFF) + " vs " + sum;
138//         }
139//         break;
140//        default:
141//         val = "UNK " + toString();
142//         break;
143//        }
144        return "Send[" + getNumDataElements() + "]: " + test + "\n";
145    }
146
147    int responseLength = -1;  // -1 is an invalid value, indicating it hasn't been set
148
149    @Override
150    public void setResponseLength(int l) {
151        responseLength = l;
152    }
153
154    @Override
155    public int getResponseLength() {
156        return responseLength;
157    }
158
159    // static methods to recognize a message
160    @Override
161    public boolean isPoll() {
162        return getElement(1) == 48;
163    }
164
165    @Override
166    public boolean isXmt() {
167        return getElement(1) == 17;
168    }
169
170    @Override
171    public int getAddr() {
172        return getElement(0);
173    }
174
175    // static methods to return a formatted message
176    static public SerialMessage getPoll(int addr) {
177        // eventually this will have to include logic for reading
178        // various bytes on the card, but our supported
179        // cards don't require that yet
180        // SerialMessage m = new SerialMessage(1);
181        // m.setResponseLength(2);
182        // m.setElement(0, addr);
183        //  m.setTimeout(SHORT_TIMEOUT);    // minumum reasonable timeout
184
185        // Powerline implementation does not currently poll
186        return null;
187    }
188
189    static public SpecificMessage getAddress(int housecode, int devicecode) {
190        SpecificMessage m = new SpecificMessage(2);
191        m.setElement(0, 0x04);
192        m.setElement(1, (X10Sequence.encode(housecode) << 4) + X10Sequence.encode(devicecode));
193        return m;
194    }
195
196    static public SpecificMessage getAddressDim(int housecode, int devicecode, int dimcode) {
197        SpecificMessage m = new SpecificMessage(2);
198        if (dimcode > 0) {
199            m.setElement(0, 0x04 | ((dimcode & 0x1f) << 3));
200        } else {
201            m.setElement(0, 0x04);
202        }
203        m.setElement(1, (X10Sequence.encode(housecode) << 4) + X10Sequence.encode(devicecode));
204        return m;
205    }
206
207    static public SpecificMessage getFunctionDim(int housecode, int function, int dimcode) {
208        SpecificMessage m = new SpecificMessage(2);
209        if (dimcode > 0) {
210            m.setElement(0, 0x06 | ((dimcode & 0x1f) << 3));
211        } else {
212            m.setElement(0, 0x06);
213        }
214        m.setElement(1, (X10Sequence.encode(housecode) << 4) + function);
215        return m;
216    }
217
218    static public SpecificMessage getFunction(int housecode, int function) {
219        SpecificMessage m = new SpecificMessage(2);
220        m.setElement(0, 0x06);
221        m.setElement(1, (X10Sequence.encode(housecode) << 4) + function);
222        return m;
223    }
224}
225
226