Adjustments and clean-ups for Makefile for C++ benchmark and drivers
[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         llb->log << "Turning off and entering while loop!" << endl;
407
408         while (true) {
409                 // Check if we got the bulb version yet
410                 // could have requested it but message could have gotten lost (UDP)
411                 if (!llb->didGetBulbVersion) {
412                         int64_t currentTime = (int64_t) time(NULL);
413                         if ((currentTime - lastSentGetBulbVersionRequest) > llb->GET_BULB_VERSION_RESEND_WAIT_SECONDS) {
414                                 // Get the bulb version so we know what type of bulb this is.
415                                 //cout << "Sending version packet! " << endl;
416                                 llb->sendGetVersionPacket();
417                                 lastSentGetBulbVersionRequest = currentTime;
418                         }
419                 }
420
421                 // Communication resource is busy so try again later
422                 if (llb->sendSocketFlag) {
423                         continue;
424                 }
425
426                 llb->socketMutex.lock();
427                 int ret = llb->communicationSocket->receiveData(dat, 1024);
428                 // Never forget to release!
429                 llb->socketMutex.unlock();
430
431                 // A packed arrived
432                 if (ret != -1) {
433                         llb->receivedPacket(dat);
434                 }
435
436                 // If a state change occurred then request the bulb state to ensure that the
437                 // bulb did indeed change its state to the correct state
438                 if (llb->stateDidChange) {
439                         llb->sendGetLightStatePacket();
440                 }
441
442                 // Wait a bit as to not tie up system resources
443                 this_thread::sleep_for (chrono::milliseconds(100));
444                 //cout << endl << "Sleep and wake up!" << endl;
445         }
446 }
447
448
449 //  Sending
450 //  Device Messages
451 void LifxLightBulb::sendGetServicePacket() {
452         LifxHeader header;
453         header.setSize(36);
454         header.setTagged(true);
455         header.setMacAddress(bulbMacAddress);
456         header.setSource(0);    // randomly picked
457         header.setAck_required(false);
458         header.setRes_required(false);
459         header.setSequence(0);
460         header.setType(2);
461
462         char dataBytes[36];
463         header.getHeaderBytes(dataBytes);
464
465         sendPacket(dataBytes, 36);
466 }
467
468
469 void LifxLightBulb::sendGetHostInfoPacket() {
470         LifxHeader header;
471         header.setSize(36);
472         header.setTagged(false);
473         header.setMacAddress(bulbMacAddress);
474         header.setSource(10);   // randomly picked
475         header.setAck_required(false);
476         header.setRes_required(false);
477         header.setSequence(0);
478         header.setType(12);
479
480         char dataBytes[36];
481         header.getHeaderBytes(dataBytes);
482
483         sendPacket(dataBytes, 36);
484 }
485
486
487 void LifxLightBulb::sendGetHostFirmwarePacket() {
488         LifxHeader header;
489         header.setSize(36);
490         header.setTagged(false);
491         header.setMacAddress(bulbMacAddress);
492         header.setSource(10);   // randomly picked
493         header.setAck_required(false);
494         header.setRes_required(false);
495         header.setSequence(0);
496         header.setType(14);
497
498         char dataBytes[36];
499         header.getHeaderBytes(dataBytes);
500
501         sendPacket(dataBytes, 36);
502 }
503
504
505 void LifxLightBulb::sendGetWifiInfoPacket() {
506         LifxHeader header;
507         header.setSize(36);
508         header.setTagged(false);
509         header.setMacAddress(bulbMacAddress);
510         header.setSource(10);   // randomly picked
511         header.setAck_required(false);
512         header.setRes_required(false);
513         header.setSequence(0);
514         header.setType(16);
515
516         char dataBytes[36];
517         header.getHeaderBytes(dataBytes);
518
519         sendPacket(dataBytes, 36);
520 }
521
522
523 void LifxLightBulb::sendGetWifiFirmwarePacket() {
524         LifxHeader header;
525         header.setSize(36);
526         header.setTagged(false);
527         header.setMacAddress(bulbMacAddress);
528         header.setSource(10);   // randomly picked
529         header.setAck_required(false);
530         header.setRes_required(false);
531         header.setSequence(0);
532         header.setType(18);
533
534         char dataBytes[36];
535         header.getHeaderBytes(dataBytes);
536
537         sendPacket(dataBytes, 36);
538 }
539
540
541 void LifxLightBulb::sendGetPowerPacket() {
542         LifxHeader header;
543         header.setSize(36);
544         header.setTagged(false);
545         header.setMacAddress(bulbMacAddress);
546         header.setSource(10);   // randomly picked
547         header.setAck_required(false);
548         header.setRes_required(false);
549         header.setSequence(0);
550         header.setType(20);
551
552         char dataBytes[36];
553         header.getHeaderBytes(dataBytes);
554
555         sendPacket(dataBytes, 36);
556 }
557
558
559 void LifxLightBulb::sendSetPowerPacket(int level) {
560         // Currently only 0 and 65535 are supported
561         // This is a fix for now
562         if ((level != 65535) && (level != 0)) {
563                 cerr << "Invalid parameter values" << endl;
564                 exit(1);
565         }
566
567         if ((level > 65535) || (level < 0)) {
568                 cerr << "Invalid parameter values" << endl;
569                 exit(1);
570         }
571
572         char packetBytes[38];
573
574         LifxHeader header;
575         header.setSize(38);
576         header.setTagged(false);
577         header.setMacAddress(bulbMacAddress);
578         header.setSource(10);   // randomly picked
579         header.setAck_required(false);
580         header.setRes_required(false);
581         header.setSequence(0);
582         header.setType(21);
583         char headerBytes[36];
584         header.getHeaderBytes(headerBytes);
585
586         for (int i = 0; i < 36; i++) {
587                 packetBytes[i] = headerBytes[i];
588         }
589
590         packetBytes[36] = (char)(level & 0xFF);
591         packetBytes[37] = (char)((level >> 8) & 0xFF);
592
593         sendPacket(packetBytes, 38);
594 }
595
596
597 void LifxLightBulb::sendGetLabelPacket() {
598         LifxHeader header;
599         header.setSize(36);
600         header.setTagged(false);
601         header.setMacAddress(bulbMacAddress);
602         header.setSource(10); // randomly picked
603         header.setAck_required(false);
604         header.setRes_required(false);
605         header.setSequence(0);
606         header.setType(23);
607
608         char dataBytes[36];
609         header.getHeaderBytes(dataBytes);
610
611         sendPacket(dataBytes, 36);
612 }
613
614
615 void LifxLightBulb::sendSetLabelPacket(string label) {
616         // Currently only 0 and 65535 are supported
617         // This is a fix for now
618         if (label.length() != 32) {
619                 cerr << "Invalid parameter values, label must be 32 bytes long" << endl;
620                 exit(1);
621         }
622
623         char packetBytes[68];
624
625         LifxHeader header;
626         header.setSize(68);
627         header.setTagged(false);
628         header.setMacAddress(bulbMacAddress);
629         header.setSource(10); // randomly picked
630         header.setAck_required(false);
631         header.setRes_required(false);
632         header.setSequence(0);
633         header.setType(24);
634         char headerBytes[36];
635         header.getHeaderBytes(headerBytes);
636
637         for (int i = 0; i < 36; i++) {
638                 packetBytes[i] = headerBytes[i];
639         }
640
641         for (int i = 0; i < 32; i++) {
642                 packetBytes[i + 36] = label.c_str()[i];
643         }
644
645         sendPacket(packetBytes, 68);
646 }
647
648
649 void LifxLightBulb::sendGetVersionPacket() {
650         LifxHeader header;
651         header.setSize(36);
652         header.setTagged(false);
653         header.setMacAddress(bulbMacAddress);
654         header.setSource(10); // randomly picked
655         header.setAck_required(false);
656         header.setRes_required(false);
657         header.setSequence(0);
658         header.setType(32);
659
660         char dataBytes[36];
661         header.getHeaderBytes(dataBytes);
662
663         sendPacket(dataBytes, 36);
664 }
665
666
667 void LifxLightBulb::sendGetInfoPacket() {
668         LifxHeader header;
669         header.setSize(36);
670         header.setTagged(false);
671         header.setMacAddress(bulbMacAddress);
672         header.setSource(10); // randomly picked
673         header.setAck_required(false);
674         header.setRes_required(false);
675         header.setSequence(0);
676         header.setType(34);
677
678         char dataBytes[36];
679         header.getHeaderBytes(dataBytes);
680
681         sendPacket(dataBytes, 36);
682 }
683
684
685 void LifxLightBulb::sendGetLocationPacket() {
686         LifxHeader header;
687         header.setSize(36);
688         header.setTagged(false);
689         header.setMacAddress(bulbMacAddress);
690         header.setSource(10); // randomly picked
691         header.setAck_required(false);
692         header.setRes_required(false);
693         header.setSequence(0);
694         header.setType(34);
695
696         char dataBytes[36];
697         header.getHeaderBytes(dataBytes);
698
699         sendPacket(dataBytes, 36);
700 }
701
702
703 void LifxLightBulb::sendGetGroupPacket() {
704         LifxHeader header;
705         header.setSize(36);
706         header.setTagged(false);
707         header.setMacAddress(bulbMacAddress);
708         header.setSource(10); // randomly picked
709         header.setAck_required(false);
710         header.setRes_required(false);
711         header.setSequence(0);
712         header.setType(51);
713
714         char dataBytes[36];
715         header.getHeaderBytes(dataBytes);
716
717         sendPacket(dataBytes, 36);
718 }
719
720
721 //  Sending
722 //  Light Messages
723 void LifxLightBulb::sendGetLightStatePacket() {
724         LifxHeader header;
725         header.setSize(36);
726         header.setTagged(false);
727         header.setMacAddress(bulbMacAddress);
728         header.setSource(10); // randomly picked
729         header.setAck_required(false);
730         header.setRes_required(false);
731         header.setSequence(0);
732         header.setType(101);
733
734         char dataBytes[36];
735         header.getHeaderBytes(dataBytes);
736
737         sendPacket(dataBytes, 36);
738 }
739
740
741 void LifxLightBulb::sendSetLightColorPacket(BulbColor* bulbColor, long duration) {
742
743         if ((duration > 4294967295l) || (duration < 0)) {
744                 cerr << "Invalid parameter value, duration out of range (0 - 4294967295)" << endl;
745                 exit(1);
746         }
747
748         char packetBytes[49];
749
750         LifxHeader header;
751         header.setSize(49);
752         header.setTagged(false);
753         header.setMacAddress(bulbMacAddress);
754         header.setSource(10); // randomly picked
755         header.setAck_required(false);
756         header.setRes_required(false);
757         header.setSequence(0);
758         header.setType(102);
759         char headerBytes[36];
760         header.getHeaderBytes(headerBytes);
761
762         for (int i = 0; i < 36; i++) {
763                 packetBytes[i] = headerBytes[i];
764         }
765
766         // 1 reserved packet
767         packetBytes[37] = (char)(bulbColor->getHue() & 0xFF);
768         packetBytes[38] = (char)((bulbColor->getHue() >> 8) & 0xFF);
769
770         packetBytes[39] = (char)(bulbColor->getSaturation() & 0xFF);
771         packetBytes[40] = (char)((bulbColor->getSaturation() >> 8) & 0xFF);
772
773         packetBytes[41] = (char)(bulbColor->getBrightness() & 0xFF);
774         packetBytes[42] = (char)((bulbColor->getBrightness() >> 8) & 0xFF);
775
776         packetBytes[43] = (char)(bulbColor->getKelvin() & 0xFF);
777         packetBytes[44] = (char)((bulbColor->getKelvin() >> 8) & 0xFF);
778
779         packetBytes[45] = (char)((duration >> 0) & 0xFF);
780         packetBytes[46] = (char)((duration >> 8) & 0xFF);
781         packetBytes[47] = (char)((duration >> 16) & 0xFF);
782         packetBytes[48] = (char)((duration >> 24) & 0xFF);
783
784         sendPacket(packetBytes, 49);
785         // Avoid memory leak - delete object
786         delete bulbColor;
787 }
788
789
790 void LifxLightBulb::sendGetLightPowerPacket() {
791         LifxHeader header;
792         header.setSize(36);
793         header.setTagged(false);
794         header.setMacAddress(bulbMacAddress);
795         header.setSource(10); // randomly picked
796         header.setAck_required(false);
797         header.setRes_required(false);
798         header.setSequence(0);
799         header.setType(116);
800
801         char dataBytes[36];
802         header.getHeaderBytes(dataBytes);
803
804         sendPacket(dataBytes, 36);
805 }
806
807
808 void LifxLightBulb::sendSetLightPowerPacket(int level, long duration) {
809
810         if ((level > 65535) || (duration > 4294967295l)
811                     || (level < 0) || (duration < 0)) {
812                 cerr << "Invalid parameter values" << endl;
813                 exit(1);
814         }
815
816         char packetBytes[42];
817
818
819         LifxHeader header;
820         header.setSize(42);
821         header.setTagged(false);
822         header.setMacAddress(bulbMacAddress);
823         header.setSource(10);   // randomly picked
824         header.setAck_required(false);
825         header.setRes_required(false);
826         header.setSequence(0);
827         header.setType(117);
828         char headerBytes[36];
829         header.getHeaderBytes(headerBytes);
830
831         for (int i = 0; i < 36; i++) {
832                 packetBytes[i] = headerBytes[i];
833         }
834
835         packetBytes[36] = (char)(level & 0xFF);
836         packetBytes[37] = (char)((level >> 8) & 0xFF);
837
838         packetBytes[38] = (char)((duration >> 0) & 0xFF);
839         packetBytes[39] = (char)((duration >> 8) & 0xFF);
840         packetBytes[40] = (char)((duration >> 16) & 0xFF);
841         packetBytes[41] = (char)((duration >> 24) & 0xFF);
842
843         sendPacket(packetBytes, 42);
844 }
845
846
847 void LifxLightBulb::sendEchoRequestPacket(char data[64]) {
848
849         char packetBytes[100];
850
851         LifxHeader header;
852         header.setSize(100);
853         header.setTagged(false);
854         header.setMacAddress(bulbMacAddress);
855         header.setSource(10); // randomly picked
856         header.setAck_required(false);
857         header.setRes_required(false);
858         header.setSequence(0);
859         header.setType(58);
860         char headerBytes[36];
861         header.getHeaderBytes(headerBytes);
862
863         for (int i = 0; i < 36; i++) {
864                 packetBytes[i] = headerBytes[i];
865         }
866
867         for (int i = 0; i < 64; i++) {
868                 packetBytes[i + 36] = data[i];
869         }
870
871         sendPacket(packetBytes, 100);
872 }
873
874
875 // Receiving
876 // Device Messages
877 DeviceStateService* LifxLightBulb::parseDeviceStateServiceMessage(char* payloadData) {
878         int service = payloadData[0];
879         int64_t port = ((payloadData[3] & 0xFF) << 24);
880         port |= ((payloadData[2] & 0xFF) << 16);
881         port |= ((payloadData[1] & 0xFF) << 8);
882         port |= (payloadData[0] & 0xFF);
883
884         return new DeviceStateService(service, port);
885 }
886
887
888 DeviceStateHostInfo* LifxLightBulb::parseDeviceStateHostInfoMessage(char* payloadData) {
889         long signal = ((payloadData[3] & 0xFF) << 24);
890         signal |= ((payloadData[2] & 0xFF) << 16);
891         signal |= ((payloadData[1] & 0xFF) << 8);
892         signal |= (payloadData[0] & 0xFF);
893
894         long tx = ((payloadData[7] & 0xFF) << 24);
895         tx |= ((payloadData[6] & 0xFF) << 16);
896         tx |= ((payloadData[5] & 0xFF) << 8);
897         tx |= (payloadData[4] & 0xFF);
898
899         long rx = ((payloadData[11] & 0xFF) << 24);
900         rx |= ((payloadData[10] & 0xFF) << 16);
901         rx |= ((payloadData[9] & 0xFF) << 8);
902         rx |= (payloadData[8] & 0xFF);
903
904         return new DeviceStateHostInfo(signal, tx, rx);
905 }
906
907
908 DeviceStateHostFirmware* LifxLightBulb::parseDeviceStateHostFirmwareMessage(char* payloadData) {
909         long build = 0;
910         for (int i = 0; i < 8; i++) {
911                 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
912         }
913
914         // 8 reserved bytes
915
916         int64_t version = ((payloadData[19] & 0xFF) << 24);
917         version |= ((payloadData[18] & 0xFF) << 16);
918         version |= ((payloadData[17] & 0xFF) << 8);
919         version |= (payloadData[16] & 0xFF);
920
921         return new DeviceStateHostFirmware(build, version);
922 }
923
924
925 DeviceStateWifiInfo* LifxLightBulb::parseDeviceStateWifiInfoMessage(char* payloadData) {
926         int64_t signal = ((payloadData[3] & 0xFF) << 24);
927         signal |= ((payloadData[2] & 0xFF) << 16);
928         signal |= ((payloadData[1] & 0xFF) << 8);
929         signal |= (payloadData[0] & 0xFF);
930
931         int64_t tx = ((payloadData[7] & 0xFF) << 24);
932         tx |= ((payloadData[6] & 0xFF) << 16);
933         tx |= ((payloadData[5] & 0xFF) << 8);
934         tx |= (payloadData[4] & 0xFF);
935
936         int64_t rx = ((payloadData[11] & 0xFF) << 24);
937         rx |= ((payloadData[10] & 0xFF) << 16);
938         rx |= ((payloadData[9] & 0xFF) << 8);
939         rx |= (payloadData[8] & 0xFF);
940
941         return new DeviceStateWifiInfo(signal, tx, rx);
942 }
943
944
945 DeviceStateWifiFirmware* LifxLightBulb::parseDeviceStateWifiFirmwareMessage(char* payloadData) {
946         long build = 0;
947         for (int i = 0; i < 8; i++) {
948                 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
949         }
950
951         // 8 reserved bytes
952
953         int64_t version = ((payloadData[19] & 0xFF) << 24);
954         version |= ((payloadData[18] & 0xFF) << 16);
955         version |= ((payloadData[17] & 0xFF) << 8);
956         version |= (payloadData[16] & 0xFF);
957
958         return new DeviceStateWifiFirmware(build, version);
959 }
960
961
962 int LifxLightBulb::parseStatePowerMessage(char* payloadData) {
963         int level = ((payloadData[1] & 0xFF) << 8);
964         level |= (payloadData[0] & 0xFF);
965         return level;
966 }
967
968
969 DeviceStateVersion* LifxLightBulb::parseDeviceStateVersionMessage(char* payloadData) {
970         int64_t vender = ((payloadData[3] & 0xFF) << 24);
971         vender |= ((payloadData[2] & 0xFF) << 16);
972         vender |= ((payloadData[1] & 0xFF) << 8);
973         vender |= (payloadData[0] & 0xFF);
974
975         int64_t product = ((payloadData[7] & 0xFF) << 24);
976         product |= ((payloadData[6] & 0xFF) << 16);
977         product |= ((payloadData[5] & 0xFF) << 8);
978         product |= (payloadData[4] & 0xFF);
979
980         int64_t version = ((payloadData[11] & 0xFF) << 24);
981         version |= ((payloadData[10] & 0xFF) << 16);
982         version |= ((payloadData[9] & 0xFF) << 8);
983         version |= (payloadData[8] & 0xFF);
984
985         return new DeviceStateVersion(vender, product, version);
986 }
987
988
989 DeviceStateInfo* LifxLightBulb::parseDeviceStateInfoMessage(char* payloadData) {
990         int64_t time = 0;
991         int64_t upTime = 0;
992         int64_t downTime = 0;
993         for (int i = 0; i < 8; i++) {
994                 time += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
995                 upTime += ((int64_t) payloadData[i + 8] & 0xffL) << (8 * i);
996                 downTime += ((int64_t) payloadData[i + 16] & 0xffL) << (8 * i);
997         }
998
999         return new DeviceStateInfo(time, upTime, downTime);
1000 }
1001
1002
1003 DeviceStateLocation* LifxLightBulb::parseDeviceStateLocationMessage(char* payloadData) {
1004         char location[16];
1005         for (int i = 0; i < 16; i++) {
1006                 location[i] = payloadData[i];
1007         }
1008
1009         char labelBytes[32];
1010         for (int i = 0; i < 32; i++) {
1011                 labelBytes[i] = payloadData[i + 16];
1012         }
1013
1014         int64_t updatedAt = 0;
1015         for (int i = 0; i < 8; i++) {
1016                 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
1017         }
1018
1019         string str(labelBytes);
1020         return new DeviceStateLocation(location, str, updatedAt);
1021 }
1022
1023
1024 DeviceStateGroup* LifxLightBulb::parseDeviceStateGroupMessage(char* payloadData) {
1025         char group[16];
1026         for (int i = 0; i < 16; i++) {
1027                 group[i] = payloadData[i];
1028         }
1029
1030         char labelBytes[32];
1031         for (int i = 0; i < 32; i++) {
1032                 labelBytes[i] = payloadData[i + 16];
1033         }
1034
1035         int64_t updatedAt = 0;
1036         for (int i = 0; i < 8; i++) {
1037                 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
1038         }
1039
1040         string str(labelBytes);
1041         return new DeviceStateGroup(group, str, updatedAt);
1042 }
1043
1044
1045 // Receiving
1046 // Light Messages
1047 LightState* LifxLightBulb::parseLightStateMessage(char* payloadData) {
1048
1049         char colorData[8];
1050         for (int i = 0; i < 8; i++) {
1051                 colorData[i] = payloadData[i];
1052         }
1053         //BulbColor color(colorData);
1054         BulbColor* color = new BulbColor(colorData);
1055
1056         int power = ((payloadData[11] & 0xFF) << 8);
1057         power |= (payloadData[10] & 0xFF);
1058
1059         string label(payloadData);
1060
1061         char labelArray[32];
1062         for (int i = 0; i < 32; i++) {
1063                 labelArray[i] = payloadData[12 + i];
1064         }
1065
1066         return new LightState(color, power, label);
1067 }
1068
1069
1070 int LifxLightBulb::parseLightStatePowerMessage(char* payloadData) {
1071         int level = ((payloadData[1] & 0xFF) << 8);
1072         level |= (payloadData[0] & 0xFF);
1073         return level;
1074 }
1075
1076
1077 // Private Handlers
1078 void LifxLightBulb::handleStateVersionMessageReceived(char* payloadData) {
1079
1080         DeviceStateVersion* deviceState = parseDeviceStateVersionMessage(payloadData);
1081         int productNumber = (int)deviceState->getProduct();
1082
1083         bool isColor = false;
1084
1085         if (productNumber == 1) {// Original 1000
1086                 isColor = true;
1087         } else if (productNumber == 3) {//Color 650
1088                 isColor = true;
1089         } else if (productNumber == 10) {// White 800 (Low Voltage)
1090                 isColor = false;
1091         } else if (productNumber == 11) {// White 800 (High Voltage)
1092                 isColor = false;
1093         } else if (productNumber == 18) {// White 900 BR30 (Low Voltage)
1094                 isColor = false;
1095         } else if (productNumber == 20) {// Color 1000 BR30
1096                 isColor = true;
1097         } else if (productNumber == 22) {// Color 1000
1098                 isColor = true;
1099         }
1100
1101         if (isColor) {
1102                 hueLowerBound = 0;
1103                 hueUpperBound = 65535;
1104                 saturationLowerBound = 0;
1105                 saturationUpperBound = 65535;
1106                 brightnessLowerBound = 0;
1107                 brightnessUpperBound = 65535;
1108                 temperatureLowerBound = 2500;
1109                 temperatureUpperBound = 9000;
1110         } else {
1111                 hueLowerBound = 0;
1112                 hueUpperBound = 0;
1113                 saturationLowerBound = 0;
1114                 saturationUpperBound = 0;
1115                 brightnessLowerBound = 0;
1116                 brightnessUpperBound = 65535;// still can dim bulb
1117                 temperatureLowerBound = 2500;
1118                 temperatureUpperBound = 9000;
1119         }
1120
1121         didGetBulbVersion.exchange(true);
1122         // Avoid memory leak - delete this object
1123         delete deviceState;
1124 }
1125
1126
1127 void LifxLightBulb::handleLightStateMessageReceived(char* payloadData) {
1128         LightState* lightState = parseLightStateMessage(payloadData);
1129
1130         BulbColor* color = lightState->getColor();
1131         int power = lightState->getPower();
1132
1133         //cout << "color->getHue(): " << color->getHue() << " - currentHue: " << currentHue << endl;
1134         //cout << "color->getSaturation(): " << color->getSaturation() << " - currentSaturation: " << currentSaturation << endl;
1135         //cout << "color->getBrightness(): " << color->getBrightness() << " - currentBrightness: " << currentBrightness << endl;
1136         //cout << "color->getKelvin(): " << color->getKelvin() << " - currentTemperature: " << currentTemperature << endl;
1137
1138         bool bulbWrongColor = false;
1139         bulbWrongColor = bulbWrongColor || (color->getHue() != currentHue);
1140         bulbWrongColor = bulbWrongColor || (color->getSaturation() != currentSaturation);
1141         bulbWrongColor = bulbWrongColor || (color->getBrightness() != currentBrightness);
1142         bulbWrongColor = bulbWrongColor || (color->getKelvin() != currentTemperature);
1143
1144
1145         // gets set to true if any of the below if statements are taken
1146         stateDidChange = false;
1147
1148         if (bulbWrongColor) {
1149                 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, currentTemperature);
1150                 sendSetLightColorPacket(newColor, 250);
1151                 //cout << "Failed Check 1" << endl;
1152         }
1153
1154         bulbStateMutex.lock();
1155         bool bulbIsOnTmp = bulbIsOn;
1156         bulbStateMutex.unlock();
1157
1158         if ((!bulbIsOnTmp) && (power != 0)) {
1159                 turnOff();
1160                 //cout << "Failed Check 2:  " << endl;
1161
1162         }
1163
1164         if (bulbIsOnTmp && (power < 65530)) {
1165                 turnOn();
1166                 //cout << "Failed Check 3:  " << endl;
1167
1168         }
1169         // Avoid memory leak - delete object
1170         delete lightState;
1171         delete color;
1172 }
1173
1174
1175 // Functions for the main function
1176 void onOff(LifxLightBulb *llb) {
1177
1178         for (int i = 0; i < 2; i++) {
1179                 llb->turnOff();
1180                 //cout << "Turning off!" << endl;
1181                 this_thread::sleep_for (chrono::milliseconds(1000));
1182                 llb->turnOn();
1183                 //cout << "Turning on!" << endl;
1184                 this_thread::sleep_for (chrono::milliseconds(1000));
1185         }
1186 }
1187
1188
1189 void adjustTemp(LifxLightBulb *llb) {
1190
1191         for (int i = 2500; i < 9000; i += 100) {
1192                 //cout << "Adjusting Temp: " << i << endl;
1193                 llb->setTemperature(i);
1194                 this_thread::sleep_for (chrono::milliseconds(100));
1195         }
1196         //cout << "Adjusted temperature to 9000!" << endl;
1197         for (int i = 9000; i > 2500; i -= 100) {
1198                 //cout << "Adjusting Temp: " << i << endl;
1199                 llb->setTemperature(i);
1200                 this_thread::sleep_for (chrono::milliseconds(100));
1201         }
1202         //cout << "Adjusted temperature to 2500!" << endl;
1203 }
1204
1205
1206 void adjustBright(LifxLightBulb *llb) {
1207         for (int i = 100; i > 0; i -= 10) {
1208                 //cout << "Adjusting Brightness: " << i << endl;
1209                 llb->setColor(llb->getHue(), llb->getSaturation(), i);
1210                 this_thread::sleep_for (chrono::milliseconds(100));
1211         }
1212         //cout << "Adjusted brightness to 0!" << endl;
1213         for (int i = 0; i < 100; i += 10) {
1214                 //cout << "Adjusting Brightness: " << i << endl;
1215                 llb->setColor(llb->getHue(), llb->getSaturation(), i);
1216                 this_thread::sleep_for (chrono::milliseconds(100));
1217         }
1218         //cout << "Adjusting brightness to 100!" << endl;
1219 }
1220
1221
1222 int main(int argc, char *argv[])
1223 {
1224         string macAddress1 = "D073D5128E300000";
1225         //string macAddress = "D073D50241DA0000";
1226         string devIPAddress1 = "192.168.2.126";
1227         //string devIPAddress = "192.168.2.232";
1228         IoTDeviceAddress* devAddress1 = new IoTDeviceAddress(devIPAddress1, 12345, 56700, false, false);
1229         unordered_set<void*>* myset1 = new unordered_set<void*>();
1230         myset1->insert(devAddress1);
1231
1232         IoTSet<void*>* setDevAddress1 = new IoTSet<void*>(myset1);
1233         LifxLightBulb *llb1 = new LifxLightBulb(setDevAddress1, macAddress1);
1234         cout << "Generated LifxLightBulb object!" << endl;
1235         llb1->init();
1236         llb1->turnOn();
1237         onOff(llb1);
1238         adjustTemp(llb1);
1239         adjustBright(llb1);
1240 //      llb->turnOff();
1241
1242 //      delete devAddress1;
1243 //      delete llb1;
1244
1245         return 0;
1246 }