From 5b47bdc675c2f01526c1581317ade951ac7709cf Mon Sep 17 00:00:00 2001 From: rtrimana Date: Wed, 11 Jan 2017 15:13:22 -0800 Subject: [PATCH] Fixing 2 issues in LifxLightBulb driver: 1) Detached thread handling (need to pass in this pointer for proper class method calls); 2) Extending socket library to have set timeout capability to create non-blocking UDP socket --- .../Cpp/LifxLightBulb/LifxLightBulb.cpp | 78 ++++++++++++++- .../Cpp/LifxLightBulb/LifxLightBulb.hpp | 97 +++++++++++-------- iotjava/iotruntime/cpp/IoTUDP.hpp | 40 ++++++-- iotjava/iotruntime/cpp/socket/Socket.cpp | 45 +++++++++ iotjava/iotruntime/cpp/socket/Socket.hpp | 25 ++++- iotjava/iotruntime/slave/IoTSlave.java | 10 +- 6 files changed, 235 insertions(+), 60 deletions(-) diff --git a/benchmarks/drivers/Cpp/LifxLightBulb/LifxLightBulb.cpp b/benchmarks/drivers/Cpp/LifxLightBulb/LifxLightBulb.cpp index 21b209c..5a53d5e 100644 --- a/benchmarks/drivers/Cpp/LifxLightBulb/LifxLightBulb.cpp +++ b/benchmarks/drivers/Cpp/LifxLightBulb/LifxLightBulb.cpp @@ -1,24 +1,94 @@ #include #include +#include + +#include + #include "LifxLightBulb.hpp" #include "IoTSet.hpp" #include "IoTDeviceAddress.hpp" using namespace std; +void run(LifxLightBulb *llb) { + + llb->init(); +} + + +void *prun(void *llb) { + + ((LifxLightBulb*)llb)->init(); +} + + +void onOff(LifxLightBulb *llb) { + + for (int i = 0; i < 5; i++) { + llb->turnOff(); + cout << "Turning off!" << endl; + this_thread::sleep_for (chrono::milliseconds(1000)); + llb->turnOn(); + cout << "Turning on!" << endl; + this_thread::sleep_for (chrono::milliseconds(1000)); + } +} + + +void adjustTemp(LifxLightBulb *llb) { + + for (int i = 2500; i < 9000; i += 100) { + cout << "Adjusting Temp: " << i << endl; + llb->setTemperature(i); + this_thread::sleep_for (chrono::milliseconds(100)); + } + cout << "Adjusted temperature to 9000!" << endl; + for (int i = 9000; i > 2500; i -= 100) { + cout << "Adjusting Temp: " << i << endl; + llb->setTemperature(i); + this_thread::sleep_for (chrono::milliseconds(100)); + } + cout << "Adjusted temperature to 2500!" << endl; +} + + +void adjustBright(LifxLightBulb *llb) { + for (int i = 100; i > 0; i -= 10) { + cout << "Adjusting Brightness: " << i << endl; + llb->setColor(llb->getHue(), llb->getSaturation(), i); + this_thread::sleep_for (chrono::milliseconds(100)); + } + cout << "Adjusted brightness to 0!" << endl; + for (int i = 0; i < 100; i += 10) { + cout << "Adjusting Brightness: " << i << endl; + llb->setColor(llb->getHue(), llb->getSaturation(), i); + this_thread::sleep_for (chrono::milliseconds(100)); + } + cout << "Adjusting brightness to 100!" << endl; +} + + int main(int argc, char *argv[]) { string macAddress = "D073D5128E300000"; + //string macAddress = "D073D50241DA0000"; string devIPAddress = "192.168.2.126"; - IoTDeviceAddress devAddress(devIPAddress, 12345, 56700, false, false); - unordered_set myset = { devAddress }; + //string devIPAddress = "192.168.2.232"; + //IoTDeviceAddress devAddress(devIPAddress, 12345, 56700, false, false); + IoTDeviceAddress* devAddress = new IoTDeviceAddress(devIPAddress, 12345, 56700, false, false); + unordered_set myset = { devAddress }; - IoTSet setDevAddress(myset); + IoTSet setDevAddress(myset); LifxLightBulb *llb = new LifxLightBulb(setDevAddress, macAddress); llb->init(); - + llb->turnOn(); cout << "Generated LifxLightBulb object!" << endl; + onOff(llb); + adjustTemp(llb); + adjustBright(llb); + llb->turnOff(); + delete devAddress; delete llb; return 0; diff --git a/benchmarks/drivers/Cpp/LifxLightBulb/LifxLightBulb.hpp b/benchmarks/drivers/Cpp/LifxLightBulb/LifxLightBulb.hpp index 489fd54..376e26d 100644 --- a/benchmarks/drivers/Cpp/LifxLightBulb/LifxLightBulb.hpp +++ b/benchmarks/drivers/Cpp/LifxLightBulb/LifxLightBulb.hpp @@ -5,9 +5,11 @@ #include #include #include +#include #include #include +#include #include "LightBulb.hpp" #include "Socket.hpp" @@ -53,7 +55,6 @@ class LifxLightBulb //: public LightBulb //TODO: //static Semaphore socketMutex = new Semaphore(1); bool sendSocketFlag = false; - int64_t lastSentGetBulbVersionRequest = 0; // time last request sent // Current Bulb Values int currentHue = 0; @@ -87,7 +88,7 @@ class LifxLightBulb //: public LightBulb bool stateDidChange = false; // Device address - IoTSet lb_addresses; + IoTSet lb_addresses; public: @@ -120,7 +121,7 @@ class LifxLightBulb //: public LightBulb } - LifxLightBulb(IoTSet _devAddress, string macAddress) { + LifxLightBulb(IoTSet _devAddress, string macAddress) { // Initialize macAddress char tmpMacAddress[16]; @@ -159,35 +160,47 @@ class LifxLightBulb //: public LightBulb if (didAlreadyInit.exchange(true)) return; - unordered_set::const_iterator itr = lb_addresses.begin(); - IoTDeviceAddress deviceAddress = *itr; - cout << "Address: " << deviceAddress.getAddress() << endl; + unordered_set::const_iterator itr = lb_addresses.begin(); + IoTDeviceAddress* deviceAddress = *itr; + cout << "Address: " << deviceAddress->getAddress() << endl; // Create IoTUDP socket communicationSocket = new IoTUDP(deviceAddress); + cout << "Host address: " << communicationSocket->getHostAddress() << endl; + cout << "Source port: " << communicationSocket->getSourcePort() << endl; + cout << "Destination port: " << communicationSocket->getDestinationPort() << endl << endl; + // Launch the worker function in a separate thread. - thread th1 (&LifxLightBulb::workerFunction, this); - th1.join(); + // NOTE: "this" pointer is passed into the detached thread because it does not belong + // to this object anymore so if it executes certain methods of "this" object, then it needs + // the correct references to stuff + thread th1 (&LifxLightBulb::workerFunction, this, this); + th1.detach(); + + cout << "Initialized LifxLightBulb!" << endl; } void turnOff() { - lock_guard guard(bulbStateMutex); + //lock_guard guard(bulbStateMutex); + bulbStateMutex.lock(); bulbIsOn = false; sendSetLightPowerPacket(0, 0); stateDidChange = true; - cout << "Turning off lightbulb!" << endl; + bulbStateMutex.unlock(); } void turnOn() { - lock_guard guard(bulbStateMutex); + //lock_guard guard(bulbStateMutex); + bulbStateMutex.lock(); bulbIsOn = true; sendSetLightPowerPacket(65535, 0); stateDidChange = true; + bulbStateMutex.unlock(); } @@ -361,13 +374,14 @@ class LifxLightBulb //: public LightBulb recHeader.setFromBytes(headerBytes); // load the payload bytes (strip away the header) - char payloadBytes[recHeader.getSize()]; + //char payloadBytes[recHeader.getSize()]; + char* payloadBytes = new char[recHeader.getSize()]; for (int i = 36; i < recHeader.getSize(); i++) { payloadBytes[i - 36] = packetData[i]; } int type = recHeader.getType(); - cout << "Received: " << type; + cout << "Received: " << type << endl; DeviceStateService* dat = NULL; switch (type) { @@ -396,7 +410,8 @@ class LifxLightBulb //: public LightBulb default: cout << "unknown packet Type" << endl; } - + // Avoid memory leaks + delete payloadBytes; } @@ -411,54 +426,54 @@ class LifxLightBulb //: public LightBulb // Worker function which runs the while loop for receiving data from the bulb. // Is blocking. - void workerFunction() { - LifxHeader h; + void workerFunction(LifxLightBulb* llb) { + // Need timeout on receives since we are not sure if a packet will be available // for processing so don't block waiting - // TODO: Check if we can do this here! - //communicationSocket.setSoTimeout(50); + llb->communicationSocket->setTimeOut(50000); // In milliseconds - turnOff(); + llb->turnOff(); - while (true) { + int64_t lastSentGetBulbVersionRequest = 0; // time last request sent + char dat[1024]; + while (true) { // Check if we got the bulb version yet // could have requested it but message could have gotten lost (UDP) - if (!didGetBulbVersion) { + if (!llb->didGetBulbVersion) { int64_t currentTime = (int64_t) time(NULL); - if ((currentTime - lastSentGetBulbVersionRequest) > GET_BULB_VERSION_RESEND_WAIT_SECONDS) { + if ((currentTime - lastSentGetBulbVersionRequest) > llb->GET_BULB_VERSION_RESEND_WAIT_SECONDS) { // Get the bulb version so we know what type of bulb this is. - sendGetVersionPacket(); + cout << "Sending version packet! " << endl; + llb->sendGetVersionPacket(); lastSentGetBulbVersionRequest = currentTime; } } // Communication resource is busy so try again later - if (sendSocketFlag) { + if (llb->sendSocketFlag) { continue; } - socketMutex.lock(); - - char dat[1024]; - int ret = communicationSocket->receiveData(dat, 1024); - + llb->socketMutex.lock(); + int ret = llb->communicationSocket->receiveData(dat, 1024); // Never forget to release! - socketMutex.unlock(); + llb->socketMutex.unlock(); // A packed arrived if (ret != -1) { - receivedPacket(dat); + llb->receivedPacket(dat); } // If a state change occurred then request the bulb state to ensure that the // bulb did indeed change its state to the correct state - if (stateDidChange) { - sendGetLightStatePacket(); + if (llb->stateDidChange) { + llb->sendGetLightStatePacket(); } // Wait a bit as to not tie up system resources this_thread::sleep_for (chrono::milliseconds(100)); + //cout << endl << "Sleep and wake up!" << endl; } } @@ -1067,7 +1082,8 @@ class LifxLightBulb //: public LightBulb for (int i = 0; i < 8; i++) { colorData[i] = payloadData[i]; } - BulbColor color(colorData); + //BulbColor color(colorData); + BulbColor* color = new BulbColor(colorData); int power = ((payloadData[11] & 0xFF) << 8); power |= (payloadData[10] & 0xFF); @@ -1079,7 +1095,7 @@ class LifxLightBulb //: public LightBulb labelArray[i] = payloadData[12 + i]; } - return new LightState(&color, power, label); + return new LightState(color, power, label); } @@ -1146,6 +1162,11 @@ class LifxLightBulb //: public LightBulb BulbColor* color = lightState->getColor(); int power = lightState->getPower(); + //cout << "color->getHue(): " << color->getHue() << " - currentHue: " << currentHue << endl; + //cout << "color->getSaturation(): " << color->getSaturation() << " - currentSaturation: " << currentSaturation << endl; + //cout << "color->getBrightness(): " << color->getBrightness() << " - currentBrightness: " << currentBrightness << endl; + //cout << "color->getKelvin(): " << color->getKelvin() << " - currentTemperature: " << currentTemperature << endl; + bool bulbWrongColor = false; bulbWrongColor = bulbWrongColor || (color->getHue() != currentHue); bulbWrongColor = bulbWrongColor || (color->getSaturation() != currentSaturation); @@ -1159,7 +1180,7 @@ class LifxLightBulb //: public LightBulb if (bulbWrongColor) { BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, currentTemperature); sendSetLightColorPacket(newColor, 250); - // System.out.println("Failed Check 1"); + //cout << "Failed Check 1" << endl; } bulbStateMutex.lock(); @@ -1168,13 +1189,13 @@ class LifxLightBulb //: public LightBulb if ((!bulbIsOnTmp) && (power != 0)) { turnOff(); - // System.out.println("Failed Check 2: " + Integer.toString(power)); + //cout << "Failed Check 2: " << endl; } if (bulbIsOnTmp && (power < 65530)) { turnOn(); - // System.out.println("Failed Check 3: " + Integer.toString(power)); + //cout << "Failed Check 3: " << endl; } // Avoid memory leak - delete object diff --git a/iotjava/iotruntime/cpp/IoTUDP.hpp b/iotjava/iotruntime/cpp/IoTUDP.hpp index 1c46ffa..d712d4b 100644 --- a/iotjava/iotruntime/cpp/IoTUDP.hpp +++ b/iotjava/iotruntime/cpp/IoTUDP.hpp @@ -17,20 +17,22 @@ class IoTUDP { // IoTUDP class properties private: + UDPSocket *socket; string strHostAddress; int iSrcPort; int iDstPort; - UDPSocket *socket; bool didClose; + int timeOut; public: // Constructor - IoTUDP(IoTDeviceAddress iotDevAdd) { + IoTUDP(IoTDeviceAddress* iotDevAdd) { - strHostAddress = iotDevAdd.getAddress(); - iSrcPort = iotDevAdd.getSourcePortNumber(); - iDstPort = iotDevAdd.getDestinationPortNumber(); + strHostAddress = iotDevAdd->getAddress(); + iSrcPort = iotDevAdd->getSourcePortNumber(); + iDstPort = iotDevAdd->getDestinationPortNumber(); + timeOut = 0; socket = new UDPSocket(iSrcPort); if (socket == NULL) { @@ -50,19 +52,39 @@ class IoTUDP } + string getHostAddress() { + return strHostAddress; + } + + + int getSourcePort() { + return iSrcPort; + } + + + int getDestinationPort() { + return iDstPort; + } + + + void setTimeOut(int interval) { + + timeOut = interval; + } + + // Send data packet void sendData(const void* buffer, int bufferLen) { - - unsigned short destinationPort = (unsigned short) iDstPort; + unsigned short destinationPort = (unsigned short) iDstPort; socket->sendTo(buffer, bufferLen, strHostAddress, destinationPort); } // Receive data packet int receiveData(void* buffer, int iMaxDataLength) { - unsigned short destinationPort = (unsigned short) iDstPort; - return socket->recvFrom(buffer, iMaxDataLength, strHostAddress, destinationPort); + //return socket->recvFrom(buffer, iMaxDataLength, strHostAddress, destinationPort); + return socket->recvFrom(buffer, iMaxDataLength, strHostAddress, destinationPort, timeOut); } }; #endif diff --git a/iotjava/iotruntime/cpp/socket/Socket.cpp b/iotjava/iotruntime/cpp/socket/Socket.cpp index ceac82b..667411a 100644 --- a/iotjava/iotruntime/cpp/socket/Socket.cpp +++ b/iotjava/iotruntime/cpp/socket/Socket.cpp @@ -27,6 +27,7 @@ typedef char raw_type; // Type used for raw data on this platform #else #include // For data types + #include // For select() - non-blocking socket #include // For socket(), connect(), send(), and recv() #include // For gethostbyname() #include // For inet_addr() @@ -37,6 +38,7 @@ #include // For errno #include // For memset +#include // For fcntl using namespace std; @@ -351,6 +353,38 @@ int UDPSocket::recvFrom(void *buffer, int bufferLen, string &sourceAddress, return rtn; } +int UDPSocket::recvFrom(void *buffer, int bufferLen, string &sourceAddress, + unsigned short &sourcePort, int timeOut) throw(SocketException) { + + if(!(fcntl(sockDesc, F_GETFL) & O_NONBLOCK)) { + // If not non-blocking then put it into non-blocking + if(fcntl(sockDesc, F_SETFL, fcntl(sockDesc, F_GETFL) | O_NONBLOCK) < 0) { + throw SocketException("Set non-blocking failed (recvfrom())", true); + } + } + fd_set readFds; // FD + FD_ZERO(&readFds); + FD_SET(sockDesc, &readFds); + struct timeval to; // timeout + to.tv_sec = 0; + to.tv_usec = timeOut; + sockaddr_in clntAddr; + socklen_t addrLen = sizeof(clntAddr); + + int rv = select(sockDesc+1 ,&readFds, NULL, NULL, &to); + int rtn = -1; // Assuming receive failure + if (rv == 1) { + if ((rtn = recvfrom(sockDesc, (raw_type *) buffer, bufferLen, 0, + (sockaddr *) &clntAddr, (socklen_t *) &addrLen)) < 0) { + throw SocketException("Receive failed (recvfrom())", true); + } + sourceAddress = inet_ntoa(clntAddr.sin_addr); + sourcePort = ntohs(clntAddr.sin_port); + } + + return rtn; +} + void UDPSocket::setMulticastTTL(unsigned char multicastTTL) throw(SocketException) { if (setsockopt(sockDesc, IPPROTO_IP, IP_MULTICAST_TTL, (raw_type *) &multicastTTL, sizeof(multicastTTL)) < 0) { @@ -381,3 +415,14 @@ void UDPSocket::leaveGroup(const string &multicastGroup) throw(SocketException) throw SocketException("Multicast group leave failed (setsockopt())", true); } } + +void UDPSocket::setTimeOut(int interval) throw(SocketException) { + + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = interval; + if (setsockopt(sockDesc, SOL_SOCKET, SO_RCVTIMEO, &timeout, + sizeof(timeout)) < 0) { + throw SocketException("Multicast group join failed (setsockopt())", true); + } +} diff --git a/iotjava/iotruntime/cpp/socket/Socket.hpp b/iotjava/iotruntime/cpp/socket/Socket.hpp index 9da627a..d01c9bb 100644 --- a/iotjava/iotruntime/cpp/socket/Socket.hpp +++ b/iotjava/iotruntime/cpp/socket/Socket.hpp @@ -86,7 +86,7 @@ public: */ void setLocalPort(unsigned short localPort) throw(SocketException); - /** + /** ADDED BY: Rahmadi Trimananda (rtrimana@uci.edu) * Set the local port to the specified port and the local address * to the specified address. If you omit the port, a random port * will be selected. @@ -301,7 +301,7 @@ public: /** * Read read up to bufferLen bytes data from this socket. The given buffer - * is where the data will be placed + * is where the data will be placed (this is a non-blocking version) * @param buffer buffer to receive data * @param bufferLen maximum number of bytes to receive * @param sourceAddress address of datagram source @@ -312,6 +312,20 @@ public: int recvFrom(void *buffer, int bufferLen, string &sourceAddress, unsigned short &sourcePort) throw(SocketException); + /** + * Read read up to bufferLen bytes data from this socket. The given buffer + * is where the data will be placed + * @param buffer buffer to receive data + * @param bufferLen maximum number of bytes to receive + * @param sourceAddress address of datagram source + * @param sourcePort port of data source + * @param timeout interval + * @return number of bytes received and -1 for error + * @exception SocketException thrown if unable to receive datagram + */ + int recvFrom(void *buffer, int bufferLen, string &sourceAddress, + unsigned short &sourcePort, int timeout) throw(SocketException); + /** * Set the multicast TTL * @param multicastTTL multicast TTL @@ -333,6 +347,13 @@ public: */ void leaveGroup(const string &multicastGroup) throw(SocketException); + /** ADDED BY: Rahmadi Trimananda (rtrimana@uci.edu) + * Set timeout for socket + * @param timeout interval (in milliseconds) + * @exception SocketException thrown if unable to set timeout + */ + void setTimeOut(int interval) throw(SocketException); + private: void setBroadcast(); }; diff --git a/iotjava/iotruntime/slave/IoTSlave.java b/iotjava/iotruntime/slave/IoTSlave.java index 0adbefe..dec974f 100644 --- a/iotjava/iotruntime/slave/IoTSlave.java +++ b/iotjava/iotruntime/slave/IoTSlave.java @@ -694,11 +694,7 @@ public class IoTSlave { // TODO: DEBUG System.out.println("\n\nDEBUG: GET ZIGBEE DEVICE IOT SET OBJECT!!!"); - System.out.println("DEBUG: sMessage host address: " + sMessage.getHostAddress()); - System.out.println("DEBUG: sMessage source port: " + sMessage.getSourceDeviceDriverPort()); - System.out.println("DEBUG: sMessage destination port: " + sMessage.getDestinationDeviceDriverPort()); - System.out.println("DEBUG: sMessage source wild card: " + sMessage.isSourcePortWildCard()); - System.out.println("DEBUG: sMessage desination wild card: " + sMessage.isDestinationPortWildCard() + "\n\n"); + System.out.println("DEBUG: sMessage host address: " + sMessage.getHostAddress() + "\n\n"); // Get IoTSet objects for IP address set on device driver/controller IoTZigbeeAddress objZBDevAddress = new IoTZigbeeAddress(sMessage.getHostAddress()); @@ -725,7 +721,7 @@ public class IoTSlave { // TODO: DEBUG System.out.println("\n\nDEBUG: GET ADD IOT SET OBJECT!!!"); - System.out.println("DEBUG: sMessage host address: " + sMessage.getHostAddress() +); + System.out.println("DEBUG: sMessage host address: " + sMessage.getHostAddress() + "\n\n"); // Get IoTSet objects for IP address set on device driver/controller IoTAddress objAddress = new IoTAddress(sMessage.getHostAddress()); @@ -746,7 +742,7 @@ public class IoTSlave { private void invokeInitMethod() throws IOException { // TODO: DEBUG - System.out.println("\n\nDEBUG: INVOKE INIT METHOD!!!"); + System.out.println("\n\nDEBUG: INVOKE INIT METHOD!!!\n\n"); new Thread() { public void run() { -- 2.34.1