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