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_var.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 "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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends