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