00001 /* 00002 * ScriptHost.cpp 00003 * 00004 * Created on: Oct 27, 2013 00005 * Author: blackpc 00006 */ 00007 00008 #include <scriptable_monitor/ScriptHost.h> 00009 00010 ScriptHost::ScriptHost() 00011 { 00012 _executionInterval = 0.1; 00013 RosTopicListener::start(); 00014 } 00015 00016 ScriptHost::~ScriptHost() 00017 { 00018 stop(); 00019 RosTopicListener::stop(); 00020 } 00021 00022 AddScriptResponse ScriptHost::addScript(string sourceCode) 00023 { 00024 lock_recursive(_scriptsMutex); 00025 AddScriptResponse response; 00026 response.message = ""; 00027 00028 set<string> internalFunctions; 00029 foreach (string functionName, InternalFunctionsManager::getFunctionNames()) { 00030 internalFunctions.insert(functionName); 00031 } 00032 00036 PredicatesScript predicateScript(sourceCode, internalFunctions); 00037 if (predicateScript.getName() == "") { 00038 cerr << "[e] Unnamed script provided, cannot add to ScriptHost" << endl; 00039 response.message = "[e] Unnamed script provided, cannot add to ScriptHost"; 00040 response.success = false; 00041 return response; 00042 } 00043 00044 if (scriptExists(predicateScript.getName())) { 00045 cerr << "[e] Script with the same name already exists" << endl; 00046 response.message = "[e] Script with the same name already exists"; 00047 response.success = false; 00048 return response; 00049 } 00050 00054 PythonScript* pythonScript = new PythonScript(predicateScript.getPythonScript()); 00055 bool validScript = prepareScript(*pythonScript); 00056 00057 if (validScript) 00058 _scripts.insert(boost::shared_ptr<PythonScript>(pythonScript)); 00059 else { 00060 cerr << "[e] Invalid script" << endl; 00061 response.message = "[e] Invalid script"; 00062 response.success = false; 00063 return response; 00064 } 00065 00069 foreach (string topicName, pythonScript->getUsedTopics()) { 00070 RosTopicListener::addTopic(topicName); 00071 } 00072 00073 cout << "[+] Script added [" << pythonScript->getName() << "]" << endl; 00074 response.message = "[+] Script added"; 00075 response.success = true; 00076 return response; 00077 } 00078 00079 bool ScriptHost::prepareScript(PythonScript& script) 00080 { 00081 CompilationResult result = _executer.compile(script); 00082 if (!result.success) { 00083 cerr << "[e] Compilation of script '" << script.getName() << "' failed" << endl; 00084 cerr << "[e] Message: " << result.message << endl; 00085 return false; 00086 } 00087 00091 _executer.simulate(script); 00092 00093 return true; 00094 } 00095 00096 void ScriptHost::run() 00097 { 00098 while (!_workThread->interruption_requested()) { 00099 00100 { 00101 lock_recursive(_scriptsMutex); 00102 foreach (PythonScriptPtr script, _scripts) { 00103 00104 if (!isExecutionTime(script)) 00105 continue; 00106 00107 if (!hasAllTopicValues(script)) 00108 continue; 00109 00110 // cout << "[i] Time to execute '" << script->getName() << "'" << endl; 00111 _executer.execute(*script, RosTopicListener::getTopicsValues()); 00112 script->updateExecutionTime(); 00113 00114 // cout << "[i] Validations: " << (script->isValidationFailed() ? "FAILED [" + script->getFailedValidation() + "]" : "PASSED") << endl; 00115 00116 addDiagnosticStatus(script); 00117 00118 } 00119 } 00120 00121 boost::this_thread::sleep(boost::posix_time::milliseconds(1000.0 * _executionInterval)); 00122 } 00123 } 00124 00125 void ScriptHost::start() 00126 { 00127 RosTopicListener::start(); 00128 00129 if (!_workThread) 00130 _workThread = boost::shared_ptr<boost::thread>( 00131 new boost::thread(boost::bind(&ScriptHost::run, this))); 00132 } 00133 00134 void ScriptHost::stop() 00135 { 00136 ROS_INFO("Stopping ScriptHost..."); 00137 _workThread->interrupt(); 00138 _workThread->join(); 00139 } 00140 00141 bool ScriptHost::isExecutionTime(PythonScriptPtr script) 00142 { 00143 boost::posix_time::ptime nowTime = boost::posix_time::microsec_clock::local_time(); 00144 boost::posix_time::ptime nextExecutionTime 00145 = script->getExecutionTime() + boost::posix_time::time_duration(boost::posix_time::milliseconds(1000.0 * script->getInterval())); 00146 00147 return nowTime > nextExecutionTime; 00148 } 00149 00150 void ScriptHost::deleteScript(string scriptName) 00151 { 00152 lock_recursive(_scriptsMutex); 00153 00154 PythonScriptPtr script = getScript(scriptName); 00155 00156 if (!scriptExists(scriptName)) 00157 return; 00158 00159 _scripts.erase(script); 00160 } 00161 00162 void ScriptHost::addDiagnosticStatus(PythonScriptPtr script) 00163 { 00164 lock_recursive(_statusesMutex); 00165 00166 DiagnosticStatusPtr status(new diagnostic_msgs::DiagnosticStatus()); 00167 00168 status->name = script->getName(); 00169 status->hardware_id = script->getParameter("hardware_id"); 00170 00171 if (script->isValidationFailed()) { 00172 status->level = (int8_t)script->getFailType(); 00173 } 00174 else 00175 status->level = diagnostic_msgs::DiagnosticStatus::OK; 00176 00177 status->message = script->isValidationFailed() ? "Validation failed: " + script->getFailedValidation() : "Fine";; 00178 00179 _diagnosticStatuses.push_back(status); 00180 } 00181 00182 vector<DiagnosticStatusPtr> ScriptHost::getDiagnosticStatusesAndClear() 00183 { 00184 lock_recursive(_statusesMutex); 00185 00186 vector<DiagnosticStatusPtr> statuses = _diagnosticStatuses; 00187 _diagnosticStatuses.clear(); 00188 return statuses; 00189 } 00190 00191 set<PythonScriptPtr> ScriptHost::getScripts() 00192 { 00193 lock_recursive(_scriptsMutex); 00194 return _scripts; 00195 } 00196 00197 PythonScriptPtr ScriptHost::getScript(string scriptName) 00198 { 00199 lock_recursive(_scriptsMutex); 00200 00201 for(std::set<PythonScriptPtr>::iterator it = _scripts.begin(); it != _scripts.end(); it++) { 00202 if ((*it)->getName() == scriptName) 00203 return (*it); 00204 } 00205 00206 return PythonScriptPtr(); 00207 } 00208 00209 bool ScriptHost::hasAllTopicValues(PythonScriptPtr script) 00210 { 00211 foreach(string topicName, script->getUsedTopics()) { 00212 if (!RosTopicListener::hasTopicValue(topicName)) 00213 return false; 00214 } 00215 00216 return true; 00217 } 00218 00219 bool ScriptHost::scriptExists(string scriptName) 00220 { 00221 lock_recursive(_scriptsMutex); 00222 return !(!getScript(scriptName)); 00223 }