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/libmodemdriver/abc_driver.cpp
00001 // copyright 2011 t. schneider tes@mit.edu
00002 // 
00003 // This program is free software: you can redistribute it and/or modify
00004 // it under the terms of the GNU General Public License as published by
00005 // the Free Software Foundation, either version 3 of the License, or
00006 // (at your option) any later version.
00007 //
00008 // This software is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 // GNU General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU General Public License
00014 // along with this software.  If not, see <http://www.gnu.org/licenses/>.
00015 
00016 #include "abc_driver.h"
00017 #include "driver_exception.h"
00018 
00019 #include "goby/util/logger.h"
00020 
00021 
00022 
00023 goby::acomms::ABCDriver::ABCDriver(std::ostream* log /*= 0*/)
00024     : ModemDriverBase(log),
00025       log_(log)
00026 {
00027     // other initialization you can do before you have your goby::acomms::DriverConfig configuration object
00028 }
00029 
00030 void goby::acomms::ABCDriver::startup(const protobuf::DriverConfig& cfg)
00031 {
00032     driver_cfg_ = cfg;
00033     // check `driver_cfg_` to your satisfaction and then start the modem physical interface
00034     if(!driver_cfg_.has_serial_baud())
00035         driver_cfg_.set_serial_baud(DEFAULT_BAUD);
00036 
00037     // log_ is allowed to be 0 (NULL), so always check it first
00038     if(log_) *log_ << group("modem_out") << "ABCDriver configuration good. Starting modem..." << std::endl;
00039     ModemDriverBase::modem_start(driver_cfg_);
00040 
00041     // set your local modem id (MAC address) 
00042     driver_cfg_.modem_id();
00043     
00044 
00045     {
00046         
00047         std::stringstream raw;
00048         raw << "CONF,MAC:" << driver_cfg_.modem_id() << "\r\n";
00049         signal_and_write(raw.str());
00050     }
00051 
00052     
00053     // now set our special configuration values
00054     {
00055         std::stringstream raw;
00056         raw << "CONF,FOO:" << driver_cfg_.GetExtension(ABCDriverConfig::enable_foo) << "\r\n";
00057         signal_and_write(raw.str());
00058     }
00059     {
00060         std::stringstream raw;
00061         raw << "CONF,BAR:" << driver_cfg_.GetExtension(ABCDriverConfig::enable_bar) << "\r\n";
00062         signal_and_write(raw.str());
00063     }
00064 } // startup
00065 
00066 void goby::acomms::ABCDriver::shutdown()
00067 {
00068     // put the modem in a low power state?
00069     // ...
00070     ModemDriverBase::modem_close();
00071 } // shutdown
00072 
00073 void goby::acomms::ABCDriver::handle_initiate_transmission(protobuf::ModemMsgBase* base_msg)
00074 {
00075     if(log_)
00076     {
00077         // base_msg->rate() can be 0 (lowest), 1, 2, 3, 4, or 5 (lowest). Map these integers onto real bit-rates
00078         // in a meaningful way (on the WHOI Micro-Modem 0 ~= 80 bps, 5 ~= 5000 bps).
00079         *log_ <<  group("modem_out") << "We were asked to transmit from " << base_msg->src()
00080               << " to " << base_msg->dest()
00081               << " at bitrate code " << base_msg->rate() << std::endl;
00082     } 
00083 
00084     protobuf::ModemDataRequest request_msg; // used to request data from libqueue
00085     protobuf::ModemDataTransmission data_msg; // used to store the requested data
00086 
00087     // set up request_msg
00088     request_msg.mutable_base()->set_src(base_msg->src());
00089     request_msg.mutable_base()->set_dest(base_msg->dest());
00090     // let's say ABC modem uses 500 byte packet
00091     request_msg.set_max_bytes(500);
00092 
00093     ModemDriverBase::signal_data_request(request_msg, &data_msg);
00094     
00095     // do nothing with an empty message
00096     if(data_msg.data().empty()) return;
00097     
00098     if(log_)
00099     {
00100         *log_ <<  group("modem_out") << "Sending these data now: " << data_msg << std::endl;
00101     }
00102     
00103     // let's say we can send at three bitrates with ABC modem: map these onto 0-5
00104     const unsigned BITRATE [] = { 100, 1000, 10000, 10000, 10000, 10000};
00105 
00106     // I'm making up a syntax for the wire protocol...
00107     std::stringstream raw;
00108     raw << "SEND,TO:" << data_msg.base().dest()
00109         << ",FROM:" << data_msg.base().src()
00110         << ",HEX:" << hex_encode(data_msg.data())
00111         << ",BITRATE:" << BITRATE[base_msg->rate()]
00112         << ",ACK:TRUE"
00113         << "\r\n";
00114 
00115     // let anyone who is interested know
00116     signal_and_write(raw.str(), base_msg);    
00117 } // handle_initiate_transmission
00118 
00119 void goby::acomms::ABCDriver::do_work()
00120 {
00121     std::string in;
00122     while(modem_read(&in))
00123     {
00124         std::map<std::string, std::string> parsed;
00125 
00126         // breaks `in`: "RECV,TO:3,FROM:6,HEX:ABCD015910"
00127         //   into `parsed`: "KEY"=>"RECV", "TO"=>"3", "FROM"=>"6", "HEX"=>"ABCD015910"
00128         try
00129         {
00130             boost::trim(in); // get whitespace off from either end
00131             parse_in(in, &parsed);
00132             
00133             protobuf::ModemMsgBase base_msg;
00134             base_msg.set_raw(in);
00135             
00136             using google::protobuf::int32;
00137             base_msg.set_src(goby::util::as<int32>(parsed["FROM"]));
00138             base_msg.set_dest(goby::util::as<int32>(parsed["TO"]));
00139             base_msg.set_time(goby::util::as<std::string>(
00140                                   goby::util::goby_time()));
00141 
00142             if(log_) *log_ << group("modem_in") << in << std::endl;
00143             ModemDriverBase::signal_all_incoming(base_msg);
00144             
00145             if(parsed["KEY"] == "RECV")
00146             {
00147                 protobuf::ModemDataTransmission data_msg;
00148                 data_msg.mutable_base()->CopyFrom(base_msg);
00149                 data_msg.set_data(hex_decode(parsed["HEX"]));
00150                 if(log_) *log_ << group("modem_in") << "received: " << data_msg << std::endl;
00151                 ModemDriverBase::signal_receive(data_msg);
00152             }
00153             else if(parsed["KEY"] == "ACKN")
00154             {
00155                 protobuf::ModemDataAck ack_msg;
00156                 ack_msg.mutable_base()->CopyFrom(base_msg);
00157                 ModemDriverBase::signal_ack(ack_msg);
00158             }
00159         }
00160         catch(std::exception& e)
00161         {
00162             if(log_) *log_ << warn << "Bad line: " << in << std::endl;
00163             if(log_) *log_ << warn << "Exception: " << e.what() << std::endl;
00164         }
00165     }
00166 } // do_work
00167 
00168 void goby::acomms::ABCDriver::signal_and_write(const std::string& raw, protobuf::ModemMsgBase* base_msg /* = 0 */)
00169 {
00170     static protobuf::ModemMsgBase local_base_msg;
00171     if(!base_msg)
00172         base_msg = &local_base_msg;
00173     
00174     base_msg->set_raw(raw);
00175     ModemDriverBase::signal_all_outgoing(*base_msg);    
00176     if(log_) *log_ << group("modem_out") << boost::trim_copy(raw) << std::endl;
00177     ModemDriverBase::modem_write(raw); 
00178 }
00179 
00180 void goby::acomms::ABCDriver::parse_in(const std::string& in, std::map<std::string, std::string>* out)
00181 {
00182     std::vector<std::string> comma_split;
00183     boost::split(comma_split, in, boost::is_any_of(","));
00184     out->insert(std::make_pair("KEY", comma_split.at(0)));
00185     for(int i = 1, n = comma_split.size(); i < n; ++i)
00186     {
00187         std::vector<std::string> colon_split;
00188         boost::split(colon_split, comma_split[i],
00189                      boost::is_any_of(":"));
00190         out->insert(std::make_pair(colon_split.at(0),
00191                                    colon_split.at(1)));
00192     }
00193 }
00194 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends