]> git.basschouten.com Git - openhab-addons.git/blob
abe2b735effecf250dab3d06f1c81d0b3732cd20
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.milight.internal.protocol;
14
15 import java.net.DatagramPacket;
16 import java.net.DatagramSocket;
17 import java.net.InetAddress;
18
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21
22 /**
23  * A queue item meant to be used for {@link QueuedSend}.
24  *
25  * @author David Graeff - Initial contribution
26  */
27 @NonNullByDefault
28 public class QueueItem {
29     protected final int uniqueCommandId;
30     protected final boolean repeatable;
31     protected final int delayTime;
32     protected final int repeatCommands;
33     protected final DatagramPacket packet;
34     private boolean invalid = false;
35
36     final DatagramSocket socket;
37     private final QueueItem root;
38     private @Nullable QueueItem last;
39     public @Nullable QueueItem next;
40
41     /**
42      * Add data to the send queue.
43      * Commands which need to be queued up and not replacing same type commands must be non-categorised.
44      * Items can be repeatable, in the sense that they do not cause side effects if they are send multiple times
45      * (e.g. absolute values).
46      *
47      * @param socket A socket
48      * @param uniqueCommandId A unique command id. A later command with the same id as previous ones will
49      *            overwrite those. 0 means a non categorised entry.
50      * @param data Data to be send
51      * @param repeatable A repeatable command should not cause side effects by sending it multiple times.
52      * @param delayTime A delay time that is used instead of the default delay time between commands for all
53      *            added byte sequences.
54      */
55     public QueueItem(DatagramSocket socket, int uniqueCommandId, byte[] data, boolean repeatable, int delayTime,
56             int repeatCommands, InetAddress address, int port) {
57         this.socket = socket;
58         this.uniqueCommandId = uniqueCommandId;
59         this.repeatable = repeatable;
60         this.delayTime = delayTime;
61         this.repeatCommands = repeatCommands;
62         this.root = this;
63         this.packet = new DatagramPacket(data, data.length, address, port);
64     }
65
66     /**
67      * @see #QueueItem(int, byte[], boolean, int)
68      * @param uniqueCommandId A unique command id. A later command with the same id as previous ones will
69      *            overwrite those. 0 means a non categorised entry.
70      * @param data Data to be send
71      * @param repeatable A repeatable command should not cause side effects by sending it multiple times.
72      * @param customDelayTime A delay time that is used instead of the default delay time between commands for all
73      *            added byte sequences.
74      * @param root Another item is the root entry for this one.
75      */
76     private QueueItem(DatagramSocket socket, int uniqueCommandId, byte[] data, boolean repeatable, int customDelayTime,
77             int repeatCommands, InetAddress address, int port, QueueItem root) {
78         this.socket = socket;
79         this.uniqueCommandId = uniqueCommandId;
80         this.repeatable = repeatable;
81         this.delayTime = customDelayTime;
82         this.repeatCommands = repeatCommands;
83         this.root = root;
84         this.packet = new DatagramPacket(data, data.length, address, port);
85     }
86
87     /**
88      * Add non-categorised, repeatable data to the send queue.
89      *
90      * <p>
91      * Commands which need to be queued up and not replacing same type commands must use this method.
92      * Items added to the queue are considered not repeatable (suited for relative commands where a repetition would
93      * cause a change of value).
94      * </p>
95      *
96      * <p>
97      * If you want to, you can add multiple byte sequences to the queue, even if they have the same id.
98      * This is used for animations and multi-message commands. Be aware that a later added command with the
99      * same id will replace all those commands at once.
100      * </p>
101      *
102      * @param data Data to be send
103      */
104     public static QueueItem createRepeatable(DatagramSocket socket, int customDelayTime, int repeatCommands,
105             InetAddress address, int port, byte[]... data) {
106         QueueItem item = new QueueItem(socket, QueuedSend.NO_CATEGORY, data[0], true, customDelayTime, repeatCommands,
107                 address, port);
108
109         QueueItem next = item;
110         for (int i = 1; i < data.length; ++i) {
111             next = next.addRepeatable(data[i]);
112         }
113         return item;
114     }
115
116     /**
117      * Add non-categorised, non-repeatable data to the send queue.
118      *
119      * <p>
120      * Commands which need to be queued up and not replacing same type commands must use this method.
121      * Items added to the queue are considered not repeatable (suited for relative commands where a repetition would
122      * cause a change of value).
123      * </p>
124      *
125      * <p>
126      * If you want to, you can add multiple byte sequences to the queue, even if they have the same id.
127      * This is used for animations and multi-message commands. Be aware that a later added command with the
128      * same id will replace all those commands at once.
129      * </p>
130      *
131      * @param data Data to be send
132      */
133     public static QueueItem createNonRepeatable(DatagramSocket socket, int customDelayTime, InetAddress address,
134             int port, byte[]... data) {
135         QueueItem item = new QueueItem(socket, QueuedSend.NO_CATEGORY, data[0], false, customDelayTime, 1, address,
136                 port);
137
138         QueueItem next = item;
139         for (int i = 1; i < data.length; ++i) {
140             next = next.addRepeatable(data[i]);
141         }
142         return item;
143     }
144
145     private QueueItem createNewItem(byte[] data, boolean repeatable) {
146         QueueItem newItem = new QueueItem(socket, uniqueCommandId, data, repeatable, delayTime, repeatCommands,
147                 packet.getAddress(), packet.getPort(), root);
148
149         // The the next pointer of the last element in the chain to the new item
150         QueueItem lastInChain = root.last != null ? root.last : root;
151         lastInChain.next = newItem;
152
153         return newItem;
154     }
155
156     /**
157      * Add a command to the command chain. Can be called on any of the
158      * commands in the chain, but will overwrite the next command in chain.
159      *
160      * This method can be used in a cascading way like:
161      * QueueItem item ...;
162      * send(item.addNonRepeatable(...).addNonRepeatable(...))
163      *
164      *
165      * @param data Add data to the chain of commands
166      * @return Always return the root command
167      */
168     public QueueItem addNonRepeatable(byte[] data) {
169         root.last = createNewItem(data, false);
170         return this.root;
171     }
172
173     /**
174      * Add a command to the command chain. Can be called on any of the
175      * commands in the chain, but will overwrite the next command in chain.
176      *
177      * This method can be used in a cascading way like:
178      * QueueItem item ...;
179      * send(item.addRepeatable(...).addRepeatable(...))
180      *
181      *
182      * @param data Add data to the chain of commands
183      * @return Always return the root command
184      */
185     public QueueItem addRepeatable(byte[] data) {
186         root.last = createNewItem(data, true);
187         return this.root;
188     }
189
190     public boolean isInvalid() {
191         return invalid;
192     }
193
194     public void makeInvalid() {
195         this.invalid = true;
196     }
197 }