Note: Goby version 1 (shown here) is now considered obsolete. Please use version 2 for new projects, and consider upgrading old projects.

Goby Underwater Autonomy Project  Series: 1.1, revision: 163, released on 2013-02-06 14:23:27 -0500
acomms/libdccl/message_publish.cpp
00001 // copyright 2008, 2009 t. schneider tes@mit.edu
00002 // 
00003 // this file is part of the Dynamic Compact Control Language (DCCL),
00004 // the goby-acomms codec. goby-acomms is a collection of libraries 
00005 // for acoustic underwater networking
00006 //
00007 // This program is free software: you can redistribute it and/or modify
00008 // it under the terms of the GNU General Public License as published by
00009 // the Free Software Foundation, either version 3 of the License, or
00010 // (at your option) any later version.
00011 //
00012 // This software is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU General Public License
00018 // along with this software.  If not, see <http://www.gnu.org/licenses/>.
00019 
00020 #include <boost/foreach.hpp>
00021 
00022 #include "message_publish.h"
00023 #include "dccl_exception.h"
00024 #include "message.h"
00025 
00026 using goby::acomms::NaN;
00027 
00028 void goby::acomms::DCCLPublish::initialize(const DCCLMessage& msg)
00029 {
00030     repeat_ = msg.repeat();
00031 
00032     // check and add all publish names grabbed by the xml parser
00033     BOOST_FOREACH(const std::string& name, names_)
00034         add_message_var(msg.name2message_var(name));
00035 
00036 
00037     BOOST_FOREACH(const std::vector<std::string>& algs, algorithms_)
00038     {
00039         BOOST_FOREACH(const std::string& alg, algs)
00040             ap_->check_algorithm(alg, msg);
00041     }
00042     
00043     
00044     // add names for any <all/> publishes and empty std::vector for algorithms
00045     if(use_all_names_)
00046     {
00047         BOOST_FOREACH(const boost::shared_ptr<DCCLMessageVar> mv, msg.header_const())
00048         {
00049             // ignore header pieces not explicitly overloaded by the <name> tag
00050             if(!mv->name().empty() && !(mv->name()[0] == '_') &&
00051                !std::count(names_.begin(), names_.end(), mv->name()))
00052             {
00053                 add_message_var(mv);
00054                 // add an empty std::vector for algorithms (no algorithms allowed for <all/> tag)
00055                 add_algorithms(std::vector<std::string>());
00056             }
00057         }
00058         
00059         BOOST_FOREACH(const boost::shared_ptr<DCCLMessageVar> mv, msg.layout_const())
00060         {
00061             if(!std::count(names_.begin(), names_.end(), mv->name()))
00062             {
00063                 add_message_var(mv);
00064                 // add an empty std::vector for algorithms (no algorithms allowed for <all/> tag)
00065                 add_algorithms(std::vector<std::string>());
00066             }
00067         }
00068     }
00069     
00070     int format_count = 0;
00071     // add format if publish doesn't have one  
00072     if(!format_set_)
00073     {
00074         std::string format_str;
00075         for (std::vector<boost::shared_ptr<DCCLMessageVar> >::size_type j = 0, m = message_vars_.size(); j < m; ++j)
00076         {
00077             if (m > 1)
00078             {
00079                 if (j)
00080                     format_str += ",";
00081                 
00082                 // allows you to use the same message var twice but gives a unique name based on the algorithms used
00083                 unsigned size = algorithms_[j].size();
00084                 if(count(message_vars_.begin(), message_vars_.end(), message_vars_[j]) > 1 && size )
00085                 {
00086                     for(unsigned i = 0; i < size; ++i)
00087                         format_str += algorithms_[j][i];
00088                             
00089                     format_str += "(" + message_vars_[j]->name() + ")=";
00090                 }
00091                 else
00092                     format_str += message_vars_[j]->name() + "=";           
00093             }
00094             
00095             for(unsigned i = 0,
00096                     n = (repeat_ > 1) ? 1 : message_vars_[j]->array_length();
00097                 i < n;
00098                 ++i)
00099             {                
00100                 ++format_count;
00101                 std::stringstream ss;
00102 
00103                 if(m > 1 && n > 1 && i == 0) ss << "{";
00104                 if(i) ss << ",";
00105                 
00106                 ss << "%" << format_count << "%";
00107 
00108                 if(m > 1 && n > 1 && i+1 == n) ss << "}";
00109                 format_str += ss.str();
00110             }
00111         }
00112         format_ = format_str;
00113     } 
00114 }
00115 
00116 
00117 void goby::acomms::DCCLPublish::fill_format(const std::map<std::string,std::vector<DCCLMessageVal> >& vals,
00118                                             std::string& key,
00119                                             std::string& value,
00120                                             unsigned repeat_index)
00121 {
00122     std::string filled_value;
00123     // format is a boost library class for replacing printf and its ilk
00124     boost::format f;
00125     
00126     // tack on the dest variable with a space separator (no space allowed in dest var
00127     // so we can use format on that too
00128     std::string input_format = var_ + " " + format_;
00129 
00130     try
00131     {            
00132         f.parse(input_format);
00133             
00134         // iterate over the message_vars and fill in the format field
00135         for (std::vector<boost::shared_ptr<DCCLMessageVar> >::size_type k = 0, o = message_vars_.size(); k < o; ++k)
00136         {
00137             std::vector<DCCLMessageVal> vm = vals.find(message_vars_[k]->name())->second;
00138             for(std::vector<DCCLMessageVal>::size_type i = (repeat_ > 1) ? repeat_index : 0,
00139                     n = (repeat_ > 1) ? repeat_index + 1 : vm.size();
00140                 i < n;
00141                 ++i)
00142             {
00143                 // special case when repeating and variable has a single entry, repeat
00144                 // that entry over all the publishes (this is used for the header
00145                 std::vector<DCCLMessageVal>::size_type eff_index = (repeat_ > 1 && vm.size() == 1) ? 0 : i;
00146                 
00147                 std::vector<std::string>::size_type num_algs = algorithms_[k].size();
00148 
00149                 // only run algorithms once on a given variable
00150                 for(std::vector<std::string>::size_type l = 0; l < num_algs; ++l)
00151                     ap_->algorithm(vm[eff_index], i, algorithms_[k][l], vals);
00152                 
00153                 std::string s =  vm[eff_index];
00154                 f % s;
00155             }
00156         }
00157 
00158         filled_value = f.str();
00159     }
00160     catch (std::exception& e)
00161     {
00162         throw DCCLException(std::string(e.what() + (std::string)"\n decode failed. check format string for this <publish />: \n" + get_display()));
00163     }
00164 
00165     // split filled_value back into variable and value
00166     std::vector<std::string> split_vec;
00167     boost::split(split_vec, filled_value, boost::is_any_of(" "));
00168         
00169     key = split_vec.at(0);
00170     value = split_vec.at(1);
00171         
00172     for(std::vector<std::string>::size_type it = 2, n = split_vec.size(); it < n; ++it)
00173         value += " " + split_vec.at(it);
00174 }
00175 
00176     
00177 
00178 void goby::acomms::DCCLPublish::write_publish(const std::map<std::string,std::vector<DCCLMessageVal> >& vals, std::multimap<std::string,DCCLMessageVal>* pubsub_vals)
00179 
00180 {
00181     for(unsigned i = 0, n = repeat_;
00182         i < n;
00183         ++i)
00184     {        
00185         std::string out_var, out_val;
00186         fill_format(vals, out_var, out_val, i);
00187         
00188         // user sets to string
00189         if(type_ == cpp_string)
00190         {
00191             pubsub_vals->insert(std::pair<std::string, DCCLMessageVal>(out_var, out_val));
00192             continue;
00193         }
00194         
00195         // pass through a DCCLMessageVal to do the type conversions
00196         DCCLMessageVal mv = out_val;
00197         double out_dval = mv;
00198         if(type_ == cpp_double)
00199         {
00200             pubsub_vals->insert(std::pair<std::string, DCCLMessageVal>(out_var, out_dval));
00201             continue;
00202         }
00203         long out_lval = mv;    
00204         if(type_ == cpp_long)
00205         {
00206             pubsub_vals->insert(std::pair<std::string, DCCLMessageVal>(out_var, out_lval));
00207             continue;
00208             
00209         }
00210         bool out_bval = mv;
00211         if(type_ == cpp_bool)
00212         {
00213             pubsub_vals->insert(std::pair<std::string, DCCLMessageVal>(out_var, out_bval));
00214             continue;
00215         }
00216         
00217         // see if our value is numeric
00218         bool is_numeric = true;
00219         try { boost::lexical_cast<double>(out_val); }
00220         catch (boost::bad_lexical_cast &) { is_numeric = false; }
00221         
00222         if(!is_numeric)
00223             pubsub_vals->insert(std::pair<std::string, DCCLMessageVal>(out_var, out_val));
00224         else
00225             pubsub_vals->insert(std::pair<std::string, DCCLMessageVal>(out_var, out_dval));
00226     }
00227 }
00228 
00229     
00230 std::string goby::acomms::DCCLPublish::get_display() const
00231 {
00232     std::stringstream ss;
00233     
00234     ss << "\t(" << type_to_string(type_);
00235     ss << ")moos_var: {" << var_ << "}" << std::endl;
00236     ss << "\tvalue: \"" << format_ << "\"" << std::endl;
00237     ss << "\tmessage_vars:" << std::endl;
00238     for (std::vector<boost::shared_ptr<DCCLMessageVar> >::size_type j = 0, m = message_vars_.size(); j < m; ++j)
00239     {
00240         ss << "\t\t" << (j+1) << ": " << message_vars_[j]->name();
00241 
00242         for(std::vector<std::string>::size_type k = 0, o = algorithms_[j].size(); k < o; ++k)
00243         {
00244             if(!k)
00245                 ss << " | algorithm(s): ";
00246             else
00247                 ss << ", ";
00248             ss << algorithms_[j][k];                
00249         }
00250             
00251         ss << std::endl;
00252     }
00253 
00254     return ss.str();
00255 }
00256 
00257 // overloaded <<
00258 std::ostream& goby::acomms::operator<< (std::ostream& out, const DCCLPublish& publish)
00259 {
00260     out << publish.get_display();
00261     return out;
00262 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends