23 #ifndef IridiumModemDriverFSM20130826H 24 #define IridiumModemDriverFSM20130826H 26 #include <boost/circular_buffer.hpp> 28 #include <boost/mpl/list.hpp> 29 #include <boost/statechart/custom_reaction.hpp> 30 #include <boost/statechart/deep_history.hpp> 31 #include <boost/statechart/event.hpp> 32 #include <boost/statechart/in_state_reaction.hpp> 33 #include <boost/statechart/simple_state.hpp> 34 #include <boost/statechart/state.hpp> 35 #include <boost/statechart/state_machine.hpp> 36 #include <boost/statechart/transition.hpp> 39 #include "goby/acomms/modemdriver/iridium_driver_common.h" 40 #include "goby/acomms/protobuf/iridium_driver.pb.h" 41 #include "goby/acomms/protobuf/modem_message.pb.h" 47 inline unsigned sbd_csum(
const std::string& data)
49 unsigned int csum = 0;
50 for (std::string::const_iterator it = data.begin(), end = data.end(); it != end; ++it)
61 glog.is(goby::common::logger::DEBUG1) &&
glog << group(
"iridiumdriver") << name_
66 glog.is(goby::common::logger::DEBUG1) &&
glog << group(
"iridiumdriver") <<
"~" << name_
93 EvAck(
const std::string& response) : response_(response) {}
95 std::string response_;
138 EvSBDBeginData(
const std::string& data =
"",
bool in_response_to_ring_alert =
false)
139 : data_(data), in_response_to_ring_alert_(in_response_to_ring_alert)
143 bool in_response_to_ring_alert_;
192 : serial_tx_buffer_(SERIAL_BUFFER_CAPACITY), received_(RECEIVED_BUFFER_CAPACITY),
193 driver_cfg_(driver_cfg), data_out_(DATA_BUFFER_CAPACITY)
196 glog_ir_group_ =
"iridiumdriver::" + goby::util::as<std::string>(count_);
202 boost::circular_buffer<std::string>& serial_tx_buffer() {
return serial_tx_buffer_; }
205 boost::circular_buffer<protobuf::ModemTransmission>& received() {
return received_; }
208 boost::circular_buffer<protobuf::ModemTransmission>& data_out() {
return data_out_; }
212 const std::string& glog_ir_group()
const {
return glog_ir_group_; }
217 SERIAL_BUFFER_CAPACITY = 10
221 RECEIVED_BUFFER_CAPACITY = 10
224 boost::circular_buffer<std::string> serial_tx_buffer_;
225 boost::circular_buffer<protobuf::ModemTransmission> received_;
230 DATA_BUFFER_CAPACITY = 5
232 boost::circular_buffer<protobuf::ModemTransmission> data_out_;
234 std::string glog_ir_group_;
240 boost::mpl::list<Command, NotOnCall> >
242 typedef boost::mpl::list<boost::statechart::transition<EvReset, Active> > reactions;
247 boost::mpl::list<Configure, SBD> >,
253 void in_state_react(
const EvAck&);
258 typedef boost::mpl::list<
259 boost::statechart::in_state_reaction<EvRxSerial, Command, &Command::in_state_react>,
260 boost::statechart::in_state_reaction<EvTxSerial, Command, &Command::in_state_react>,
261 boost::statechart::transition<EvOnline, Online>,
262 boost::statechart::in_state_reaction<EvAck, Command, &Command::in_state_react> >
268 double last_send_time_;
272 void push_at_command(
const std::string& cmd)
277 boost::circular_buffer<std::pair<ATSentenceMeta, std::string> >& at_out() {
return at_out_; }
279 void clear_sbd_rx_buffer() { sbd_rx_buffer_.clear(); }
281 void handle_sbd_rx(
const std::string& in);
286 AT_BUFFER_CAPACITY = 100
288 boost::circular_buffer<std::pair<ATSentenceMeta, std::string> > at_out_;
291 COMMAND_TIMEOUT_SECONDS = 2,
292 DIAL_TIMEOUT_SECONDS = 60,
293 SBDIX_TIMEOUT_SECONDS = DIAL_TIMEOUT_SECONDS,
294 TRIPLE_PLUS_TIMEOUT_SECONDS = 6,
295 HANGUP_TIMEOUT_SECONDS = 10,
296 ANSWER_TIMEOUT_SECONDS = 30
301 RETRIES_BEFORE_RESET = 3
303 std::string sbd_rx_buffer_;
308 typedef boost::mpl::list<boost::statechart::transition<EvAtEmpty, Ready> > reactions;
312 context<Command>().push_at_command(
"");
313 for (
int i = 0, n = context<IridiumDriverFSM>().driver_cfg().ExtensionSize(
314 IridiumDriverConfig::config);
317 context<Command>().push_at_command(
318 context<IridiumDriverFSM>().driver_cfg().GetExtension(IridiumDriverConfig::config,
332 boost::statechart::result react(
const EvDial&)
334 if (state_downcast<const NotOnCall*>() != 0)
336 return transit<Dial>();
340 glog.is(goby::common::logger::DEBUG1) &&
341 glog << group(
"iridiumdriver") <<
"Not dialing since we are already on a call." 343 return discard_event();
347 typedef boost::mpl::list<boost::statechart::transition<EvRing, Answer>,
348 boost::statechart::custom_reaction<EvDial> >
359 context<Command>().push_at_command(
"+++");
360 context<Command>().push_at_command(
"H");
364 typedef boost::mpl::list<boost::statechart::transition<EvAtEmpty, Ready> > reactions;
375 glog.is(goby::common::logger::DEBUG1) &&
376 glog << group(
"iridiumdriver") <<
"Disconnected; checking error details: " << std::endl;
377 context<Command>().push_at_command(
"+CEER");
381 typedef boost::mpl::list<boost::statechart::transition<EvAtEmpty, Ready> > reactions;
388 typedef boost::mpl::list<boost::statechart::custom_reaction<EvNoCarrier> > reactions;
390 Dial(my_context ctx) : my_base(ctx),
StateNotify(
"Dial"), dial_attempts_(0) { dial(); }
393 boost::statechart::result react(
const EvNoCarrier&);
402 typedef boost::mpl::list<boost::statechart::transition<EvNoCarrier, Ready> > reactions;
406 context<Command>().push_at_command(
"A");
420 typedef boost::mpl::list<
421 boost::statechart::transition<EvHangup, HangingUp>,
422 boost::statechart::transition<EvDisconnect, PostDisconnected>,
423 boost::statechart::in_state_reaction<EvRxSerial, Online, &Online::in_state_react>,
424 boost::statechart::in_state_reaction<EvTxSerial, Online, &Online::in_state_react> >
431 typedef boost::mpl::list<boost::statechart::transition<EvConnect, OnCall> > reactions;
445 context<IridiumDriverFSM>().serial_tx_buffer().push_front(
"goby\r");
453 glog.is(goby::common::logger::DEBUG1) &&
glog << group(
"iridiumdriver") <<
"Sent " 454 << total_bytes_sent()
455 <<
" bytes on this call." << std::endl;
463 typedef boost::mpl::list<
464 boost::statechart::transition<EvNoCarrier, NotOnCall>,
465 boost::statechart::in_state_reaction<EvRxOnCallSerial, OnCall, &OnCall::in_state_react>,
466 boost::statechart::in_state_reaction<EvTxOnCallSerial, OnCall, &OnCall::in_state_react>,
467 boost::statechart::in_state_reaction<EvSendBye, OnCall, &OnCall::in_state_react>
483 in_response_to_ring_alert_ = e.in_response_to_ring_alert_;
485 void clear_data() { data_.clear(); }
486 const std::string& data()
const {
return data_; }
487 bool in_response_to_ring_alert()
const {
return in_response_to_ring_alert_; }
490 void set_data(
const std::string& data)
496 unsigned int csum = sbd_csum(data);
498 const int bits_in_byte = 8;
499 data_ = data + std::string(1, (csum & 0xFF00) >> bits_in_byte) +
500 std::string(1, (csum & 0xFF));
506 bool in_response_to_ring_alert_;
525 typedef boost::mpl::list<
526 boost::statechart::transition<EvSBDBeginData, SBDClearBuffers, SBD, &SBD::set_data> >
536 typedef boost::mpl::list<boost::statechart::transition<EvSBDSendBufferCleared, SBDWrite> >
541 context<Command>().clear_sbd_rx_buffer();
542 context<Command>().push_at_command(
"+SBDD2");
552 if (context<SBD>().data().empty())
554 glog.is(goby::common::logger::DEBUG1) &&
glog << group(
"iridiumdriver")
555 <<
"Mailbox Check." << std::endl;
560 glog.is(goby::common::logger::DEBUG1) &&
glog << group(
"iridiumdriver")
561 <<
"Writing data." << std::endl;
563 const int csum_bytes = 2;
564 context<Command>().push_at_command(
565 "+SBDWB=" + goby::util::as<std::string>(context<SBD>().data().size() - csum_bytes));
571 context<IridiumDriverFSM>().serial_tx_buffer().push_back(context<SBD>().data());
576 typedef boost::mpl::list<
577 boost::statechart::in_state_reaction<EvSBDWriteReady, SBDWrite, &SBDWrite::in_state_react>,
578 boost::statechart::transition<EvSBDWriteComplete, SBDTransmit> >
584 typedef boost::mpl::list<boost::statechart::custom_reaction<EvSBDTransmitComplete> > reactions;
587 if (context<SBD>().in_response_to_ring_alert())
588 context<Command>().push_at_command(
"+SBDIXA");
590 context<Command>().push_at_command(
"+SBDIX");
594 std::string mo_status_as_string(
int code)
599 case 0:
return "MO message, if any, transferred successfully";
601 return "MO message, if any, transferred successfully, but the MT message in the " 602 "queue was too big to be transferred";
604 return "MO message, if any, transferred successfully, but the requested Location " 605 "Update was not accepted";
608 return "Reserved, but indicate MO session success if used";
631 default:
return "Reserved, but indicate MO session failure if used";
632 case 10:
return "GSS reported that the call did not complete in the allowed time";
633 case 11:
return "MO message queue at the GSS is full";
634 case 12:
return "MO message has too many segments";
635 case 13:
return "GSS reported that the session did not complete";
636 case 14:
return "Invalid segment size";
637 case 15:
return "Access is denied";
638 case 16:
return "Modem has been locked and may not make SBD calls";
639 case 17:
return "Gateway not responding (local session timeout)";
640 case 18:
return "Connection lost (RF drop)";
641 case 19:
return "Link failure (A protocol error caused termination of the call)";
642 case 32:
return "No network service, unable to initiate call";
643 case 35:
return "Iridium 9523 is busy, unable to initiate call";
650 std::vector<std::string> sbdi_fields;
651 boost::algorithm::split(sbdi_fields, e.sbdi_, boost::is_any_of(
":,"));
653 std::for_each(sbdi_fields.begin(), sbdi_fields.end(),
654 boost::bind(&boost::trim<std::string>, _1, std::locale()));
656 if (sbdi_fields.size() != 7)
658 glog.is(goby::common::logger::DEBUG1) &&
glog << group(
"iridiumdriver")
659 <<
"Invalid +SBDI response: " << e.sbdi_
661 return transit<SBDReady>();
676 MT_STATUS_NO_MESSAGE = 0,
677 MT_STATUS_RECEIVED_MESSAGE = 1,
684 MO_STATUS_SUCCESS_MAX = 4,
685 MO_STATUS_FAILURE_MIN = 5
688 int mo_status = goby::util::as<int>(sbdi_fields[MO_STATUS]);
689 if (mo_status <= MO_STATUS_SUCCESS_MAX)
691 glog.is(goby::common::logger::DEBUG1) &&
692 glog << group(
"iridiumdriver")
693 <<
"Success sending SBDIX: " << mo_status_as_string(mo_status)
698 glog.is(goby::common::logger::WARN) &&
699 glog << group(
"iridiumdriver")
700 <<
"Error sending SBD packet: " << mo_status_as_string(mo_status)
702 return transit<SBDReady>();
705 int mt_status = goby::util::as<int>(sbdi_fields[MT_STATUS]);
706 if (mt_status == MT_STATUS_RECEIVED_MESSAGE)
707 return transit<SBDReceive>();
709 return transit<SBDReady>();
716 typedef boost::mpl::list<boost::statechart::transition<EvSBDReceiveComplete, SBDReady> >
720 context<Command>().push_at_command(
"+SBDRB");
common::FlexOstream glog
Access the Goby logger through this object.
The global namespace for the Goby project.