Goby Underwater Autonomy Project
Series: 1.1, revision: 163, released on 2013-02-06 14:23:27 -0500
|
00001 // copyright 2009-2011 t. schneider tes@mit.edu 00002 // 00003 // this file is part of the goby-acomms WHOI Micro-Modem driver. 00004 // 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 #ifndef Modem20091211H 00021 #define Modem20091211H 00022 00023 #include "goby/util/time.h" 00024 00025 #include "driver_base.h" 00026 #include "goby/protobuf/mm_driver.pb.h" 00027 #include "goby/acomms/acomms_helpers.h" 00028 00029 namespace goby 00030 { 00031 namespace acomms 00032 { 00033 00037 class MMDriver : public ModemDriverBase 00038 { 00039 public: 00044 MMDriver(std::ostream* log = 0); 00046 ~MMDriver(); 00047 00051 void startup(const protobuf::DriverConfig& cfg); 00052 void shutdown(); 00053 00055 void do_work(); 00056 00058 void handle_initiate_transmission(protobuf::ModemMsgBase* m); 00059 00061 void handle_initiate_ranging(protobuf::ModemRangingRequest* m); 00062 00063 private: 00064 00065 // startup 00066 void initialize_talkers(); // insert strings into sentence_id_map_, etc for later use 00067 void set_clock(); // set the modem clock from the system (goby) clock 00068 void write_cfg(); // write the NVRAM configuration values to the modem 00069 void write_single_cfg(const std::string &s); // write a single NVRAM value 00070 void query_all_cfg(); // query the current NVRAM configuration of the modem 00071 void set_hydroid_gateway_prefix(int id); // if using the hydroid gateway, set its id number 00072 00073 // output 00074 void try_send(); // try to send another NMEA message to the modem 00075 void pop_out(); // pop the NMEA send deque upon successful NMEA acknowledgment 00076 void cache_outgoing_data(const protobuf::ModemDataInit& init_msg); // cache data upon a CCCYC 00077 void append_to_write_queue(const util::NMEASentence& nmea, protobuf::ModemMsgBase* base_msg); // add a message 00078 void mm_write(const protobuf::ModemMsgBase& base_msg); // actually write a message (appends hydroid prefix if needed) 00079 void increment_present_fail(); 00080 void present_fail_exceeds_retries(); 00081 00082 // input 00083 void process_receive(const util::NMEASentence& nmea); // parse a receive message and call proper method 00084 00085 // data cycle 00086 void cyc(const util::NMEASentence& nmea, protobuf::ModemDataInit* init_msg); // $CACYC 00087 void rxd(const util::NMEASentence& nmea, protobuf::ModemDataTransmission* data_msg); // $CARXD 00088 void ack(const util::NMEASentence& nmea, protobuf::ModemDataAck* ack_msg); // $CAACK 00089 00090 // ranging (pings) 00091 void mpr(const util::NMEASentence& nmea, protobuf::ModemRangingReply* ranging_msg); // $CAMPR 00092 void tta(const util::NMEASentence& nmea, protobuf::ModemRangingReply* ranging_msg); // $SNTTA, why not $CATTA? 00093 void toa(const util::NMEASentence& nmea, protobuf::ModemRangingReply* ranging_msg); // $CATOA? 00094 // send toa once we actually know who the message is from 00095 void flush_toa(const protobuf::ModemMsgBase& base_msg, protobuf::ModemRangingReply* ranging_msg); 00096 00097 00098 // local modem 00099 void rev(const util::NMEASentence& nmea); // $CAREV 00100 void err(const util::NMEASentence& nmea); // $CAERR 00101 void cfg(const util::NMEASentence& nmea, protobuf::ModemMsgBase* base_msg); // $CACFG 00102 void clk(const util::NMEASentence& nmea, protobuf::ModemMsgBase* base_msg); // $CACLK 00103 void drq(const util::NMEASentence& nmea); // $CADRQ 00104 00105 bool validate_data(const protobuf::ModemDataRequest& request, 00106 protobuf::ModemDataTransmission* data); 00107 00108 bool is_valid_destination(int dest) 00109 { return dest >= BROADCAST_ID; } 00110 00111 00112 // utility 00113 static boost::posix_time::ptime nmea_time2ptime(const std::string& mt); 00114 00115 // doxygen 00117 00119 00120 private: 00121 // for the serial connection ($CCCFG,BR1,3) 00122 enum { DEFAULT_BAUD = 19200 }; 00123 // failures before closing port and throwing exception 00124 enum { MAX_FAILS_BEFORE_DEAD = 5 }; 00125 // how many retries on a given message 00126 enum { RETRIES = 3 }; 00127 enum { ROUGH_SPEED_OF_SOUND = 1500 }; // m/s 00128 enum { REMUS_LBL_TURN_AROUND_MS = 50 }; // milliseconds 00129 00130 00131 // seconds to wait for modem to respond 00132 static boost::posix_time::time_duration MODEM_WAIT; 00133 // seconds to wait after modem reboot 00134 static boost::posix_time::time_duration WAIT_AFTER_REBOOT; 00135 // allowed time skew between our clock and the modem clock 00136 static boost::posix_time::time_duration ALLOWED_SKEW; 00137 00138 static std::string SERIAL_DELIMITER; 00139 // number of frames for a given packet type 00140 static unsigned PACKET_FRAME_COUNT []; 00141 // size of packet (in bytes) for a given modem rate 00142 static unsigned PACKET_SIZE []; 00143 00144 00145 // all startup configuration (DriverConfig defined in driver_base.proto and extended in mm_driver.proto) 00146 protobuf::DriverConfig driver_cfg_; 00147 00148 // deque for outgoing messages to the modem, we queue them up and send 00149 // as the modem acknowledges them 00150 std::deque< std::pair<util::NMEASentence, protobuf::ModemMsgBase> > out_; 00151 00152 // human readable debug log (e.g. &std::cout) 00153 std::ostream* log_; 00154 00155 // time of the last message written. we timeout and resend after MODEM_WAIT seconds 00156 boost::posix_time::ptime last_write_time_; 00157 00158 // are we waiting for a command ack (CA) from the modem or can we send another output? 00159 bool waiting_for_modem_; 00160 00161 // set after the startup routines finish once. we can't startup on instantiation because 00162 // the base class sets some of our references (from the MOOS file) 00163 bool startup_done_; 00164 00165 // keeps track of number of failures and exits after reaching MAX_FAILS, assuming modem dead 00166 unsigned global_fail_count_; 00167 00168 // keeps track of number of failures on the present talker and moves on to the next talker 00169 // if exceeded 00170 unsigned present_fail_count_; 00171 00172 // has the clock been properly set. we must reset the clock after reboot ($CAREV,INIT) 00173 bool clock_set_; 00174 00175 enum TalkerIDs { TALKER_NOT_DEFINED = 0,CA,CC,SN,GP}; 00176 00177 enum SentenceIDs { SENTENCE_NOT_DEFINED = 0, 00178 ACK,DRQ,RXA,RXD, 00179 RXP,TXD,TXA,TXP, 00180 TXF,CYC,MPC,MPA, 00181 MPR,RSP,MSC,MSA, 00182 MSR,EXL,MEC,MEA, 00183 MER,MUC,MUA,MUR, 00184 PDT,PNT,TTA,MFD, 00185 CLK,CFG,AGC,BBD, 00186 CFR,CST,MSG,REV, 00187 DQF,SHF,SNR,DOP, 00188 DBG,FFL,FST,ERR, 00189 TOA}; 00190 00191 std::map<std::string, TalkerIDs> talker_id_map_; 00192 std::map<std::string, SentenceIDs> sentence_id_map_; 00193 std::map<std::string, std::string> description_map_; 00194 std::map<std::string, std::string> cfg_map_; 00195 00196 // 00197 // stuff to deal with the non-standard Hydroid gateway buoy 00198 // 00199 00200 // length of #G1 or #M1 00201 enum { HYDROID_GATEWAY_PREFIX_LENGTH = 3 }; 00202 // time between requests to the hydroid gateway buoy gps 00203 static boost::posix_time::time_duration HYDROID_GATEWAY_GPS_REQUEST_INTERVAL; 00204 boost::posix_time::ptime last_hydroid_gateway_gps_request_; 00205 bool is_hydroid_gateway_; 00206 std::string hydroid_gateway_modem_prefix_; 00207 std::string hydroid_gateway_gps_request_; 00208 00209 00210 // NVRAM parameters like SRC, DTO, PTO, etc. 00211 std::map<std::string, int> nvram_cfg_; 00212 00213 // cache the appropriate amount of data upon CCCYC request (initiate_transmission) 00214 // for immediate use upon the DRQ message 00215 // maps frame number to DataTransmission object 00216 std::map<unsigned, protobuf::ModemDataTransmission> cached_data_msgs_; 00217 00218 // keep track of which frames we've sent and are awaiting acks for. This 00219 // way we have a chance of intercepting unexpected behavior of the modem 00220 // relating to ACKs 00221 std::set<unsigned> frames_waiting_for_ack_; 00222 00223 // true if we initiated the last cycle ($CCCYC) (and thereby cache data for it)? 00224 // false if a third party initiated the last cycle 00225 bool local_cccyc_; 00226 00227 }; 00228 } 00229 } 00230 #endif