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