23 #include <boost/algorithm/string.hpp>    24 #include <boost/algorithm/string/classification.hpp>    26 #include "goby/acomms/acomms_constants.h"    27 #include "goby/common/logger.h"    28 #include "goby/common/time.h"    29 #include "goby/util/binary.h"    31 #include "iridium_driver_fsm.h"    32 #include "rudics_packet.h"    38 int goby::acomms::fsm::IridiumDriverFSM::count_ = 0;
    40 void goby::acomms::fsm::IridiumDriverFSM::buffer_data_out(
    43     data_out_.push_back(msg);
    46 void goby::acomms::fsm::Command::in_state_react(
const EvRxSerial& e)
    48     std::string in = e.line;
    51     if (!at_out().empty() && at_out().front().second == 
"+SBDRB")
    60     if (!at_out().empty() && at_out().front().second != 
"E" &&
    61         (in == std::string(
"AT" + at_out().front().second)))
    63         glog.is(WARN) && 
glog << group(
"iridiumdriver") << 
"Echo turned on. Disabling" << std::endl;
    65         at_out_.insert(at_out_.begin() + 1, std::make_pair(ATSentenceMeta(), 
"E"));
    69     static const std::string 
connect = 
"CONNECT";
    70     static const std::string sbdi = 
"+SBDI";
    74         post_event(EvAck(in));
    76     else if (in == 
"RING")
    80     else if (in == 
"NO CARRIER")
    82         post_event(EvAck(in));
    83         post_event(EvNoCarrier());
    85     else if (in.compare(0, connect.size(), connect) == 0)
    87         post_event(EvAck(in));
    88         post_event(EvConnect());
    90     else if (in == 
"NO DIALTONE")
    92         post_event(EvAck(in));
    93         post_event(EvNoCarrier());
    95     else if (in == 
"BUSY")
    97         post_event(EvAck(in));
    98         post_event(EvNoCarrier());
   100     else if (in == 
"ERROR")
   102         post_event(EvReset());
   104     else if (in == 
"0" || in == 
"1" || in == 
"2" || in == 
"3")
   106         post_event(EvAck(in));
   108     else if (in == 
"READY")
   110         post_event(EvAck(in));
   112     else if (in.compare(0, sbdi.size(), sbdi) == 0)
   114         post_event(EvSBDTransmitComplete(in));
   116     else if (in == 
"SBDRING")
   118         post_event(EvSBDBeginData(
"", 
true));
   122 void goby::acomms::fsm::Command::handle_sbd_rx(
const std::string& in)
   126         SBD_FIELD_SIZE_BYTES = 2,
   127         SBD_BITS_IN_BYTE = 8,
   128         SBD_CHECKSUM_BYTES = 2
   131     if (sbd_rx_buffer_.empty() && in.at(0) == 
'\n')
   132         sbd_rx_buffer_ = in.substr(1); 
   134         sbd_rx_buffer_ += in;
   137     if (sbd_rx_buffer_.size() < SBD_FIELD_SIZE_BYTES)
   141         unsigned sbd_rx_size =
   142             ((sbd_rx_buffer_[0] & 0xff) << SBD_BITS_IN_BYTE) | (sbd_rx_buffer_[1] & 0xff);
   143         glog.is(DEBUG1) && 
glog << group(
"iridiumdriver") << 
"SBD RX Size: " << sbd_rx_size
   146         if (sbd_rx_buffer_.size() < (SBD_FIELD_SIZE_BYTES + sbd_rx_size))
   152             std::string sbd_rx_data = sbd_rx_buffer_.substr(SBD_FIELD_SIZE_BYTES, sbd_rx_size);
   154             parse_rudics_packet(&bytes, sbd_rx_data);
   155             protobuf::ModemTransmission msg;
   156             parse_iridium_modem_message(bytes, &msg);
   157             context<IridiumDriverFSM>().received().push_back(msg);
   158             at_out().pop_front();
   160             post_event(EvSBDReceiveComplete());
   168 void goby::acomms::fsm::Command::in_state_react(
const EvTxSerial&)
   172     if (!at_out_.empty())
   174         double timeout = COMMAND_TIMEOUT_SECONDS;
   175         switch (at_out_.front().second[0])
   178             case 'D': timeout = DIAL_TIMEOUT_SECONDS; 
break;
   179             case 'A': timeout = ANSWER_TIMEOUT_SECONDS; 
break;
   180             case 'H': timeout = HANGUP_TIMEOUT_SECONDS; 
break;
   182                 if (at_out_.front().second == 
"+++")
   183                     timeout = TRIPLE_PLUS_TIMEOUT_SECONDS;
   187         static const std::string sbdi = 
"+SBDI";
   188         if (at_out_.front().second.compare(0, sbdi.size(), sbdi) == 0)
   189             timeout = SBDIX_TIMEOUT_SECONDS;
   191         if (at_out_.front().second == 
"+SBDRB")
   192             clear_sbd_rx_buffer();
   194         if ((at_out_.front().first.last_send_time_ + timeout) < now)
   196             std::string at_command;
   197             if (at_out_.front().second != 
"+++")
   198                 at_command = 
"AT" + at_out_.front().second + 
"\r";
   200                 at_command = at_out_.front().second;
   202             if (++at_out_.front().first.tries_ > RETRIES_BEFORE_RESET)
   204                 glog.is(DEBUG1) && 
glog << group(
"iridiumdriver") << warn
   205                                         << 
"No valid response after " << RETRIES_BEFORE_RESET
   206                                         << 
" tries. Resetting state machine" << std::endl;
   207                 post_event(EvReset());
   211                 context<IridiumDriverFSM>().serial_tx_buffer().push_back(at_command);
   212                 at_out_.front().first.last_send_time_ = now;
   218 void goby::acomms::fsm::Online::in_state_react(
const EvRxSerial& e)
   225 void goby::acomms::fsm::Online::in_state_react(
const EvTxSerial&)
   227     post_event(EvTxOnCallSerial());
   230 void goby::acomms::fsm::Command::in_state_react(
const EvAck& e)
   233     if (e.response_.size() > 0)
   235         switch (e.response_[0])
   238                 if (!at_out().empty() && at_out().front().second == 
"+SBDD2")
   240                     post_event(EvSBDSendBufferCleared());
   242                 else if (at_out().empty()) 
   244                     post_event(EvSBDWriteComplete());
   245                     push_at_command(
"AT"); 
   255     if (!at_out().empty())
   257         const std::string& last_at = at_out().front().second;
   258         if (last_at.size() > 0 && (e.response_ == 
"OK"))
   263                     post_event(EvNoCarrier());
   268                 case 'D': post_event(EvNoCarrier()); 
break;
   274         if (e.response_ == 
"READY") 
   275             post_event(EvSBDWriteReady());
   277         at_out().pop_front();
   278         if (at_out().empty())
   279             post_event(EvAtEmpty());
   283         glog.is(DEBUG1) && 
glog << group(
"iridiumdriver") << warn << 
"Unexpected '" << e.response_
   288 boost::statechart::result goby::acomms::fsm::Dial::react(
const EvNoCarrier& x)
   290     const int redial_wait_seconds = 2;
   291     glog.is(DEBUG1) && 
glog << group(
"iridiumdriver") << 
"Redialing in " << redial_wait_seconds
   292                             << 
" seconds ..." << std::endl;
   294     sleep(redial_wait_seconds);
   296     const int max_attempts =
   297         context<IridiumDriverFSM>().driver_cfg().GetExtension(IridiumDriverConfig::dial_attempts);
   298     if (dial_attempts_ < max_attempts)
   301         return discard_event();
   305         glog.is(DEBUG1) && 
glog << warn << group(
"iridiumdriver") << 
"Failed to connect after "   306                                 << max_attempts << 
" tries." << std::endl;
   308         return transit<Ready>();
   312 void goby::acomms::fsm::Dial::dial()
   315     context<Command>().push_at_command(
"D" + context<IridiumDriverFSM>()
   317                                                  .GetExtension(IridiumDriverConfig::remote)
   321 void goby::acomms::fsm::OnCall::in_state_react(
const EvRxOnCallSerial& e)
   323     std::string in = e.line;
   326     static const std::string no_carrier = 
"NO CARRIER";
   327     if (in.find(no_carrier) != std::string::npos)
   329         post_event(EvNoCarrier());
   331     else if (boost::trim_copy(in) == 
"goby")
   333         glog.is(DEBUG1) && 
glog << group(
"iridiumdriver") << 
"Detected start of Goby RUDICS call"   336     else if (boost::trim_copy(in) == 
"bye")
   338         glog.is(DEBUG1) && 
glog << group(
"iridiumdriver")
   339                                 << 
"Detected remote completion of Goby RUDICS call" << std::endl;
   340         set_bye_received(
true);
   347             parse_rudics_packet(&bytes, in);
   349             protobuf::ModemTransmission msg;
   350             parse_iridium_modem_message(bytes, &msg);
   351             context<IridiumDriverFSM>().received().push_back(msg);
   354         catch (RudicsPacketException& e)
   356             glog.is(DEBUG1) && 
glog << warn << group(
"iridiumdriver")
   357                                     << 
"Could not decode packet: " << e.what() << std::endl;
   362 void goby::acomms::fsm::OnCall::in_state_react(
const EvTxOnCallSerial&)
   364     const static double target_byte_rate = (context<IridiumDriverFSM>().driver_cfg().GetExtension(
   365                                                 IridiumDriverConfig::target_bit_rate) /
   366                                             static_cast<double>(goby::acomms::BITS_IN_BYTE));
   368     const double send_wait = last_bytes_sent() / target_byte_rate;
   371     boost::circular_buffer<protobuf::ModemTransmission>& data_out =
   372         context<IridiumDriverFSM>().data_out();
   373     if (!data_out.empty() && (now > last_tx_time() + send_wait))
   377         serialize_iridium_modem_message(&bytes, data_out.front());
   380         std::string rudics_packet;
   381         serialize_rudics_packet(bytes, &rudics_packet);
   383         context<IridiumDriverFSM>().serial_tx_buffer().push_back(rudics_packet);
   384         data_out.pop_front();
   386         set_last_bytes_sent(rudics_packet.size());
   387         set_last_tx_time(now);
   391 void goby::acomms::fsm::OnCall::in_state_react(
const EvSendBye&)
   393     context<IridiumDriverFSM>().serial_tx_buffer().push_front(
"bye\r");
 
double goby_time< double >()
Returns current UTC time as seconds and fractional seconds since 1970-01-01 00:00:00. 
 
ReturnType goby_time()
Returns current UTC time as a boost::posix_time::ptime. 
 
void connect(Signal *signal, Slot slot)
connect a signal to a slot (e.g. function pointer) 
 
common::FlexOstream glog
Access the Goby logger through this object.