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