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