Goby Underwater Autonomy Project
Series: 1.1, revision: 163, released on 2013-02-06 14:23:27 -0500
|
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 }