corobot_analyzer.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2009, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the Willow Garage nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *********************************************************************/
00034 
00035 // This Analyzer is a modifyed version of the GenericAnalyzer
00036 
00037 
00038 #include "corobot_diagnostics/corobot_analyzer.h"
00039 
00040 
00041 PLUGINLIB_EXPORT_CLASS(diagnostic_aggregator::CorobotAnalyzer, 
00042                         diagnostic_aggregator::Analyzer)
00043 
00044 using namespace diagnostic_aggregator;
00045 using namespace std;
00046 
00047 CorobotAnalyzer::CorobotAnalyzer() { }
00048 
00049 bool CorobotAnalyzer::init(const string base_path, const ros::NodeHandle &n)
00050 { 
00051 
00052   ros::NodeHandle nh;
00053   newError_pub = nh.advertise<std_msgs::String>("new_diagnostic_error", 1000);
00054   removeError_pub = nh.advertise<std_msgs::String>("remove_diagnostic_error", 1000);
00055 
00056   string nice_name;
00057   if (!n.getParam("path", nice_name))
00058   {
00059     ROS_ERROR("GenericAnalyzer was not given parameter \"path\". Namepspace: %s",
00060               n.getNamespace().c_str());
00061     return false;
00062   }
00063 
00064   XmlRpc::XmlRpcValue findRemove;
00065   if (n.getParam("find_and_remove_prefix", findRemove))
00066   {
00067     vector<string> output;
00068     getParamVals(findRemove, output);
00069     chaff_ = output;
00070     startswith_ = output;
00071   }
00072   
00073   XmlRpc::XmlRpcValue removes;
00074   if (n.getParam("remove_prefix", removes))
00075     getParamVals(removes, chaff_);
00076     
00077   XmlRpc::XmlRpcValue startswith;
00078   if (n.getParam("startswith", startswith))
00079     getParamVals(startswith, startswith_);
00080 
00081   XmlRpc::XmlRpcValue name_val;
00082   if (n.getParam("name", name_val))
00083     getParamVals(name_val, name_);
00084 
00085   XmlRpc::XmlRpcValue contains;
00086   if (n.getParam("contains", contains))
00087     getParamVals(contains, contains_);
00088 
00089   XmlRpc::XmlRpcValue expected;
00090   if (n.getParam("expected", expected))
00091   {
00092     getParamVals(expected, expected_);
00093     for (unsigned int i = 0; i < expected_.size(); ++i)
00094     {
00095       boost::shared_ptr<StatusItem> item(new StatusItem(expected_[i]));
00096       addItem(expected_[i], item);
00097     }
00098  }
00099  
00100   XmlRpc::XmlRpcValue regexes;
00101   if (n.getParam("regex", regexes))
00102   {
00103     vector<string> regex_strs;
00104     getParamVals(regexes, regex_strs);
00105   
00106     for (unsigned int i = 0; i < regex_strs.size(); ++i)
00107     {
00108       try
00109       {
00110         boost::regex re(regex_strs[i]);
00111         regex_.push_back(re);
00112       }
00113       catch (boost::regex_error& e)
00114       {
00115         ROS_ERROR("Attempted to make regex from %s. Caught exception, ignoring value. Exception: %s", 
00116                  regex_strs[i].c_str(), e.what());
00117       }
00118     }
00119   }
00120 
00121   if (startswith_.size() == 0 && name_.size() == 0 && 
00122       contains_.size() == 0 && expected_.size() == 0 && regex_.size() == 0)
00123   {
00124     ROS_ERROR("CorobotAnalyzer was not initialized with any way of checking diagnostics. Name: %s, namespace: %s", nice_name.c_str(), n.getNamespace().c_str());
00125     return false;
00126   }
00127   
00128   double timeout;
00129   int num_items_expected;
00130   bool discard_stale;
00131   n.param("timeout", timeout, 5.0);   // Timeout for stale
00132   n.param("num_items", num_items_expected, -1); // Number of items must match this
00133   n.param("discard_stale", discard_stale, false);
00134   
00135   
00136   string my_path;
00137   if (base_path == "/")
00138     my_path = nice_name;
00139   else
00140     my_path = base_path + "/" + nice_name;
00141 
00142   if (my_path.find("/") != 0)
00143     my_path = "/" + my_path;
00144 
00145 
00146   return GenericAnalyzerBase::init(my_path, nice_name, 
00147                                    timeout, num_items_expected, discard_stale);
00148 }
00149 
00150 CorobotAnalyzer::~CorobotAnalyzer() 
00151 { 
00152 
00153 }
00154 
00155 
00156 bool CorobotAnalyzer::match(const string name)
00157 {
00158   boost::cmatch what;
00159   for (unsigned int i = 0; i < regex_.size(); ++i)
00160   {
00161     if (boost::regex_match(name.c_str(), what, regex_[i]))
00162       return true;
00163   }
00164   
00165   for (unsigned int i = 0; i < expected_.size(); ++i)
00166   {
00167     if (name == expected_[i])
00168       return true;
00169   }
00170   
00171   for (unsigned int i = 0; i < name_.size(); ++i)
00172   {
00173     if (name == name_[i])
00174       return true;
00175   }
00176   
00177   for (unsigned int i = 0; i < startswith_.size(); ++i)
00178   {
00179     if (name.find(startswith_[i]) == 0)
00180       return true;
00181   }
00182   
00183   for (unsigned int i = 0; i < contains_.size(); ++i)
00184   {
00185     if (name.find(contains_[i]) != string::npos)
00186       return true;
00187   }
00188   
00189   return false;
00190 }
00191 
00192 void CorobotAnalyzer::processLCD(boost::shared_ptr<diagnostic_msgs::DiagnosticStatus> processed)
00193 // This function analyze one of the diagnostic messages, figures out if something needs to be displayed on the LCD and if so displays it. It also finds out if a displayed message needs to be removed
00194 {
00195     std::string error;
00196 
00197     if (processed->level > 0)
00198     {
00199         for (unsigned int k = 0; k < processed->values.size(); ++k)
00200         {
00201             // Check if the process has a Recommendation key, which means that we have to display it on the LCD as it indicates an error        
00202           if(processed->values[k].key == "Recommendation") 
00203               {
00204                 error = processed->values[k].value;
00205               }
00206         }
00207     }
00208     if (processed->level == 3) // The process is stalled, we need to write it on the lcd
00209     {
00210         // We need to send an error message to the LCD saying that this process is staled
00211         error = processed->name + std::string(" is stalled");
00212     }
00213 
00214     // Check if the process has been updated if so we remove the previous error message concerning the process if it exist
00215     for (int i=0; i < processErrorsList.size(); i++)
00216     {
00217         if (processErrorsList.at(i).processName.compare(processed->name) == 0 && (processErrorsList.at(i).level != processed->level || error.compare(processErrorsList.at(i).error) != 0))
00218         {
00219             // Remove the previous message from the LCD list
00220             std_msgs::String msg;
00221             msg.data = processErrorsList.at(i).error;
00222             if(removeError_pub)
00223                 removeError_pub.publish(msg);
00224             // We also need to remove our local list
00225             processErrorsList.erase(processErrorsList.begin()+i);
00226         }
00227     }
00228     int k;
00229     for (k=0; k < processErrorsList.size(); k++)
00230     // We need to check if an error message has already been save concerning the current process
00231     {
00232         if (processErrorsList.at(k).processName.compare(processed->name) == 0)
00233             break;
00234     }
00235 
00236         //If no error message exist regarding the process, and if the process has an error we need to add the new error message to the error list
00237     if (processed->level != 0 && k==processErrorsList.size() && error.size() != 0 && newError_pub.getNumSubscribers() > 0)
00238     {
00239         struct processErrors perr;
00240         perr.error = error;
00241         perr.level = processed->level;
00242         perr.processName = processed->name;
00243         processErrorsList.push_back(perr);
00244 
00245             std_msgs::String msg;
00246         msg.data = error;
00247             if(newError_pub)
00248                 newError_pub.publish(msg);
00249     }
00250 
00251 }
00252 
00253 
00254 vector<boost::shared_ptr<diagnostic_msgs::DiagnosticStatus> > CorobotAnalyzer::report()
00255 {
00256   vector<boost::shared_ptr<diagnostic_msgs::DiagnosticStatus> > processed = GenericAnalyzerBase::report();
00257 
00258   
00259   // Process the data to display on the LCD only what is necessary
00260   for (unsigned int j = 0; j < processed.size(); ++j)
00261   {
00262        processLCD(processed[j]);
00263  
00264   }
00265 
00266   // Check and make sure our expected names haven't been removed ...
00267   vector<string> expected_names_missing;
00268   bool has_name = false;
00269   bool all_stale = true;
00270   
00271   for (unsigned int i = 0; i < expected_.size(); ++i)
00272   {
00273     has_name = false;
00274     for (unsigned int j = 0; j < processed.size(); ++j)
00275     {
00276       if (!processed[j]->level == 3)
00277         all_stale = false;
00278 
00279       size_t last_slash = processed[j]->name.rfind("/");
00280       string nice_name = processed[j]->name.substr(last_slash + 1);
00281       if (nice_name == expected_[i] || nice_name == getOutputName(expected_[i]))
00282       {
00283         has_name = true;
00284         break;
00285       }
00286 
00287       // Remove chaff, check names
00288       for (unsigned int k = 0; k < chaff_.size(); ++k)
00289       {     
00290         if (nice_name == removeLeadingNameChaff(expected_[i], chaff_[k]))
00291         {
00292           has_name = true;
00293           break;
00294         }
00295       }
00296 
00297     }
00298     if (!has_name)
00299       expected_names_missing.push_back(expected_[i]);
00300   }  
00301 
00302   // Add missing names to header ...
00303   for (unsigned int i = 0; i < expected_names_missing.size(); ++i)
00304   {
00305     boost::shared_ptr<StatusItem> item(new StatusItem(expected_names_missing[i]));
00306     processed.push_back(item->toStatusMsg(path_, true));
00307   } 
00308 
00309   // Check that all processed items aren't stale
00310   for (unsigned int j = 0; j < processed.size(); ++j)
00311   {
00312     if (processed[j]->level != 3)
00313       all_stale = false;
00314   
00315   }
00316 
00317   for (unsigned int j = 0; j < processed.size(); ++j)
00318   {
00319     // Remove all leading name chaff
00320     for (unsigned int i = 0; i < chaff_.size(); ++i)
00321       processed[j]->name = removeLeadingNameChaff(processed[j]->name, chaff_[i]);
00322 
00323     // If we're missing any items, set the header status to error or stale
00324     if (expected_names_missing.size() > 0 && processed[j]->name == path_)
00325     {
00326       if (!all_stale)
00327       {
00328         processed[j]->level = 2;
00329         processed[j]->message = "Error";
00330       }
00331       else
00332       {
00333         processed[j]->level = 3;
00334         processed[j]->message = "All Stale";
00335       }
00336 
00337       // Add all missing items to header item
00338       for (unsigned int k = 0; k < expected_names_missing.size(); ++k)
00339       {
00340         diagnostic_msgs::KeyValue kv;
00341         kv.key = expected_names_missing[k];
00342         kv.value = "Missing";
00343         processed[j]->values.push_back(kv);
00344       }
00345     }
00346   }
00347   
00348   return processed;
00349 }
00350 


corobot_diagnostics
Author(s):
autogenerated on Wed Aug 26 2015 11:09:34