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