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