Goby3  3.1.4
2024.02.22
goby-acomms: amac (Medium Access Control)

Supported MAC schemes

The Medium Access Control schemes provided by amac are based on Time Division Multiple Access (TDMA) where different communicators share the same bandwidth but transmit at different times to avoid conflicts. Time is divided into slots and each vehicle is given a slot to transmit on. The set of slots comprising all the vehicles is referred to here as a cycle, which repeats itself when it reaches the end. MACManager is implemented as a timer and a std::list of goby::acomms::protobuf::ModemTransmission objects. This allows you to use amac to create a TDMA cycle for any type of transmission (data, ping, LBL, etc.) that your modem supports.

The two variations on this scheme provided by amac are:

  • Decentralized: Each vehicle initiates its own transmission at the start of its slot. (goby::acomms::protobuf::MAC_FIXED_DECENTRALIZED): Slots are set at launch and can be updated using the std::list insert, push, pop, erase, etc. Each vehicle can have more than one slot in the cycle. The cycles must agree across all platforms; the network designer is responsible for this. Most of the time you will want to use this mode.
  • Centralized Polling (goby::acomms::protobuf::MAC_POLLED on the master, goby::acomms::protobuf::MAC_NONE on all other nodes): The TDMA cycle is set up and operated by a centralized master modem ("poller"), which is usually the modem connected to the vehicle operator's topside. The poller initiates each transmission and thus the vehicles are not required to maintain synchronous clocks. This mode requires third-party initiation of transmissions to function.

Interacting with the goby::acomms::MACManager

To use the goby::acomms::MACManager, you need to instantiate it:

goby::acomms::MACManager mac;

Then you need to provide a callback (or "slot", not to be confused with a TDMA slot) for initiated transmissions for the signal goby::acomms::MACManager::signal_initiate_transmission. This signal will be called when the goby::acomms::MACManager determines it is time to send a message. If using modemdriver, simply call goby::acomms::bind(goby::acomms::MACManager&, goby::acomms::ModemDriverBase&) to bind this callback to the modem driver.

Next you need to decide which type of MAC to use: decentralized fixed or centralized polling and set the type of the goby::acomms::protobuf::MACConfig with the corresponding goby::acomms::protobuf::MACType. We also need to give goby::acomms::MACManager the vehicle's modem id (like all the other components of goby-acomms):

using namespace goby::acomms;
protobuf::MACConfig mac_cfg;
mac_cfg.set_type(protobuf::MAC_FIXED_DECENTRALIZED);
mac_cfg.set_modem_id(1);

You can also provide a set of slots in the protobuf::MACConfig to initialize the MACManager with. Otherwise, you can add them later using the std::list calls.

The usage of the goby::acomms::MACManager depends now on the type:

goby::acomms::protobuf::ModemTransmission slot;
slot.set_src(1);
slot.set_dest(goby::acomms::QUERY_DESTINATION_ID);
slot.set_rate(0);
slot.set_type(goby::acomms::protobuf::SLOT_DATA);
slot.set_seconds(10);
mac.push_back(slot); // 1->-1@0 wait 10
slot.set_src(3);
mac.push_back(slot); // 3->-1@0 wait 10
slot.set_rate(5);
mac.push_back(slot); // 3->-1@5 wait 10
slot.set_src(4);
slot.set_rate(0);
mac.push_back(slot); // 4->-1@0 wait 10
mac.update() // important - call update() after any modifying changes to the MACManager underlying std::list!
  • goby::acomms::protobuf::MAC_POLLED: On the vehicles, you do not need to run the goby::acomms::MACManager at all, or simply give it the "do nothing" goby::acomms::protobuf::MAC_NONE type. All the MAC is done on the topside (the centralized poller). On the poller, you need to manually set up a list of vehicles to be polled by adding an goby::acomms::protobuf::Slot (in the initial goby::acomms::protobuf::MACConfig object or at runtime via goby::acomms::MACManager::add_slot()) for each vehicle to be polled. You can poll the same vehicle multiple times, just add more goby::acomms::protobuf::Slot objects corresponding to that vehicle. Each slot has a source, destination, rate, type (data), and length (in seconds). If the source is the poller, you can set the destination to goby::acomms::QUERY_DESTINATION_ID (=-1) to let queue determine the next destination (based on the highest priority message to send). All goby::acomms::protobuf::Slot objects for vehicles must have a specified destination (the goby::acomms::BROADCAST_ID is a good choice or the id of the poller). For example:
// poll ourselves (for commands, perhaps)
goby::acomms::protobuf::ModemTransmission slot;
slot.set_src(1);
slot.set_dest(goby::acomms::QUERY_DESTINATION_ID);
slot.set_rate(0);
slot.set_type(goby::acomms::protobuf::ModemTransmission::DATA);
slot.SetExtension(goby::acomms::protobuf::slot_seconds, 10);
mac_cfg.add_slot(slot); // 1->-1@0 wait 10
// reuse slot
slot.set_src(3);
slot.set_dest(goby::acomms::BROADCAST_ID);
mac_cfg.add_slot(slot); // 3->0@0 wait 10
slot.set_rate(5);
mac_cfg.add_slot(slot); // 3->0@5 wait 10
slot.set_src(4);
slot.set_rate(0);
mac_cfg.add_slot(slot); // 4->0@0 wait 10

You can remove vehicles by a call to goby::acomms::MACManager::remove_slot or clear out the entire cycle and start over with goby::acomms::MACManager::clear_all_slots.

Then, for either MAC scheme, start the goby::acomms::MACManager running (goby::acomms::MACManager::startup with the goby::acomms::protobuf::MACConfig object), and call goby::acomms::MACManager::do_work() periodically (5 Hz is ok, 10 Hz is better).

You can modify the MAC scheme while MACManager is running. Simply use the std::list insert, push, pop, erase methods to changes slots (goby::acomms::protobuf::ModemTransmission objects). After any changes that invalidate std::list iterators (insert, push, pop, erase), you must call goby::acomms::MACManager::update() before the next call to goby::acomms::MACManager::do_work().

See acomms/amac/amac_simple/amac_simple.cpp for a basic complete example.