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 "goby/util/string.h" 00023 00024 #include "message_var.h" 00025 #include "message.h" 00026 #include "message_val.h" 00027 #include "dccl_constants.h" 00028 #include "message_algorithms.h" 00029 00030 goby::acomms::DCCLMessageVar::DCCLMessageVar() 00031 : array_length_(1), 00032 is_key_frame_(true), 00033 source_set_(false), 00034 ap_(DCCLAlgorithmPerformer::getInstance()) 00035 { } 00036 00037 void goby::acomms::DCCLMessageVar::initialize(const DCCLMessage& msg) 00038 { 00039 // add trigger_var_ as source_var for any message_vars without a source 00040 if(!source_set_) 00041 source_var_ = msg.trigger_var(); 00042 00043 BOOST_FOREACH(const std::string& alg, algorithms_) 00044 ap_->check_algorithm(alg, msg); 00045 00046 initialize_specific(); 00047 00048 } 00049 00050 void goby::acomms::DCCLMessageVar::set_defaults(std::map<std::string,std::vector<DCCLMessageVal> >& vals, unsigned modem_id, unsigned id) 00051 { 00052 vals[name_].resize(array_length_); 00053 00054 std::vector<DCCLMessageVal>& vm = vals[name_]; 00055 00056 for(std::vector<DCCLMessageVal>::size_type i = 0, n = vm.size(); i < n; ++i) 00057 set_defaults_specific(vm[i], modem_id, id); 00058 00059 } 00060 00061 00062 void goby::acomms::DCCLMessageVar::var_encode(std::map<std::string,std::vector<DCCLMessageVal> >& vals, boost::dynamic_bitset<unsigned char>& bits) 00063 { 00064 // ensure that every DCCLMessageVar has the full number of (maybe blank) DCCLMessageVals 00065 vals[name_].resize(array_length_); 00066 00067 // modify the original vals to be used before running algorithms and encoding 00068 for(std::vector<DCCLMessageVal>::size_type i = 0, n = vals[name_].size(); i < n; ++i) 00069 pre_encode(vals[name_][i]); 00070 00071 // copy so algorithms can modify directly and not affect other algorithms' use of original values 00072 std::vector<DCCLMessageVal> vm = vals[name_]; 00073 00074 // write all the delta values first 00075 is_key_frame_ = false; 00076 00077 for(std::vector<DCCLMessageVal>::size_type i = 0, n = vm.size(); i < n; ++i) 00078 { 00079 for(std::vector<std::string>::size_type j = 0, m = algorithms_.size(); j < m; ++j) 00080 ap_->algorithm(vm[i], i, algorithms_[j], vals); 00081 00082 // read the first value as the key 00083 if(i == 0) key_val_ = vm[i]; 00084 // otherwise add the bits to the stream 00085 else encode_value(vm[i], bits); 00086 } 00087 00088 is_key_frame_ = true; 00089 00090 // insert the key at the end of the bitstream 00091 encode_value(key_val_, bits); 00092 } 00093 00094 void goby::acomms::DCCLMessageVar::encode_value(const DCCLMessageVal& val, boost::dynamic_bitset<unsigned char>& bits) 00095 { 00096 bits <<= calc_size(); 00097 00098 boost::dynamic_bitset<unsigned char> add_bits = encode_specific(val); 00099 add_bits.resize(bits.size()); 00100 00101 bits |= add_bits; 00102 } 00103 00104 00105 void goby::acomms::DCCLMessageVar::var_decode(std::map<std::string,std::vector<DCCLMessageVal> >& vals, boost::dynamic_bitset<unsigned char>& bits) 00106 { 00107 vals[name_].resize(array_length_); 00108 00109 // count down from one-past-the-end to 1, because we'll put the key at the beginning (array position 0) 00110 for(unsigned i = array_length_, n = 0; i > n; --i) 00111 { 00112 is_key_frame_ = (i == array_length_) ? true : false; 00113 00114 boost::dynamic_bitset<unsigned char> remove_bits = bits; 00115 remove_bits.resize(calc_size()); 00116 00117 DCCLMessageVal val = decode_specific(remove_bits); 00118 00119 bits >>= calc_size(); 00120 00121 // read the key first on the reverse bitstream 00122 if(is_key_frame_) key_val_ = val; 00123 else vals[name_][i] = val; 00124 } 00125 00126 // insert the key at the beginning of the return vector 00127 vals[name_][0] = key_val_; 00128 } 00129 00130 00131 void goby::acomms::DCCLMessageVar::read_pubsub_vars(std::map<std::string,std::vector<DCCLMessageVal> >& vals, 00132 const std::map<std::string,std::vector<DCCLMessageVal> >& in) 00133 { 00134 const std::map<std::string, std::vector<goby::acomms::DCCLMessageVal> >::const_iterator it = 00135 in.find(source_var_); 00136 00137 if(it != in.end()) 00138 { 00139 const std::vector<DCCLMessageVal>& vm = it->second; 00140 00141 BOOST_FOREACH(DCCLMessageVal val, vm) 00142 { 00143 switch(val.type()) 00144 { 00145 case cpp_string: 00146 val = parse_string_val(val); 00147 break; 00148 00149 default: 00150 break; 00151 } 00152 00153 // if we're expecting a vector, 00154 // split up vector quantities and add to vector 00155 if(array_length_ > 1) 00156 { 00157 std::string sval = val; 00158 std::vector<std::string> vec; 00159 boost::split(vec, sval, boost::is_any_of(",")); 00160 BOOST_FOREACH(const std::string& s, vec) 00161 vals[name_].push_back(s); 00162 } 00163 else // otherwise just use the value as is 00164 { 00165 vals[name_] = val; 00166 } 00167 } 00168 } 00169 } 00170 00171 00172 // deal with cases where key=value exists within the string 00173 std::string goby::acomms::DCCLMessageVar::parse_string_val(const std::string& sval) 00174 { 00175 std::string pieceval; 00176 00177 // is the parameter part of the std::string (as opposed to being the std::string) 00178 // that is, in_str is true if "key=value" is part of the string, rather 00179 // than the std::string simply being "value" 00180 bool in_str = false; 00181 00182 // see if the parameter is *in* the string, if so put it in pieceval 00183 // use source_key if specified, otherwise try the name 00184 std::string subkey = (source_key_ == "") ? name_ : source_key_; 00185 00186 in_str = util::val_from_string(pieceval, sval, subkey); 00187 //pick the substring from the string 00188 if(in_str) 00189 return pieceval; 00190 else 00191 return sval; 00192 } 00193 00194 std::string goby::acomms::DCCLMessageVar::get_display() const 00195 { 00196 std::stringstream ss; 00197 ss << "\t" << name_ << " (" << type_to_string(type()) << "):" << std::endl; 00198 00199 for(std::vector<std::string>::size_type j = 0, m = algorithms_.size(); j < m; ++j) 00200 { 00201 if(!j) 00202 ss << "\t\talgorithm(s): "; 00203 else 00204 ss << ", "; 00205 ss << algorithms_[j]; 00206 if (j==(m-1)) 00207 ss << std::endl; 00208 } 00209 00210 if(source_var_ != "") 00211 { 00212 ss << "\t\t" << "source: {"; 00213 ss << source_var_; 00214 ss << "}"; 00215 if(source_key_ != "") 00216 ss << " key: " << source_key_; 00217 ss << std::endl; 00218 } 00219 00220 if(array_length_ > 1) 00221 ss << "\t\tarray length: " << array_length_ << std::endl; 00222 00223 get_display_specific(ss); 00224 00225 00226 if(array_length_ > 1) 00227 ss << "\t\telement size [bits]: [" << calc_size() << "]" << std::endl; 00228 00229 00230 ss << "\t\ttotal size [bits]: [" << calc_total_size() << "]" << std::endl; 00231 00232 return ss.str(); 00233 } 00234 00235 00236 std::ostream& goby::acomms::operator<< (std::ostream& out, const DCCLMessageVar& mv) 00237 { 00238 out << mv.get_display(); 00239 return out; 00240 }