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