021e749beef220623750705b128a8a7ea81f7c2a
[iot2.git] / benchmarks / drivers / LifxLightBulb / LifxLightBulb.java
1 package iotcode.LifxLightBulb;
2
3 // Standard Java Packages
4 import java.io.*;
5 import java.net.*;
6 import java.util.concurrent.Semaphore;
7 import java.security.InvalidParameterException;
8 import java.util.Date;
9 import java.util.Iterator;
10 import java.util.concurrent.atomic.AtomicBoolean;
11
12
13 // IoT Packages
14 //import iotcode.annotation.*;
15 import iotcode.interfaces.LightBulb;
16 import iotruntime.IoTUDP;
17 import iotruntime.slave.IoTDeviceAddress;
18 import iotruntime.slave.IoTSet;
19
20 // String to byte conversion
21 import javax.xml.bind.DatatypeConverter;
22
23 import iotchecker.qual.*;
24
25 public class LifxLightBulb implements LightBulb {
26
27         /*******************************************************************************************************************************************
28         **
29         **  Constants
30         **
31         *******************************************************************************************************************************************/
32         public static final long GET_BULB_VERSION_RESEND_WAIT_SECONDS = 10;
33
34
35
36         /*******************************************************************************************************************************************
37         **
38         **  Variables
39         **
40         *******************************************************************************************************************************************/
41         private IoTUDP communicationSockect;
42         private byte[] bulbMacAddress = new byte[8];
43         static Semaphore socketMutex = new Semaphore(1);
44         static boolean sendSocketFlag = false;
45         private long lastSentGetBulbVersionRequest = 0;                                                                                                                                                                                                                                                         // time last request sent
46
47         // Current Bulb Values
48         private int currentHue = 0;
49         private int currentSaturation = 0;
50         private int currentBrightness = 65535;
51         private int currentTemperature = 9000;
52         private boolean bulbIsOn = false;
53
54
55
56         private AtomicBoolean didAlreadyInit = new AtomicBoolean(false);
57
58         private AtomicBoolean didGetBulbVersion = new AtomicBoolean(false);
59         static Semaphore settingBulbColorMutex = new Semaphore(1);
60         static Semaphore settingBulbTempuraturerMutex = new Semaphore(1);
61         static Semaphore bulbStateMutex = new Semaphore(1);
62
63         // color and temperature ranges for the bulbs
64         private int hueLowerBound = 0;
65         private int hueUpperBound = 0;
66         private int saturationLowerBound = 0;
67         private int saturationUpperBound = 0;
68         private int brightnessLowerBound = 0;
69         private int brightnessUpperBound = 0;
70         private int temperatureLowerBound = 2500;
71         private int temperatureUpperBound = 9000;
72
73
74
75         // Check if a state change was requested, used to poll the bulb for if the bulb did
76         // preform the requested state change
77         private boolean stateDidChange = false;
78
79         /*******************************************************************************************************************************************
80         **
81         **  Threads
82         **
83         *******************************************************************************************************************************************/
84
85         // Main worker thread will do the receive loop
86         Thread workerThread = null;
87
88         /*******************************************************************************************************************************************
89         **
90         **  IoT Sets and Relations
91         **
92         *******************************************************************************************************************************************/
93
94         // IoTSet of Device Addresses.
95         // Will be filled with only 1 address.
96         @config private IoTSet<IoTDeviceAddress> lb_addresses;
97
98         /**
99          * Used for testing only
100          */
101         public LifxLightBulb(IoTUDP udp, byte[] macAddress) {
102                 communicationSockect = udp;
103                 bulbMacAddress = macAddress;
104         }
105
106         public LifxLightBulb(String macAddress) {
107                 communicationSockect = null;
108
109                 // Set the Mac Address to a default value
110                 // Probably not needed for anything
111                 /*bulbMacAdd[0] = (byte)0x00;
112                    bulbMacAdd[1] = (byte)0x00;
113                    bulbMacAdd[2] = (byte)0x00;
114                    bulbMacAdd[3] = (byte)0x00;
115                    bulbMacAdd[4] = (byte)0x00;
116                    bulbMacAdd[5] = (byte)0x00;
117                    bulbMacAdd[6] = (byte)0x00;
118                    bulbMacAdd[7] = (byte)0x00;*/
119
120                 bulbMacAddress = DatatypeConverter.parseHexBinary(macAddress);
121         }
122
123
124
125         /*******************************************************************************************************************************************
126         **  Sending
127         **  Device Messages
128         **
129         *******************************************************************************************************************************************/
130         private void sendGetServicePacket() {
131                 LifxHeader header = new LifxHeader();
132                 header.setSize(36);
133                 header.setTagged(true);
134                 header.setMacAddress(bulbMacAddress);
135                 header.setSource(0);                                                                                                                                                                                                                                                                                                                                                                                                                            // randomly picked
136                 header.setAck_required(false);
137                 header.setRes_required(false);
138                 header.setSequence(0);
139                 header.setType(2);
140
141                 byte[] dataBytes = header.getHeaderBytes();
142                 sendPacket(dataBytes);
143         }
144
145         private void sendGetHostInfoPacket() {
146                 LifxHeader header = new LifxHeader();
147                 header.setSize(36);
148                 header.setTagged(false);
149                 header.setMacAddress(bulbMacAddress);
150                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
151                 header.setAck_required(false);
152                 header.setRes_required(false);
153                 header.setSequence(0);
154                 header.setType(12);
155
156                 byte[] dataBytes = header.getHeaderBytes();
157                 sendPacket(dataBytes);
158         }
159
160         private void sendGetHostFirmwarePacket() {
161                 LifxHeader header = new LifxHeader();
162                 header.setSize(36);
163                 header.setTagged(false);
164                 header.setMacAddress(bulbMacAddress);
165                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
166                 header.setAck_required(false);
167                 header.setRes_required(false);
168                 header.setSequence(0);
169                 header.setType(14);
170
171                 byte[] dataBytes = header.getHeaderBytes();
172                 sendPacket(dataBytes);
173         }
174
175         private void sendGetWifiInfoPacket() {
176                 LifxHeader header = new LifxHeader();
177                 header.setSize(36);
178                 header.setTagged(false);
179                 header.setMacAddress(bulbMacAddress);
180                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
181                 header.setAck_required(false);
182                 header.setRes_required(false);
183                 header.setSequence(0);
184                 header.setType(16);
185
186                 byte[] dataBytes = header.getHeaderBytes();
187                 sendPacket(dataBytes);
188         }
189
190         private void sendGetWifiFirmwarePacket() {
191                 LifxHeader header = new LifxHeader();
192                 header.setSize(36);
193                 header.setTagged(false);
194                 header.setMacAddress(bulbMacAddress);
195                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
196                 header.setAck_required(false);
197                 header.setRes_required(false);
198                 header.setSequence(0);
199                 header.setType(18);
200
201                 byte[] dataBytes = header.getHeaderBytes();
202                 sendPacket(dataBytes);
203         }
204
205         private void sendGetPowerPacket() {
206                 LifxHeader header = new LifxHeader();
207                 header.setSize(36);
208                 header.setTagged(false);
209                 header.setMacAddress(bulbMacAddress);
210                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
211                 header.setAck_required(false);
212                 header.setRes_required(false);
213                 header.setSequence(0);
214                 header.setType(20);
215
216                 byte[] dataBytes = header.getHeaderBytes();
217                 sendPacket(dataBytes);
218         }
219
220         private void sendSetPowerPacket(int level) {
221                 // Currently only 0 and 65535 are supported
222                 // This is a fix for now
223                 if ((level != 65535) && (level != 0)) {
224                         throw new InvalidParameterException("Invalid parameter values");
225                 }
226
227                 if ((level > 65535) || (level < 0)) {
228                         throw new InvalidParameterException("Invalid parameter values");
229                 }
230
231                 byte[] packetBytes = new byte[38];
232
233                 LifxHeader header = new LifxHeader();
234                 header.setSize(38);
235                 header.setTagged(false);
236                 header.setMacAddress(bulbMacAddress);
237                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
238                 header.setAck_required(false);
239                 header.setRes_required(false);
240                 header.setSequence(0);
241                 header.setType(21);
242                 byte[] headerBytes = header.getHeaderBytes();
243
244                 for (int i = 0; i < 36; i++) {
245                         packetBytes[i] = headerBytes[i];
246                 }
247
248                 packetBytes[36] = (byte)(level & 0xFF);
249                 packetBytes[37] = (byte)((level >> 8) & 0xFF);
250
251                 sendPacket(packetBytes);
252         }
253
254         private void sendGetLabelPacket() {
255                 LifxHeader header = new LifxHeader();
256                 header.setSize(36);
257                 header.setTagged(false);
258                 header.setMacAddress(bulbMacAddress);
259                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
260                 header.setAck_required(false);
261                 header.setRes_required(false);
262                 header.setSequence(0);
263                 header.setType(23);
264
265                 byte[] dataBytes = header.getHeaderBytes();
266                 sendPacket(dataBytes);
267         }
268
269         private void sendSetLabelPacket(String label) {
270                 // Currently only 0 and 65535 are supported
271                 // This is a fix for now
272                 if (label.length() != 32) {
273                         throw new InvalidParameterException("Invalid parameter values, label must be 32 bytes long");
274                 }
275
276                 byte[] packetBytes = new byte[68];
277
278                 LifxHeader header = new LifxHeader();
279                 header.setSize(68);
280                 header.setTagged(false);
281                 header.setMacAddress(bulbMacAddress);
282                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
283                 header.setAck_required(false);
284                 header.setRes_required(false);
285                 header.setSequence(0);
286                 header.setType(24);
287                 byte[] headerBytes = header.getHeaderBytes();
288
289                 for (int i = 0; i < 36; i++) {
290                         packetBytes[i] = headerBytes[i];
291                 }
292
293                 for (int i = 0; i < 32; i++) {
294                         packetBytes[i + 36] = label.getBytes()[i];
295                 }
296
297                 sendPacket(packetBytes);
298         }
299
300         private void sendGetVersionPacket() {
301                 LifxHeader header = new LifxHeader();
302                 header.setSize(36);
303                 header.setTagged(false);
304                 header.setMacAddress(bulbMacAddress);
305                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
306                 header.setAck_required(false);
307                 header.setRes_required(false);
308                 header.setSequence(0);
309                 header.setType(32);
310
311                 byte[] dataBytes = header.getHeaderBytes();
312                 sendPacket(dataBytes);
313         }
314
315         private void sendGetInfoPacket() {
316                 LifxHeader header = new LifxHeader();
317                 header.setSize(36);
318                 header.setTagged(false);
319                 header.setMacAddress(bulbMacAddress);
320                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
321                 header.setAck_required(false);
322                 header.setRes_required(false);
323                 header.setSequence(0);
324                 header.setType(34);
325
326                 byte[] dataBytes = header.getHeaderBytes();
327                 sendPacket(dataBytes);
328         }
329
330         private void sendGetLocationPacket() {
331                 LifxHeader header = new LifxHeader();
332                 header.setSize(36);
333                 header.setTagged(false);
334                 header.setMacAddress(bulbMacAddress);
335                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
336                 header.setAck_required(false);
337                 header.setRes_required(false);
338                 header.setSequence(0);
339                 header.setType(34);
340
341                 byte[] dataBytes = header.getHeaderBytes();
342                 sendPacket(dataBytes);
343         }
344
345         private void sendGetGroupPacket() {
346                 LifxHeader header = new LifxHeader();
347                 header.setSize(36);
348                 header.setTagged(false);
349                 header.setMacAddress(bulbMacAddress);
350                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
351                 header.setAck_required(false);
352                 header.setRes_required(false);
353                 header.setSequence(0);
354                 header.setType(51);
355
356                 byte[] dataBytes = header.getHeaderBytes();
357                 sendPacket(dataBytes);
358         }
359
360
361         /*******************************************************************************************************************************************
362         **  Sending
363         **  Light Messages
364         **
365         *******************************************************************************************************************************************/
366         private void sendGetLightStatePacket() {
367                 LifxHeader header = new LifxHeader();
368                 header.setSize(36);
369                 header.setTagged(false);
370                 header.setMacAddress(bulbMacAddress);
371                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
372                 header.setAck_required(false);
373                 header.setRes_required(false);
374                 header.setSequence(0);
375                 header.setType(101);
376
377                 byte[] dataBytes = header.getHeaderBytes();
378                 sendPacket(dataBytes);
379         }
380
381         private void sendSetLightColorPacket(BulbColor bulbColor, long duration) {
382
383                 if ((duration > 4294967295l) || (duration < 0)) {
384                         throw new InvalidParameterException("Invalid parameter value, duration out of range (0 - 4294967295)");
385                 }
386
387                 byte[] packetBytes = new byte[49];
388
389                 LifxHeader header = new LifxHeader();
390                 header.setSize(49);
391                 header.setTagged(false);
392                 header.setMacAddress(bulbMacAddress);
393                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
394                 header.setAck_required(false);
395                 header.setRes_required(false);
396                 header.setSequence(0);
397                 header.setType(102);
398                 byte[] headerBytes = header.getHeaderBytes();
399
400                 for (int i = 0; i < 36; i++) {
401                         packetBytes[i] = headerBytes[i];
402                 }
403
404                 // 1 reserved packet
405                 packetBytes[37] = (byte)(bulbColor.getHue() & 0xFF);
406                 packetBytes[38] = (byte)((bulbColor.getHue() >> 8) & 0xFF);
407
408                 packetBytes[39] = (byte)(bulbColor.getSaturation() & 0xFF);
409                 packetBytes[40] = (byte)((bulbColor.getSaturation() >> 8) & 0xFF);
410
411                 packetBytes[41] = (byte)(bulbColor.getBrightness() & 0xFF);
412                 packetBytes[42] = (byte)((bulbColor.getBrightness() >> 8) & 0xFF);
413
414                 packetBytes[43] = (byte)(bulbColor.getKelvin() & 0xFF);
415                 packetBytes[44] = (byte)((bulbColor.getKelvin() >> 8) & 0xFF);
416
417                 packetBytes[45] = (byte)((duration >> 0) & 0xFF);
418                 packetBytes[46] = (byte)((duration >> 8) & 0xFF);
419                 packetBytes[47] = (byte)((duration >> 16) & 0xFF);
420                 packetBytes[48] = (byte)((duration >> 24) & 0xFF);
421
422                 sendPacket(packetBytes);
423         }
424
425         private void sendGetLightPowerPacket() {
426                 LifxHeader header = new LifxHeader();
427                 header.setSize(36);
428                 header.setTagged(false);
429                 header.setMacAddress(bulbMacAddress);
430                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
431                 header.setAck_required(false);
432                 header.setRes_required(false);
433                 header.setSequence(0);
434                 header.setType(116);
435
436                 byte[] dataBytes = header.getHeaderBytes();
437                 sendPacket(dataBytes);
438         }
439
440         private void sendSetLightPowerPacket(int level, long duration) {
441
442                 if ((level > 65535) || (duration > 4294967295l)
443                         || (level < 0) || (duration < 0)) {
444                         throw new InvalidParameterException("Invalid parameter values");
445                 }
446
447                 byte[] packetBytes = new byte[42];
448
449
450                 LifxHeader header = new LifxHeader();
451                 header.setSize(42);
452                 header.setTagged(false);
453                 header.setMacAddress(bulbMacAddress);
454                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
455                 header.setAck_required(false);
456                 header.setRes_required(false);
457                 header.setSequence(0);
458                 header.setType(117);
459                 byte[] headerBytes = header.getHeaderBytes();
460
461                 for (int i = 0; i < 36; i++) {
462                         packetBytes[i] = headerBytes[i];
463                 }
464
465                 packetBytes[36] = (byte)(level & 0xFF);
466                 packetBytes[37] = (byte)((level >> 8) & 0xFF);
467
468                 packetBytes[38] = (byte)((duration >> 0) & 0xFF);
469                 packetBytes[39] = (byte)((duration >> 8) & 0xFF);
470                 packetBytes[40] = (byte)((duration >> 16) & 0xFF);
471                 packetBytes[41] = (byte)((duration >> 24) & 0xFF);
472
473                 sendPacket(packetBytes);
474         }
475
476         private void sendEchoRequestPacket(byte[] data) {
477                 // Currently only 0 and 65535 are supported
478                 // This is a fix for now
479                 if (data.length != 64) {
480                         throw new InvalidParameterException("Invalid parameter values, must have 64 bytes");
481                 }
482
483                 byte[] packetBytes = new byte[100];
484
485                 LifxHeader header = new LifxHeader();
486                 header.setSize(100);
487                 header.setTagged(false);
488                 header.setMacAddress(bulbMacAddress);
489                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
490                 header.setAck_required(false);
491                 header.setRes_required(false);
492                 header.setSequence(0);
493                 header.setType(58);
494                 byte[] headerBytes = header.getHeaderBytes();
495
496                 for (int i = 0; i < 36; i++) {
497                         packetBytes[i] = headerBytes[i];
498                 }
499
500                 for (int i = 0; i < 64; i++) {
501                         packetBytes[i + 36] = data[i];
502                 }
503
504                 sendPacket(packetBytes);
505         }
506
507
508         /*******************************************************************************************************************************************
509         **  Receiving
510         **  Device Messages
511         **
512         *******************************************************************************************************************************************/
513         private DeviceStateService parseDeviceStateServiceMessage(LifxHeader header, byte[] payloadData) {
514                 int service = payloadData[0];
515                 long port = ((payloadData[3] & 0xFF) << 24);
516                 port |= ((payloadData[2] & 0xFF) << 16);
517                 port |= ((payloadData[1] & 0xFF) << 8);
518                 port |= (payloadData[0] & 0xFF);
519
520                 return new DeviceStateService(service, port);
521         }
522
523         private DeviceStateHostInfo parseDeviceStateHostInfoMessage(LifxHeader header, byte[] payloadData) {
524                 long signal = ((payloadData[3] & 0xFF) << 24);
525                 signal |= ((payloadData[2] & 0xFF) << 16);
526                 signal |= ((payloadData[1] & 0xFF) << 8);
527                 signal |= (payloadData[0] & 0xFF);
528
529                 long tx = ((payloadData[7] & 0xFF) << 24);
530                 tx |= ((payloadData[6] & 0xFF) << 16);
531                 tx |= ((payloadData[5] & 0xFF) << 8);
532                 tx |= (payloadData[4] & 0xFF);
533
534                 long rx = ((payloadData[11] & 0xFF) << 24);
535                 rx |= ((payloadData[10] & 0xFF) << 16);
536                 rx |= ((payloadData[9] & 0xFF) << 8);
537                 rx |= (payloadData[8] & 0xFF);
538
539                 return new DeviceStateHostInfo(signal, tx, rx);
540         }
541
542         private DeviceStateHostFirmware parseDeviceStateHostFirmwareMessage(LifxHeader header, byte[] payloadData) {
543                 long build = 0;
544                 for (int i = 0; i < 8; i++) {
545                         build += ((long) payloadData[i] & 0xffL) << (8 * i);
546                 }
547
548                 // 8 reserved bytes
549
550                 long version = ((payloadData[19] & 0xFF) << 24);
551                 version |= ((payloadData[18] & 0xFF) << 16);
552                 version |= ((payloadData[17] & 0xFF) << 8);
553                 version |= (payloadData[16] & 0xFF);
554
555                 return new DeviceStateHostFirmware(build, version);
556         }
557
558         private DeviceStateWifiInfo parseDeviceStateWifiInfoMessage(LifxHeader header, byte[] payloadData) {
559                 long signal = ((payloadData[3] & 0xFF) << 24);
560                 signal |= ((payloadData[2] & 0xFF) << 16);
561                 signal |= ((payloadData[1] & 0xFF) << 8);
562                 signal |= (payloadData[0] & 0xFF);
563
564                 long tx = ((payloadData[7] & 0xFF) << 24);
565                 tx |= ((payloadData[6] & 0xFF) << 16);
566                 tx |= ((payloadData[5] & 0xFF) << 8);
567                 tx |= (payloadData[4] & 0xFF);
568
569                 long rx = ((payloadData[11] & 0xFF) << 24);
570                 rx |= ((payloadData[10] & 0xFF) << 16);
571                 rx |= ((payloadData[9] & 0xFF) << 8);
572                 rx |= (payloadData[8] & 0xFF);
573
574                 return new DeviceStateWifiInfo(signal, tx, rx);
575         }
576
577         private DeviceStateWifiFirmware parseDeviceStateWifiFirmwareMessage(LifxHeader header, byte[] payloadData) {
578                 long build = 0;
579                 for (int i = 0; i < 8; i++) {
580                         build += ((long) payloadData[i] & 0xffL) << (8 * i);
581                 }
582
583                 // 8 reserved bytes
584
585                 long version = ((payloadData[19] & 0xFF) << 24);
586                 version |= ((payloadData[18] & 0xFF) << 16);
587                 version |= ((payloadData[17] & 0xFF) << 8);
588                 version |= (payloadData[16] & 0xFF);
589
590                 return new DeviceStateWifiFirmware(build, version);
591         }
592
593         private int parseStatePowerMessage(LifxHeader header, byte[] payloadData) {
594                 int level = ((payloadData[1] & 0xFF) << 8);
595                 level |= (payloadData[0] & 0xFF);
596                 return level;
597         }
598
599         private String parseStateLabelMessage(LifxHeader header, byte[] payloadData) {
600                 return new String(payloadData);
601         }
602
603
604         private DeviceStateVersion parseDeviceStateVersionMessage(LifxHeader header, byte[] payloadData) {
605                 long vender = ((payloadData[3] & 0xFF) << 24);
606                 vender |= ((payloadData[2] & 0xFF) << 16);
607                 vender |= ((payloadData[1] & 0xFF) << 8);
608                 vender |= (payloadData[0] & 0xFF);
609
610                 long product = ((payloadData[7] & 0xFF) << 24);
611                 product |= ((payloadData[6] & 0xFF) << 16);
612                 product |= ((payloadData[5] & 0xFF) << 8);
613                 product |= (payloadData[4] & 0xFF);
614
615                 long version = ((payloadData[11] & 0xFF) << 24);
616                 version |= ((payloadData[10] & 0xFF) << 16);
617                 version |= ((payloadData[9] & 0xFF) << 8);
618                 version |= (payloadData[8] & 0xFF);
619
620                 return new DeviceStateVersion(vender, product, version);
621         }
622
623         private DeviceStateInfo parseDeviceStateInfoMessage(LifxHeader header, byte[] payloadData) {
624                 long time = 0;
625                 long upTime = 0;
626                 long downTime = 0;
627                 for (int i = 0; i < 8; i++) {
628                         time += ((long) payloadData[i] & 0xffL) << (8 * i);
629                         upTime += ((long) payloadData[i + 8] & 0xffL) << (8 * i);
630                         downTime += ((long) payloadData[i + 16] & 0xffL) << (8 * i);
631                 }
632
633                 return new DeviceStateInfo(time, upTime, downTime);
634         }
635
636         private DeviceStateLocation parseDeviceStateLocationMessage(LifxHeader header, byte[] payloadData) {
637                 byte[] location = new byte[16];
638                 for (int i = 0; i < 16; i++) {
639                         location[i] = payloadData[i];
640                 }
641
642                 byte[] labelBytes = new byte[32];
643                 for (int i = 0; i < 32; i++) {
644                         labelBytes[i] = payloadData[i + 16];
645                 }
646
647                 long updatedAt = 0;
648                 for (int i = 0; i < 8; i++) {
649                         updatedAt += ((long) payloadData[48] & 0xffL) << (8 * i);
650                 }
651
652                 return new DeviceStateLocation(location, new String(labelBytes), updatedAt);
653         }
654
655         private DeviceStateGroup parseDeviceStateGroupMessage(LifxHeader header, byte[] payloadData) {
656                 byte[] group = new byte[16];
657                 for (int i = 0; i < 16; i++) {
658                         group[i] = payloadData[i];
659                 }
660
661                 byte[] labelBytes = new byte[32];
662                 for (int i = 0; i < 32; i++) {
663                         labelBytes[i] = payloadData[i + 16];
664                 }
665
666                 long updatedAt = 0;
667                 for (int i = 0; i < 8; i++) {
668                         updatedAt += ((long) payloadData[48] & 0xffL) << (8 * i);
669                 }
670
671                 return new DeviceStateGroup(group, new String(labelBytes), updatedAt);
672         }
673
674         private byte[] parseDeviceEchoResponseMessage(LifxHeader header, byte[] payloadData) {
675                 return payloadData;
676         }
677
678         /*******************************************************************************************************************************************
679         **  Receiving
680         **  Light Messages
681         **
682         *******************************************************************************************************************************************/
683         private LightState parseLightStateMessage(LifxHeader header, byte[] payloadData) {
684
685                 byte[] colorData = new byte[8];
686                 for (int i = 0; i < 8; i++) {
687                         colorData[i] = payloadData[i];
688                 }
689                 BulbColor color = new BulbColor(colorData);
690
691                 int power = ((payloadData[11] & 0xFF) << 8);
692                 power |= (payloadData[10] & 0xFF);
693
694                 String label = new String(payloadData);
695
696                 byte[] labelArray = new byte[32];
697                 for (int i = 0; i < 32; i++) {
698                         labelArray[i] = payloadData[12 + i];
699                 }
700
701                 return new LightState(color, power, label);
702         }
703
704         private int parseLightStatePowerMessage(LifxHeader header, byte[] payloadData) {
705                 int level = ((payloadData[1] & 0xFF) << 8);
706                 level |= (payloadData[0] & 0xFF);
707                 return level;
708         }
709
710
711         /*******************************************************************************************************************************************
712         **
713         **  Private Handlers
714         **
715         *******************************************************************************************************************************************/
716         private void handleStateVersionMessageRecieved(LifxHeader header, byte[] payloadData) {
717
718                 DeviceStateVersion deviceState = parseDeviceStateVersionMessage(header, payloadData);
719                 int productNumber = (int)deviceState.getProduct();
720
721                 boolean isColor = false;
722
723                 if (productNumber == 1) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               // Original 1000
724                         isColor = true;
725                 } else if (productNumber == 3) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                //Color 650
726                         isColor = true;
727                 } else if (productNumber == 10) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               // White 800 (Low Voltage)
728                         isColor = false;
729                 } else if (productNumber == 11) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               // White 800 (High Voltage)
730                         isColor = false;
731                 } else if (productNumber == 18) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               // White 900 BR30 (Low Voltage)
732                         isColor = false;
733                 } else if (productNumber == 20) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               // Color 1000 BR30
734                         isColor = true;
735                 } else if (productNumber == 22) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               // Color 1000
736                         isColor = true;
737                 }
738
739                 if (isColor) {
740                         hueLowerBound = 0;
741                         hueUpperBound = 65535;
742                         saturationLowerBound = 0;
743                         saturationUpperBound = 65535;
744                         brightnessLowerBound = 0;
745                         brightnessUpperBound = 65535;
746                         temperatureLowerBound = 2500;
747                         temperatureUpperBound = 9000;
748                 } else {
749                         hueLowerBound = 0;
750                         hueUpperBound = 0;
751                         saturationLowerBound = 0;
752                         saturationUpperBound = 0;
753                         brightnessLowerBound = 0;
754                         brightnessUpperBound = 65535;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   // still can dim bulb
755                         temperatureLowerBound = 2500;
756                         temperatureUpperBound = 9000;
757                 }
758
759                 didGetBulbVersion.set(true);
760
761         }
762
763         private void handleLightStateMessageRecieved(LifxHeader header, byte[] payloadData) {
764                 LightState lightState = parseLightStateMessage(header, payloadData);
765
766                 BulbColor color = lightState.getColor();
767                 int power = lightState.getPower();
768
769                 boolean bulbWrongColor = false;
770                 bulbWrongColor = bulbWrongColor || (color.getHue() != currentHue);
771                 bulbWrongColor = bulbWrongColor || (color.getSaturation() != currentSaturation);
772                 bulbWrongColor = bulbWrongColor || (color.getBrightness() != currentBrightness);
773                 bulbWrongColor = bulbWrongColor || (color.getKelvin() != currentTemperature);
774
775
776                 // gets set to true if any of the below if statements are taken
777                 stateDidChange = false;
778
779                 if (bulbWrongColor) {
780                         BulbColor newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, currentTemperature);
781                         sendSetLightColorPacket(newColor, 250);
782                         // System.out.println("Failed Check 1");
783                 }
784
785                 try {
786                         bulbStateMutex.acquire();
787                 } catch (Exception e) {
788                         e.printStackTrace();
789                 }
790                 boolean bulbIsOnTmp = bulbIsOn;
791                 bulbStateMutex.release();
792
793                 if ((!bulbIsOnTmp) && (power != 0)) {
794                         turnOff();
795                         // System.out.println("Failed Check 2:  " + Integer.toString(power));
796
797                 }
798
799                 if (bulbIsOnTmp && (power < 65530)) {
800                         turnOn();
801                         // System.out.println("Failed Check 3:  " + Integer.toString(power));
802
803                 }
804         }
805
806         /*******************************************************************************************************************************************
807         **
808         **  Light Bulb Interface Methods
809         **
810         *******************************************************************************************************************************************/
811         public double getHue() {
812                 double tmp = 0;
813                 try {
814                         settingBulbColorMutex.acquire();
815                         tmp = ((double)currentHue / 65535.0) * 360.0;
816                 } catch (Exception e) {
817                         e.printStackTrace();
818                 }
819                 settingBulbColorMutex.release();
820
821
822                 return tmp;
823         }
824
825         public double getSaturation() {
826                 double tmp = 0;
827                 try {
828                         settingBulbColorMutex.acquire();
829                         tmp = ((double)currentSaturation / 65535.0) * 360.0;
830                 } catch (Exception e) {
831                         e.printStackTrace();
832                 }
833                 settingBulbColorMutex.release();
834
835
836                 return tmp;
837         }
838
839         public double getBrightness() {
840                 double tmp = 0;
841                 try {
842                         settingBulbColorMutex.acquire();
843                         tmp = ((double)currentBrightness / 65535.0) * 360.0;
844                 } catch (Exception e) {
845                         e.printStackTrace();
846                 }
847                 settingBulbColorMutex.release();
848
849                 return tmp;
850         }
851
852         public int getTemperature() {
853
854                 int tmp = 0;
855                 try {
856                         settingBulbTempuraturerMutex.acquire();
857                         tmp = currentTemperature;
858                 } catch (Exception e) {
859                         e.printStackTrace();
860                 }
861                 settingBulbTempuraturerMutex.release();
862
863                 return tmp;
864         }
865
866         public double getHueRangeLowerBound() {
867                 if (!didGetBulbVersion.get()) {
868                         return -1;
869                 }
870                 return ((double)hueLowerBound / 65535.0) * 360.0;
871         }
872
873         public double getHueRangeUpperBound() {
874                 if (!didGetBulbVersion.get()) {
875                         return -1;
876                 }
877                 return ((double)hueUpperBound / 65535.0) * 360.0;
878         }
879
880         public double getSaturationRangeLowerBound() {
881                 if (!didGetBulbVersion.get()) {
882                         return -1;
883                 }
884                 return ((double)saturationLowerBound / 65535.0) * 100.0;
885         }
886
887         public double getSaturationRangeUpperBound() {
888                 if (!didGetBulbVersion.get()) {
889                         return -1;
890                 }
891                 return ((double)saturationUpperBound / 65535.0) * 100.0;
892         }
893
894         public double getBrightnessRangeLowerBound() {
895                 if (!didGetBulbVersion.get()) {
896                         return -1;
897                 }
898                 return ((double)brightnessLowerBound / 65535.0) * 100.0;
899         }
900
901         public double getBrightnessRangeUpperBound() {
902                 if (!didGetBulbVersion.get()) {
903                         return -1;
904                 }
905                 return ((double)brightnessUpperBound / 65535.0) * 100.0;
906         }
907
908         public int getTemperatureRangeLowerBound() {
909                 if (!didGetBulbVersion.get()) {
910                         return -1;
911                 }
912                 return temperatureLowerBound;
913         }
914
915         public int getTemperatureRangeUpperBound() {
916                 if (!didGetBulbVersion.get()) {
917                         return -1;
918                 }
919                 return temperatureUpperBound;
920         }
921
922         public void setTemperature(int _temperature) {
923
924                 try {
925                         settingBulbTempuraturerMutex.acquire();
926                 } catch (Exception e) {
927                         e.printStackTrace();
928                 }
929
930                 BulbColor newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, _temperature);
931                 sendSetLightColorPacket(newColor, 250);
932
933                 currentTemperature = _temperature;
934                 stateDidChange = true;
935
936                 settingBulbTempuraturerMutex.release();
937         }
938
939         public void setColor(double _hue, double _saturation, double _brightness) {
940
941                 try {
942                         settingBulbColorMutex.acquire();
943                 } catch (Exception e) {
944                         e.printStackTrace();
945                 }
946
947
948                 _hue /= 360.0;
949                 _saturation /= 100.0;
950                 _brightness /= 100.0;
951
952
953                 int newHue = (int)(_hue * 65535.0);
954                 int newSaturation = (int)(_saturation * 65535.0);
955                 int newBrightness = (int)(_brightness * 65535.0);
956
957                 BulbColor newColor = new BulbColor(newHue, newSaturation, newBrightness, currentTemperature);
958                 sendSetLightColorPacket(newColor, 250);
959
960                 currentHue = newHue;
961                 currentSaturation = newSaturation;
962                 currentBrightness = newBrightness;
963                 stateDidChange = true;
964
965                 settingBulbColorMutex.release();
966         }
967
968
969         public void turnOff() {
970
971                 try {
972                         bulbStateMutex.acquire();
973                         bulbIsOn = false;
974                         sendSetLightPowerPacket(0, 0);
975                         stateDidChange = true;
976                 } catch (Exception e) {
977                         e.printStackTrace();
978                 }
979
980                 bulbStateMutex.release();
981         }
982
983         public void turnOn() {
984                 try {
985                         bulbStateMutex.acquire();
986                         bulbIsOn = true;
987                         sendSetLightPowerPacket(65535, 0);
988                         stateDidChange = true;
989
990                 } catch (Exception e) {
991                         e.printStackTrace();
992                 }
993
994
995                 bulbStateMutex.release();
996         }
997
998         public boolean getState() {
999
1000                 boolean tmp = false;
1001                 try {
1002                         bulbStateMutex.acquire();
1003                         tmp = bulbIsOn;
1004                 } catch (Exception e) {
1005                         e.printStackTrace();
1006                 }
1007
1008                 bulbStateMutex.release();
1009
1010                 return tmp;
1011         }
1012
1013
1014         /*******************************************************************************************************************************************
1015         **
1016         **  Communication Helpers
1017         **
1018         *******************************************************************************************************************************************/
1019         private void recievedPacket(byte[] packetData) {
1020
1021                 byte[] headerBytes = new byte[36];
1022                 for (int i = 0; i < 36; i++) {
1023                         headerBytes[i] = packetData[i];
1024                 }
1025
1026                 LifxHeader recHeader = new LifxHeader();
1027                 recHeader.setFromBytes(headerBytes);
1028
1029                 // load the payload bytes (strip away the header)
1030                 byte[] payloadBytes = new byte[recHeader.getSize()];
1031                 for (int i = 36; i < recHeader.getSize(); i++) {
1032                         payloadBytes[i - 36] = packetData[i];
1033                 }
1034
1035                 System.out.println("Received: " + Integer.toString(recHeader.getType()));
1036
1037                 switch (recHeader.getType()) {
1038                 case 3:
1039                         DeviceStateService dat = parseDeviceStateServiceMessage(recHeader, payloadBytes);
1040                         // System.out.println("Service: " + Integer.toString(dat.getService()));
1041                         // System.out.println("Port   : " + Long.toString(dat.getPort()));
1042                         break;
1043
1044
1045                 case 33:
1046                         handleStateVersionMessageRecieved(recHeader, payloadBytes);
1047                         break;
1048
1049                 case 35:
1050                         parseDeviceStateInfoMessage(recHeader, payloadBytes);
1051                         break;
1052
1053
1054                 case 107:
1055                         handleLightStateMessageRecieved(recHeader, payloadBytes);
1056                         break;
1057
1058                 default:
1059                         // System.out.println("unknown packet Type");
1060                 }
1061
1062         }
1063
1064         private void sendPacket(byte[] packetData) {
1065                 // System.out.println("About to send");
1066                 sendSocketFlag = true;
1067
1068                 try {
1069                         socketMutex.acquire();
1070                 } catch (InterruptedException e) {
1071                         System.out.println("mutex Error");
1072                 }
1073
1074                 try {
1075                         communicationSockect.sendData(packetData);
1076
1077                 } catch (IOException e) {
1078                         System.out.println("Socket Send Error");
1079                 }
1080
1081                 sendSocketFlag = false;
1082                 socketMutex.release();
1083         }
1084
1085
1086         /**
1087          *   Worker function which runs the while loop for receiving data from the bulb.
1088          *   Is blocking
1089          */
1090         private void workerFunction() {
1091                 LifxHeader h = new LifxHeader();
1092
1093                 try {
1094                         // Need timeout on receives since we are not sure if a packet will be available
1095                         // for processing so don't block waiting
1096                         communicationSockect.setSoTimeout(50);
1097                 } catch (IOException e) {
1098                 }
1099
1100                 // Start the bulb in the off state
1101                 turnOff();
1102
1103
1104                 while (true) {
1105
1106                         // Check if we got the bulb version yet
1107                         // could have requested it but message could have gotten lost (UDP)
1108                         if (!didGetBulbVersion.get()) {
1109                                 long currentTime = (new Date().getTime()) / 1000;
1110                                 if ((currentTime - lastSentGetBulbVersionRequest) > GET_BULB_VERSION_RESEND_WAIT_SECONDS) {
1111                                         // Get the bulb version so we know what type of bulb this is.
1112                                         sendGetVersionPacket();
1113                                         lastSentGetBulbVersionRequest = currentTime;
1114                                 }
1115                         }
1116
1117                         // Communication resource is busy so try again later
1118                         if (sendSocketFlag) {
1119                                 continue;
1120                         }
1121
1122                         try {
1123                                 socketMutex.acquire();
1124                         } catch (InterruptedException e) {
1125                         }
1126
1127                         byte[] dat = null;
1128                         try {
1129                                 dat = communicationSockect.recieveData(1024);
1130                         } catch (java.net.SocketTimeoutException e) {
1131                                 // Timeout occurred
1132
1133                         } catch (IOException e) {
1134                                 // Problem but might be able to recover??
1135                                 e.printStackTrace();
1136
1137                         }
1138
1139                         // Never forget to release!
1140                         socketMutex.release();
1141
1142                         // A packed arrived
1143                         if (dat != null) {
1144                                 recievedPacket(dat);
1145                         }
1146
1147                         // If a state change occurred then request the bulb state to ensure that the
1148                         // bulb did indeed change its state to the correct state
1149                         if (stateDidChange) {
1150                                 sendGetLightStatePacket();
1151                         }
1152
1153                         // Wait a bit as to not tie up system resources
1154                         try {
1155                                 Thread.sleep(100);
1156                         } catch (Exception e) {
1157
1158                         }
1159
1160
1161                 }
1162         }
1163
1164
1165         public void init() {
1166
1167                 if (didAlreadyInit.compareAndSet(false, true) == false) {
1168                         return; // already init
1169                 }
1170
1171                 try {
1172                         // Get the bulb address from the IoTSet
1173                         Iterator itr = lb_addresses.iterator();
1174                         IoTDeviceAddress deviceAddress = (IoTDeviceAddress)itr.next();
1175
1176                         System.out.println("Address: " + deviceAddress.getCompleteAddress());
1177
1178                         // Create the communication channel
1179                         communicationSockect = new IoTUDP(deviceAddress);
1180
1181                 } catch (IOException e) {
1182                         e.printStackTrace();
1183                 }
1184
1185                 // Launch the worker function in a separate thread.
1186                 workerThread = new Thread(new Runnable() {
1187                         public void run() {
1188                                 workerFunction();
1189                         }
1190                 });
1191                 workerThread.start();
1192
1193         }
1194 }
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214