001package jmri.jmrix.powerline;
002
003/**
004 * Represent a sequence of one or more Insteon commands (addresses and
005 * functions).
006 * <p>
007 * These are Insteon specific, but not device/interface specific.
008 * <p>
009 * A sequence should consist of addressing (1 or more), and then one or more
010 * commands. It can address multiple devices.
011 *
012 * @author Bob Coleman Copyright (C) 2010
013 * @author Bob Jacobsen Copyright (C) 2008
014 * @author Ken Cameron Copyright (C) 2010
015 */
016public class InsteonSequence {
017
018    // First implementation of this class uses a fixed length
019    // array to hold the sequence; there's a practical limit to how
020    // many Insteon commands anybody would want to send at once!
021    private static final int MAXINDEX = 32;
022    int index = 0;
023    Command[] cmds = new Command[MAXINDEX];  // doesn't scale, but that's for another day
024
025    /**
026     * Append a new "do function" operation to the sequence
027     * @param idhighbyte   1st id value
028     * @param idmiddlebyte 2nd id value
029     * @param idlowbyte    3rd id value
030     * @param function     function
031     * @param flag         option flag
032     * @param command1     cmd1
033     * @param command2     cmd2
034     */
035    public void addFunction(int idhighbyte, int idmiddlebyte, int idlowbyte, int function, int flag, int command1, int command2) {
036        if (index >= MAXINDEX) {
037            throw new IllegalArgumentException("Sequence too long");
038        }
039        cmds[index] = new Function(idhighbyte, idmiddlebyte, idlowbyte, function, flag, command1, command2);
040        index++;
041    }
042
043    /**
044     * Append a new "set address" operation to the sequence
045     * @param idhighbyte   1st addr 
046     * @param idmiddlebyte 2nd addr
047     * @param idlowbyte    3rd addr
048     */
049    public void addAddress(int idhighbyte, int idmiddlebyte, int idlowbyte) {
050        if (index >= MAXINDEX) {
051            throw new IllegalArgumentException("Sequence too long");
052        }
053        cmds[index] = new Address(idhighbyte, idmiddlebyte, idlowbyte);
054        index++;
055    }
056
057    /**
058     * Next getCommand will be the first in the sequence
059     */
060    public void reset() {
061        index = 0;
062    }
063
064    /**
065     * Retrieve the next command in the sequence
066     * @return single Insteon cmd
067     */
068    public Command getCommand() {
069        return cmds[index++];
070    }
071
072    /**
073     * Represent a single Insteon command, which is either a "set address" or
074     * "do function" operation
075     */
076    public interface Command {
077
078        public boolean isAddress();
079
080        public boolean isFunction();
081
082        public int getAddressHigh();
083
084        public int getAddressMiddle();
085
086        public int getAddressLow();
087    }
088
089    /**
090     * Represent a single "set address" Insteon command
091     */
092    public static class Address implements Command {
093
094        public Address(int idhighbyte, int idmiddlebyte, int idlowbyte) {
095            this.idhighbyte = idhighbyte;
096            this.idmiddlebyte = idmiddlebyte;
097            this.idlowbyte = idlowbyte;
098        }
099        int idhighbyte;
100        int idmiddlebyte;
101        int idlowbyte;
102
103        @Override
104        public int getAddressHigh() {
105            return idhighbyte;
106        }
107
108        @Override
109        public int getAddressMiddle() {
110            return idmiddlebyte;
111        }
112
113        @Override
114        public int getAddressLow() {
115            return idlowbyte;
116        }
117
118        @Override
119        public boolean isAddress() {
120            return true;
121        }
122
123        @Override
124        public boolean isFunction() {
125            return false;
126        }
127    }
128
129    /**
130     * Represent a single "do function" Insteon command
131     */
132    public static class Function implements Command {
133
134        public Function(int idhighbyte, int idmiddlebyte, int idlowbyte, int function, int flag, int command1, int command2) {
135            this.idhighbyte = idhighbyte;
136            this.idmiddlebyte = idmiddlebyte;
137            this.idlowbyte = idlowbyte;
138            this.function = function;
139            this.flag = flag;
140            this.command1 = command1;
141            this.command2 = command2;
142        }
143        int idhighbyte;
144        int idmiddlebyte;
145        int idlowbyte;
146        int function;
147        int flag;
148        int command1;
149        int command2;
150
151        @Override
152        public int getAddressHigh() {
153            return idhighbyte;
154        }
155
156        @Override
157        public int getAddressMiddle() {
158            return idmiddlebyte;
159        }
160
161        @Override
162        public int getAddressLow() {
163            return idlowbyte;
164        }
165
166        public int getFunction() {
167            return function;
168        }
169
170        public int getFlag() {
171            return flag;
172        }
173
174        public int getCommand1() {
175            return command1;
176        }
177
178        public int getCommand2() {
179            return command2;
180        }
181
182        @Override
183        public boolean isAddress() {
184            return false;
185        }
186
187        @Override
188        public boolean isFunction() {
189            return true;
190        }
191    }
192
193    /**
194     * Represent a single "Extended Data" Insteon command
195     */
196    public static class ExtData implements Command {
197
198        public ExtData(int value) {
199            this.value = value;
200            this.idhighbyte = -1;
201            this.idmiddlebyte = -1;
202            this.idlowbyte = -1;
203        }
204        int idhighbyte;
205        int idmiddlebyte;
206        int idlowbyte;
207        int value;
208
209        @Override
210        public int getAddressHigh() {
211            return idhighbyte;
212        }
213
214        @Override
215        public int getAddressMiddle() {
216            return idmiddlebyte;
217        }
218
219        @Override
220        public int getAddressLow() {
221            return idlowbyte;
222        }
223
224        public int getExtData() {
225            return value;
226        }
227
228        @Override
229        public boolean isAddress() {
230            return false;
231        }
232
233        @Override
234        public boolean isFunction() {
235            return false;
236        }
237    }
238
239    /**
240     * Return a human-readable name for a function code
241     * @param i function value
242     * @return  text of the fuction
243     */
244    public static String functionName(int i) {
245        return X10Sequence.functionName(i);
246    }
247
248    /**
249     * For the house (A-P) and device (1-16) codes, get the line-coded value.
250     * Argument is from 1 to 16 only.
251     * @param i code to convert
252     * @return  converted code
253     */
254    public static int encode(int i) {
255        return X10Sequence.encode(i);
256    }
257
258    /**
259     * Get house (A-P as 1-16) or device (1-16) from line-coded value.
260     * @param i encoded value
261     * @return  int value
262     */
263    public static int decode(int i) {
264        return X10Sequence.decode(i);
265    }
266
267    /**
268     * Pretty-print an address code
269     * @param b address as value
270     * @return  text of address explained
271     */
272    public static String formatAddressByte(int b) {
273        return "House " + X10Sequence.houseValueToText(X10Sequence.decode((b >> 4) & 0x0F))
274                + " address device " + X10Sequence.decode(b & 0x0f);
275    }
276
277    /**
278     * Pretty-print a function code
279     * @param b function code value
280     * @return  text of function code
281     */
282    public static String formatCommandByte(int b) {
283        return "House " + X10Sequence.houseValueToText(X10Sequence.decode((b >> 4) & 0x0F))
284                + " function: " + X10Sequence.functionName(b & 0x0f);
285    }
286
287    /**
288     * Translate House Value (1 to 16) to text
289     * @param hV value for housecode
290     * @return   text for housecode
291     */
292    public static String houseValueToText(int hV) {
293        if (hV >= 1 && hV <= 16) {
294            return X10Sequence.houseValueToText(hV);
295        } else {
296            return "??";
297        }
298    }
299
300    /**
301     * Translate House Code to text
302     * @param hC housecode value
303     * @return   text for the housecode
304     */
305    public static String houseCodeToText(int hC) {
306        return X10Sequence.houseCodeToText(hC);
307    }
308
309}