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/mm_driver.h
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends