26 #include <boost/bind.hpp> 27 #include <boost/date_time/gregorian/gregorian_types.hpp> 28 #include <boost/foreach.hpp> 30 #include "goby/acomms/acomms_helpers.h" 31 #include "goby/common/logger.h" 33 #include "mac_manager.h" 41 int goby::acomms::MACManager::count_;
44 : timer_(io_), work_(io_), current_slot_(
std::list<protobuf::ModemTransmission>::begin()),
49 glog_mac_group_ =
"goby::acomms::amac::" + as<std::string>(count_);
53 goby::acomms::MACManager::~MACManager() {}
55 void goby::acomms::MACManager::restart_timer()
59 timer_.expires_at(next_slot_t_);
60 timer_.async_wait(boost::bind(&MACManager::begin_slot,
this, _1));
63 void goby::acomms::MACManager::stop_timer() { timer_.cancel(); }
71 case protobuf::MAC_POLLED:
72 case protobuf::MAC_FIXED_DECENTRALIZED:
73 std::list<protobuf::ModemTransmission>::clear();
74 for (
int i = 0, n = cfg_.slot_size(); i < n; ++i)
77 slot.set_slot_index(i);
78 std::list<protobuf::ModemTransmission>::push_back(slot);
81 if (cfg_.type() == protobuf::MAC_POLLED)
82 glog.is(DEBUG1) &&
glog << group(glog_mac_group_)
83 <<
"Using the Centralized Polling MAC_POLLED scheme" 85 else if (cfg_.type() == protobuf::MAC_FIXED_DECENTRALIZED)
86 glog.is(DEBUG1) &&
glog << group(glog_mac_group_)
87 <<
"Using the Decentralized MAC_FIXED_DECENTRALIZED scheme" 99 glog.is(DEBUG1) &&
glog << group(glog_mac_group_)
100 <<
"Goby Acoustic Medium Access Control module starting up." 105 glog.is(DEBUG1) &&
glog << group(glog_mac_group_)
106 <<
" ... MAC is already started, not restarting." << std::endl;
114 glog.is(DEBUG1) &&
glog << group(glog_mac_group_)
115 <<
"the first MAC TDMA cycle begins at time: " << next_slot_t_
123 current_slot_ = std::list<protobuf::ModemTransmission>::begin();
126 glog.is(DEBUG1) &&
glog << group(glog_mac_group_)
127 <<
"the MAC cycle has been shutdown until restarted." << std::endl;
130 void goby::acomms::MACManager::begin_slot(
const boost::system::error_code& e)
133 if (e == boost::asio::error::operation_aborted)
137 if (std::abs(goby_time<double>() - goby::util::as<double>(next_slot_t_)) > ALLOWED_SKEW_SECONDS)
139 glog.is(DEBUG1) &&
glog << group(glog_mac_group_) << warn
140 <<
"Clock skew detected, updating MAC." << std::endl;
146 s.set_time(goby::util::as<uint64>(next_slot_t_));
148 bool we_are_transmitting =
true;
151 case protobuf::MAC_FIXED_DECENTRALIZED:
153 we_are_transmitting = (s.src() == cfg_.modem_id()) || s.always_initiate();
156 case protobuf::MAC_POLLED:
167 glog << group(glog_mac_group_) <<
"Cycle order: [";
169 for (std::list<protobuf::ModemTransmission>::iterator
170 it = std::list<protobuf::ModemTransmission>::begin(),
174 if (it == current_slot_)
175 glog << group(glog_mac_group_) <<
" " <<
green;
179 case protobuf::ModemTransmission::DATA:
glog <<
"d";
break;
180 case protobuf::ModemTransmission::DRIVER_SPECIFIC:
glog <<
"s";
break;
185 glog << it->src() <<
"/" << it->dest() <<
"@" << it->rate() <<
" " <<
nocolor;
187 glog <<
" ]" << std::endl;
190 glog.is(DEBUG1) &&
glog << group(glog_mac_group_) <<
"Starting slot: " << s.ShortDebugString()
193 if (we_are_transmitting)
199 glog.is(DEBUG1) &&
glog << group(glog_mac_group_) <<
"Next slot at " << next_slot_t_
205 void goby::acomms::MACManager::increment_slot()
209 case protobuf::MAC_FIXED_DECENTRALIZED:
210 case protobuf::MAC_POLLED:
211 next_slot_t_ += boost::posix_time::microseconds(current_slot_->slot_seconds() * 1e6);
214 if (current_slot_ == std::list<protobuf::ModemTransmission>::end())
215 current_slot_ = std::list<protobuf::ModemTransmission>::begin();
222 boost::posix_time::ptime goby::acomms::MACManager::next_cycle_time()
227 ptime now = goby_time();
230 switch (cfg_.ref_time_type())
232 case protobuf::MACConfig::REFERENCE_START_OF_DAY:
233 reference = ptime(now.date(), seconds(0));
235 case protobuf::MACConfig::REFERENCE_FIXED:
240 time_duration duration_since_ref = now - reference;
242 duration_since_ref.total_seconds() * 1000000ll +
243 (duration_since_ref - seconds(duration_since_ref.total_seconds())).total_microseconds();
245 glog.is(DEBUG2) &&
glog << group(glog_mac_group_) <<
"reference: " << reference << std::endl;
247 glog.is(DEBUG2) &&
glog << group(glog_mac_group_)
248 <<
"microseconds since reference: " << microsec_since_reference
251 glog.is(DEBUG2) &&
glog << group(glog_mac_group_) <<
"cycle duration: " << cycle_duration()
254 cycles_since_reference_ = microsec_since_reference / (cycle_duration() * 1000000) + 1;
256 glog.is(DEBUG2) &&
glog << group(glog_mac_group_)
257 <<
"cycles since reference: " << cycles_since_reference_ << std::endl;
259 double secs_to_next = cycles_since_reference_ * cycle_duration();
261 return reference + seconds(secs_to_next) +
262 microseconds((secs_to_next - floor(secs_to_next)) * 1000000);
267 glog.is(DEBUG1) &&
glog << group(glog_mac_group_) <<
"Updating MAC cycle." << std::endl;
269 if (std::list<protobuf::ModemTransmission>::size() == 0)
271 glog.is(DEBUG1) &&
glog << group(glog_mac_group_)
272 <<
"the MAC TDMA cycle is empty. Stopping timer" << std::endl;
278 current_slot_ = std::list<protobuf::ModemTransmission>::begin();
280 next_slot_t_ = next_cycle_time();
282 glog.is(DEBUG1) &&
glog << group(glog_mac_group_)
283 <<
"The next MAC TDMA cycle begins at time: " << next_slot_t_
287 if (cfg_.start_cycle_in_middle() && std::list<protobuf::ModemTransmission>::size() > 1 &&
288 (cfg_.type() == protobuf::MAC_FIXED_DECENTRALIZED || cfg_.type() == protobuf::MAC_POLLED))
290 glog.is(DEBUG1) &&
glog << group(glog_mac_group_)
291 <<
"Starting next available slot (in middle of cycle)" << std::endl;
294 next_slot_t_ -= boost::posix_time::microseconds(cycle_duration() * 1e6);
296 boost::posix_time::ptime now = goby_time();
299 while (next_slot_t_ < now) increment_slot();
301 glog.is(DEBUG1) &&
glog << group(glog_mac_group_) <<
"Next slot at " << next_slot_t_
309 double goby::acomms::MACManager::cycle_duration()
313 length += slot.slot_seconds();
Contains functions for adding color to Terminal window streams.
void startup(const protobuf::MACConfig &cfg)
Starts the MAC with given configuration.
ReturnType goby_time()
Returns current UTC time as a boost::posix_time::ptime.
const int BROADCAST_ID
special modem id for the broadcast destination - no one is assigned this address. Analogous to 192...
void add_group(const std::string &name, Colors::Color color=Colors::nocolor, const std::string &description="")
Add another group to the logger. A group provides related manipulator for categorizing log messages...
google::protobuf::int64 int64
a signed 64 bit integer
MACManager()
Default constructor.
void shutdown()
Shutdown the MAC.
common::FlexOstream glog
Access the Goby logger through this object.
boost::signals2::signal< void(const protobuf::ModemTransmission &m)> signal_slot_start
Signals the start of all transmissions (even when we don't transmit)
std::ostream & green(std::ostream &os)
All text following this manipulator is green (e.g. std::cout << green << "text";) ...
void restart()
Restarts the MAC with original configuration.
void update()
You must call this after any change to the underlying list that would invalidate iterators or change ...
boost::posix_time::ptime unix_double2ptime(double given_time)
convert to boost date_time ptime from the number of seconds (including fractional) since 1/1/1970 0:0...
boost::signals2::signal< void(const protobuf::ModemTransmission &m)> signal_initiate_transmission
Signals when it is time for this platform to begin transmission of an acoustic message at the start o...
std::ostream & nocolor(std::ostream &os)
All text following this manipulator is uncolored (e.g. std::cout << green << "green" << nocolor << "u...