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