/* Copyright 2009 Virginia Polytechnic Institute and State University Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #include #include #include #include #include #include "vtcross/cbr.h" #include "vtcross/cognitive_engine.h" #include "vtcross/common.h" #include "vtcross/components.h" #include "vtcross/containers.h" #include "vtcross/debug.h" #include "vtcross/error.h" #include "vtcross/socketcomm.h" #define INTERFERENCE 0 #define CHANNEL 1 #define ENERGY 0 #define COMMUNICATION_TIME 1 #define UTILITY 4 static CBR *myCBR; CognitiveEngine::CognitiveEngine() { LOG("Creating Cognitive Engine.\n"); SML_present = false; commandSocketFD = -1; srand ( time(NULL) ); } CognitiveEngine::~CognitiveEngine() { delete myCBR; delete [] pList; delete [] oList; delete [] uList; delete [] radioInfo; } CognitiveEngine::CognitiveEngine(const char *serverName, const char *serverPort, \ const bool SML) { LOG("Creating Cognitive Engine.\n"); pList = new Parameter[10]; oList = new Observable[10]; uList = new Utility[10]; radioInfo = new Radio_Info; ConnectToRemoteComponent(serverName, serverPort, SML); } void CognitiveEngine::SendComponentType() { SendMessage(commandSocketFD, "response_engine_cognitive"); LOG("Cognitive Engine responded to GetRemoteComponentType query.\n"); } void CognitiveEngine::ConnectToRemoteComponent(const char *serverName, \ const char *serverPort, const bool SML) { commandSocketFD = ClientSocket(serverName, serverPort); SML_present = SML; if(SML) { RegisterComponent(); LOG("Cognitive Engine connected to SML at %s.\n", serverName); ReceiveRadioConfiguration(); ReceiveExperience(); RegisterServices(); } else { RegisterComponent(); LOG("Cognitive Engine connected to shell at %s.\n", serverName); ReceiveRadioConfiguration(); ReceiveExperience(); } } void CognitiveEngine::ReceiveFeedback(Observable *observables, Parameter *parameters) { LOG("Cognitive Engine:: Receiving feedback.\n"); uint32_t numberColumns = radioInfo->numParameters; uint32_t obsColumns = radioInfo->numObservables + 1; uint32_t numberTotalColumns = radioInfo->numUtilities + radioInfo->numParameters + radioInfo->numObservables + 1; float valList[numberColumns]; float obsVals[numberColumns]; string nameList[numberColumns]; string obsList[obsColumns]; string searchNames[1]; float searchVals[1]; int searchOps[1]; float returnValues[numberTotalColumns]; size_t columnObsIndex = 0; for (size_t i = 0; i < radioInfo->numObservables; i++){ obsList[columnObsIndex] = observables[i].name; columnObsIndex++; } std::string utility_name = "utility"; obsList[columnObsIndex] = utility_name; size_t columnIndex = 0; for (size_t i = 0; i < radioInfo->numParameters; i++){ nameList[columnIndex] = parameters[i].name; columnIndex++; } size_t obsValueIndex = 0; for(size_t i = 0; i < radioInfo->numObservables; i++) { obsVals[obsValueIndex] = observables[i].value; obsValueIndex++; } /* Make sure we do not return any entries for the current channel */ std::string channel_name = "channel"; searchNames[0] = channel_name; searchOps[0] = 0; searchVals[0] = parameters[0].value; /* Execute CBR search and put output into returnValues */ myCBR->Search(searchNames, searchOps, searchVals, 1, returnValues); /* Calculate Utility */ float oldUtilityValue = returnValues[UTILITY]; // Set DSA utility to take into account both the previously sensed // energy and the average communication time. float newUtilityValue = oldUtilityValue + observables[COMMUNICATION_TIME].value; // If communication time value is set, we know we need to change channels because of PU. // So we should lower the utility for this channel. if((observables[COMMUNICATION_TIME].value != 0) || (observables[ENERGY].value > 1000)) { newUtilityValue = newUtilityValue - 100; } else { newUtilityValue = newUtilityValue + 20; } if(newUtilityValue <= 100) newUtilityValue = 100; obsVals[obsValueIndex] = newUtilityValue; size_t returnValueIndex = 0; for(size_t i = 0; i < radioInfo->numParameters; i++) { valList[returnValueIndex] = parameters[i].value; returnValueIndex++; } myCBR->Update(nameList, obsList, valList, obsVals, numberColumns, obsColumns); } void CognitiveEngine::WaitForSignal() { char buffer[256]; while(true) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); // TODO this is ugly... is there a better way? Doesn't strcmp compare the // whole string? We only need to compare until we find a single different // byte... // // If we send integer op codes rather than strings, this process will be // MUCH faster since instead of donig string compares we can simply // switch on the integer value... if(strcmp(buffer, "update_performance") == 0) { /* Receive Set of current Parameters */ memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); uint32_t numParameters = atoi(buffer); Parameter *p = new Parameter[numParameters]; for(size_t i = 0; i < numParameters; i++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); p[i].name = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); p[i].value = atof(buffer); } /* Receive Set of Observables */ memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); uint32_t numObservables = atoi(buffer); Observable *o = new Observable[numObservables]; for(size_t i = 0; i < numObservables; i++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); o[i].name = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); o[i].value = atof(buffer); } ReceiveFeedback(o,p); delete [] o; delete [] p; } else if(strcmp(buffer, "request_optimization_service") == 0) { // THIS IS CURRENTLY IN DEMO MODE /* Receive Set of Observables */ LOG("\nCognitive Engine:: Receiving service name\n"); memset(buffer, 0, 256); ReadMessage(commandSocketFD,buffer); LOG("\nCognitive Engine:: Got service name, %s\n", buffer); /* Receive Set of Observables */ LOG("\nCognitive Engine:: Receiving Observable Parameters\n"); memset(buffer, 0, 256); ReadMessage(commandSocketFD,buffer); uint32_t numObservables = atoi(buffer); Observable *o = new Observable[numObservables]; for(size_t i = 0; i < numObservables; i++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); o[i].name = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); o[i].value = atof(buffer); } /* Receive Set of current Parameters */ LOG("Cognitive Engine:: Receiving Current Transmission Parameters\n"); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); uint32_t numCurrentParameters = atoi(buffer); Parameter *cp = new Parameter[numCurrentParameters]; for(size_t i = 0; i < numCurrentParameters; i++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); cp[i].name = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); cp[i].value = atof(buffer); } LOG("Cognitive Engine:: Processing parameters....\n"); // TODO need to actually do something with the observables here LOG("Cognitive Engine:: Sending Optimal Parameters to Application.\n"); char numParametersChar[10]; sprintf(numParametersChar, "%i", radioInfo->numParameters); SendMessage(commandSocketFD, numParametersChar); for(size_t i = 0; i < radioInfo->numParameters; i++) { SendMessage(commandSocketFD, "test"); SendMessage(commandSocketFD, "00"); } delete [] o; delete [] cp; } else if(strcmp(buffer, "request_optimization") == 0) { /* Receive Set of Observables */ LOG("\nCognitive Engine:: Receiving Observable Parameters\n"); memset(buffer, 0, 256); ReadMessage(commandSocketFD,buffer); uint32_t numObservables = atoi(buffer); Observable *o = new Observable[numObservables]; for(size_t i = 0; i < numObservables; i++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); o[i].name = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); o[i].value = atof(buffer); } /* Receive Set of current Parameters */ LOG("Cognitive Engine:: Receiving Current Transmission Parameters\n"); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); uint32_t numCurrentParameters = atoi(buffer); Parameter *cp = new Parameter[numCurrentParameters]; for(size_t i = 0; i < numCurrentParameters; i++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); cp[i].name = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); cp[i].value = atof(buffer); } LOG("Cognitive Engine:: Processing parameters....\n"); Parameter *solutionSet; solutionSet = GetSolution(o,cp); // TODO need to actually do something with the observables here LOG("Cognitive Engine:: Sending Optimal Parameters to Application.\n"); char numParametersChar[10]; char solutionValue[50]; sprintf(numParametersChar, "%i", radioInfo->numParameters); SendMessage(commandSocketFD, numParametersChar); for(size_t i = 0; i < radioInfo->numParameters; i++) { SendMessage(commandSocketFD, solutionSet[i].name.c_str()); memset(solutionValue, 0, 50); sprintf(solutionValue, "%f", solutionSet[i].value); SendMessage(commandSocketFD, solutionValue); } delete [] o; delete [] cp; } else if(strcmp(buffer, "query_component_type") == 0) { SendComponentType(); } else if(strcmp(buffer, "connect_sml") == 0) { /* This command implies that we are disconnecting from the shell and * connecting to a SML component. */ char serverName[256]; char serverPort[256]; // TODO is this going to end up being too slow? memset(serverName, 0, 256); memset(serverPort, 0, 256); ReadMessage(commandSocketFD, serverName); ReadMessage(commandSocketFD, serverPort); /* Only continue if we are currently connected to a shell. */ if(!SML_present) { DeregisterComponent(); shutdown(commandSocketFD, 2); close(commandSocketFD); ConnectToRemoteComponent(serverName, serverPort, true); } } else if(strcmp(buffer, "disconnect_sml") == 0) { /* This command implies that we are disconnecting from the SML and * connecting to a shell component. */ char serverName[256]; char serverPort[256]; // TODO is this going to end up being too slow? memset(serverName, 0, 256); memset(serverPort, 0, 256); ReadMessage(commandSocketFD, serverName); ReadMessage(commandSocketFD, serverPort); /* We only want to do this if we are actually connected to an SML * currently. */ if(SML_present) { DeregisterServices(); shutdown(commandSocketFD, 2); close(commandSocketFD); ConnectToRemoteComponent(serverName, serverPort, false); } } else if(strcmp(buffer, "reset_engine_cognitive") == 0) { Reset(); } else if(strcmp(buffer, "shutdown_engine_cognitive") == 0) { Shutdown(); } } } void CognitiveEngine::Shutdown() { if(SML_present) { //DeregisterServices(); DeregisterComponent(); } else { DeregisterComponent(); } // TODO should something else be happening here? } void CognitiveEngine::Reset() { LOG("Resetting Cognitive Engine.\n"); if(SML_present) { DeregisterServices(); DeregisterComponent(); } else { DeregisterComponent(); } } void CognitiveEngine::RegisterComponent() { char buffer[256]; SendMessage(commandSocketFD, "register_engine_cognitive"); LOG("Cognitive Engine:: Registration message sent to shell.\n"); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); } void CognitiveEngine::DeregisterComponent() { SendMessage(commandSocketFD, "deregister_engine_cognitive"); LOG("Cognitive Engine:: Deregistration message sent.\n"); shutdown(commandSocketFD, 2); close(commandSocketFD); commandSocketFD = -1; LOG("Cognitive Engine:: Shell socket closed.\n"); } void CognitiveEngine::RegisterServices() { LOG("Cognitive Engine:: Registering services.\n"); SendMessage(commandSocketFD, "register_service"); SendMessage(commandSocketFD, "test_srv"); SendMessage(commandSocketFD, "register_service"); SendMessage(commandSocketFD, "test_srv1"); SendMessage(commandSocketFD, "register_service"); SendMessage(commandSocketFD, "test_srv2"); SendMessage(commandSocketFD, "register_service"); SendMessage(commandSocketFD, "test_srv3"); } //Combined with deregister component since those two things must happen togeather void CognitiveEngine::DeregisterServices() { LOG("Cognitive Engine:: Deregistering services.\n"); SendMessage(commandSocketFD, "deregister_service"); SendMessage(commandSocketFD, "test_srv"); SendMessage(commandSocketFD, "deregister_service"); SendMessage(commandSocketFD, "test_srv1"); SendMessage(commandSocketFD, "deregister_service"); SendMessage(commandSocketFD, "test_srv2"); SendMessage(commandSocketFD, "deregister_service"); SendMessage(commandSocketFD, "test_srv3"); } void CognitiveEngine::ReceiveRadioConfiguration() { LOG("Cognitive Engine:: Receiving Radio Configuration.\n"); char buffer[256]; /* Receive Set of Utilities */ memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); radioInfo->numUtilities = atoi(buffer); for(size_t i = 0; i < radioInfo->numUtilities; i++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); uList[i].name = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); uList[i].units = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); uList[i].goal = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); uList[i].target = atof(buffer); } /* Receive Set of Parameters */ memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); radioInfo->numParameters = atoi(buffer); for(size_t i = 0; i < radioInfo->numParameters; i++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); pList[i].name = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); pList[i].units = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); pList[i].min = atof(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); pList[i].max = atof(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); pList[i].step = atof(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD,buffer); pList[i].numAffects = atoi(buffer); for(size_t j = 0; j < pList[i].numAffects; j++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD,buffer); // TODO for + if{break} = while? for(size_t k = 0; k < radioInfo->numUtilities; k++) { if(uList[k].name == std::string(buffer)) { pList[i].affection_list[j].u = &uList[k]; break; } } memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); pList[i].affection_list[j].relation = std::string(buffer); } } /* Receive Set of Observables */ memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); radioInfo->numObservables = atoi(buffer); for(size_t i = 0; i < radioInfo->numObservables; i++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); oList[i].name = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); oList[i].numAffects = atoi(buffer); for(size_t j = 0; j < oList[i].numAffects; j++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); // TODO for + if{break} = while? for(size_t k = 0; k < radioInfo->numUtilities; k++) { if(uList[k].name == std::string(buffer)){ oList[i].affection_list[j].u = &uList[k]; break; } } memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); oList[i].affection_list[j].relation = std::string(buffer); } } SendMessage(commandSocketFD, "receive_config_ack"); BuildCognitiveEngine(); } void CognitiveEngine::ReceiveExperience() { LOG("Cognitive Engine:: Receiving Experience Report.\n"); char buffer[256]; uint32_t numberExp; /* Receive number of experience entries */ memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); numberExp = atoi(buffer); LOG("Cognitive Engine:: Waiting for %i number of entries.\n", numberExp); SendMessage(commandSocketFD, "receive_exp_ack"); } /* The core of the CE is this function */ Parameter* CognitiveEngine::GetSolution(Observable *observables, Parameter *currentParameters) { LOG("Cognitive Engine:: Generating solution.\n"); /* Put together the CBR search array */ uint32_t channel = 0; string searchNames[1]; string sumSearchName; float searchVals[1]; float utilArray[(int)pList[0].max]; int searchOps[1]; uint32_t numberColumns = radioInfo->numUtilities + radioInfo->numParameters + \ radioInfo->numObservables + 1; float returnValues[numberColumns]; float sumRetVals[numberColumns]; // Total sum of utilities in sumRetVals[0] string channel_name = "channel"; string utility_name = "utility"; for(int32_t i = 0 ; i < pList[0].max ; i++ ) { searchNames[0] = pList[0].name; searchOps[0] = 0; searchVals[0] = i+1; uint32_t rc = myCBR->Search(searchNames, searchOps, searchVals, 1, returnValues); if(rc == 31337) { // No entry - must add string rowNames[numberColumns]; size_t rowIndex = 0; for(size_t j = 0; j < radioInfo->numUtilities; j++) { rowNames[rowIndex] = uList[j].name; rowIndex++; } for(size_t j = 0; j < radioInfo->numParameters; j++) { rowNames[rowIndex] = pList[j].name; if(pList[j].name == "channel") returnValues[rowIndex] = i+1; rowIndex++; } for(size_t j = 0; j < radioInfo->numObservables; j++) { rowNames[rowIndex] = oList[j].name; rowIndex++; } rowNames[rowIndex] = utility_name; returnValues[rowIndex] = 500; /* Add the new optimized set to the CBR database */ myCBR->AddRow(rowNames, returnValues, numberColumns); } utilArray[i] = returnValues[UTILITY]; } printf("1: %f\t2: %f\t3: %f\t4: %f\n",utilArray[0],utilArray[1],utilArray[2],utilArray[3]); // Get sum of all the channel utilities. sumSearchName = utility_name; uint32_t rc = myCBR->SearchSum(sumSearchName, sumRetVals); // Psuedo random channel selection based upon utility. int k = rand() % (int)sumRetVals[0]; int cdf_total(0); for ( int i = 0; i < pList[0].max; i++ ) { cdf_total += utilArray[i]; if(k < cdf_total) { channel = i + 1; break; } } searchNames[0] = pList[0].name; searchOps[0] = 0; searchVals[0] = channel; rc = myCBR->Search(searchNames, searchOps, searchVals, 1, returnValues); //returnValues[CHANNEL] = rand() % (int)pList[0].max + (int)pList[0].min; returnValues[CHANNEL] = channel; /* Package up the new set of parameters in order to add the new entry into the CBR database. */ size_t returnValueIndex = 0; for(size_t i = 0; i < radioInfo->numUtilities; i++) { uList[i].value = returnValues[returnValueIndex]; returnValueIndex++; } for(size_t i = 0; i < radioInfo->numParameters; i++) { pList[i].value = returnValues[returnValueIndex]; returnValueIndex++; } for(size_t i = 0; i < radioInfo->numObservables; i++) { oList[i].value = returnValues[returnValueIndex]; returnValueIndex++; } //returnValues[returnValueIndex] = 0; string allNames[numberColumns]; size_t allNameIndex = 0; for(size_t i = 0; i < radioInfo->numUtilities; i++) { allNames[allNameIndex] = uList[i].name; returnValues[allNameIndex] = uList[i].target; allNameIndex++; } for(size_t i = 0; i < radioInfo->numParameters; i++) { allNames[allNameIndex] = pList[i].name; allNameIndex++; } for(size_t i = 0; i < radioInfo->numObservables; i++) { allNames[allNameIndex] = oList[i].name; // returnValues[allNameIndex] = 0; allNameIndex++; } allNames[allNameIndex] = utility_name; /* Add the new optimized set to the CBR database */ myCBR->AddRow(allNames, returnValues, returnValueIndex+1); /* Return the set of new parameter values. */ return pList; } Parameter* CognitiveEngine::GetSolution(Observable *observables, \ Parameter *currentParameters, std::string service) { LOG("Cognitive Engine:: Generating solution for %s service.\n", service.c_str()); return pList; } void CognitiveEngine::ReceiveFeedback(Observable *observables, Parameter *parameters, \ std::string service) { LOG("Cognitive Engine:: Receiving feedback.\n"); } void CognitiveEngine::BuildCognitiveEngine() { string filename = "ex1"; string tablename = "data"; uint32_t numberColumns = radioInfo->numUtilities + radioInfo->numParameters + \ radioInfo->numObservables + 1; string cols[numberColumns]; size_t columnIndex = 0; for (size_t i = 0; i < radioInfo->numUtilities; i++){ cols[columnIndex] = uList[i].name; columnIndex++; } string paramCols[radioInfo->numParameters]; size_t paramColumnIndex = 0; // Also need to make parameters the unique key for (size_t i = 0; i < radioInfo->numParameters; i++){ cols[columnIndex] = pList[i].name; paramCols[paramColumnIndex] = pList[i].name; columnIndex++; paramColumnIndex++; } for (size_t i = 0; i < radioInfo->numObservables; i++){ cols[columnIndex] = oList[i].name; columnIndex++; } std::string utility_name = "utility"; cols[columnIndex] = utility_name; myCBR = new CBR(filename, tablename, cols, paramCols, numberColumns, radioInfo->numParameters); }