Goby v2
goby-acomms: An overview of Acoustic Communications Library

Table of Contents for goby-acomms: An overview of Acoustic Communications Library.

Quick Start

To get started using the goby-acomms libraries as quickly as possible:

  1. If you haven't yet, follow instructions on installing Goby: http://gobysoft.com/wiki/InstallingGoby.
  2. Identify which components you need:
    • Encoding and decoding from C++ types to bit-packed messages: dccl.
    • Queuing of DCCL messages with priority based message selection: queue.
    • A driver for interacting with the acoustic modem firmware: modemdriver.
    • Time division multiple access (TDMA) medium access control (MAC): amac.
  3. Look at the "simple" code examples that accompany each component (dccl_simple.cpp, queue_simple.cpp, driver_simple.cpp, amac_simple.cpp). Then look at the example that uses all the components together: chat.cpp. The full list of examples is given in this table.
  4. Refer to the rest of the documentation as needed.

Please visit https://answers.launchpad.net/goby with any questions.

Overview

Analogy to established networking systems

To start on some (hopefully) common ground, let's begin with an analogy to Open Systems Initiative (OSI) networking layers in this table. For a complete description of the OSI layers see http://www.itu.int/rec/T-REC-X.200-199407-I/en.

OSI Layer Goby-Acomms library component API class(es) Example(s)
Application Not yet part of Goby MOOS Application: pAcommsHandler
Presentation dccl: Encoding and decoding goby::acomms::DCCLCodec dccl_simple.cpp
two_message.cpp
chat.cpp
Session Not used, sessions are established passively.
Transport queue: Priority based message queuing goby::acomms::QueueManager queue_simple.cpp
chat.cpp
Network Does not yet exist. All transmissions are considered single hop, currently. Addressing routing over multiple hops is an open and pressing research problem.
Data Link modemdriver: Modem driver classes derived from goby::acomms::ModemDriverBase; e.g. goby::acomms::MMDriver driver_simple.cpp
chat.cpp
amac: Medium Access Control (MAC) goby::acomms::MACManager amac_simple.cpp
chat.cpp
Physical Not part of Goby Modem Firmware, e.g. WHOI Micro-Modem Firmware (NMEA 0183 on RS-232) (see Interface Guide)

Acoustic Communications are slow

Do not take the previous analogy too literally; some things we are doing here for acoustic communications (hereafter, acomms) are unconventional from the approach of networking on electromagnetic carriers (hereafter, EM networking). The difference is a vast spread in the expected throughput of a standard internet hardware carrier and acoustic communications. For example, an optical fiber can put through greater than 10 Tbps over greater than 100 km, whereas the WHOI acoustic Micro-Modem can (at best) do 5000 bps over several km. This is a difference of thirteen orders of magnitude for the bit-rate distance product!

Efficiency to make messages small is good

Extremely low throughput means that essentially every efficiency in bit packing messages to the smallest size possible is desirable. The traditional approach of layering (e.g. TCP/IP) creates inefficiencies as each layer wraps the message of the higher layer with its own header. See RFC3439 section 3 ("Layering Considered Harmful") for an interesting discussion of this issue http://tools.ietf.org/html/rfc3439#page-7. Thus, the "layers" of goby-acomms are more tightly interrelated than TCP/IP, for example. Higher layers depend on lower layers to carry out functions such as error checking and do not replicate this functionality.

Total throughput unrealistic: prioritize data

The second major difference stemming from this bandwidth constraint is that total throughput is often an unrealistic goal. The quality of the acoustic channel varies widely from place to place, and even from hour to hour as changes in the sea affect propagation of sound. This means that it is also difficult to predict what one's throughput will be at any given time.

These two considerations manifest themselves in the goby-acomms design as a priority based queuing system for the transport layer. Messages are placed in different queues based on their priority (which is determined by the designer of the message). This means that the channel is always utilized (low priority data are sent when the channel quality is high) but important messages are not swamped by low priority data. In contrast, TCP/IP considers all packets equally. Packets made from a spam email are given the same consideration as a high priority email from the President. This is a trade-off in efficiency versus simplicity that makes sense for EM networking, but does not for acoustic communications.

Despite all this, simplicity is good

The "law of diminishing returns" means that at some point, if we try to optimize excessively, we will end up making the system more complex without substantial gain. Thus, goby-acomms makes some concessions for the sake of simplicity:

Component model

A relatively simple component model for the goby-acomms library showing the interface classes :

goby-acomms-overview.png
For a more detailed model, see the UML models section.

dccl: Encoding and decoding

The Dynamic Compact Control Language (DCCL) provides a structure for defining messages to be sent through an acoustic modem. The messages are configured in Google Protocol Buffers and are intended to be easily reconfigurable, unlike the original CCL framework used in the REMUS vehicles and others (for information on CCL, see http://acomms.whoi.edu/ccl/.

Unlike the encoder / decoder provided with Google Protocol Buffers, each field (which could be a primitive type like double, int32, string or an user-defined embedded message like CTDMessage) of a DCCL message can be encoded using a DCCL built-in or user-defined encoder. This allows the codecs to be matched to the data's physical origins and thus make the most of the limited throughput available by making very small encoded messages.

Detailed documentation for goby-acomms: DCCL (Dynamic Compact Control Language).

queue: Priority based message queuing

The goby-acomms queuing (queue) component interacts with both the application level process and the modem driver process that talks directly to the modem.

On the application side, queue provides the ability for the application level process to push DCCL messages to various queues and receive messages from a remote sender that correspond to messages in the same queue (e.g. you have a queue for STATUS_MESSAGE that you can push messages to you and also receive other STATUS_MESSAGEs on). The push feature is called by the application level process and received messages are signaled to all previous bound slots (see Signal / Slot model for asynchronous events).

On the driver side, queue provides the modem driver with data upon request. It chooses the data to send based on dynamic priorities (and several other configuration parameters). It will also pack as many messages from the user into a single frame from the modem as possible using the DCCLCodec's repeated encoding functionality. Note, however, that queue will not split a user's data into frames (like TCP/IP). If this functionality is desired, it must be provided at the application layer. Acoustic communications are too unpredictable to reliably stitch together frames.

Detailed documentation for goby-acomms: queue (Message Priority Queuing).

modemdriver: Modem driver

The goby-acomms Modem driver component (modemdriver) of the Goby-Acomms library provides an interface from the rest of goby-acomms to the acoustic modem firmware. While currently the only driver publicly available is for the WHOI Micro-Modem (and for an example toy modem "ABCDriver"), this component is written in such a way that drivers for any acoustic modem that interfaces over a serial or TCP connection and can provide (or provide abstractions for) sending data directly to another modem on the link should be able to be written. Any one who is interested in writing a modem driver for another acoustic modem should get in touch with the goby project https://launchpad.net/goby and see Writing a new driver.

Detailed documentation for goby-acomms: modemdriver (Driver to interact with modem firmware).

amac: Medium Access Control (MAC)

The goby-acomms MAC component (amac) handles access to the shared medium, in our case the acoustic channel. We assume that we have a single (frequency) band for transmission so that if vehicles transmit simultaneously, collisions will occur between messaging. Therefore, we use time division multiple access (TDMA) schemes, or "slotting". Networks with multiple frequency bands will have to employ a different MAC scheme or augment amac for the frequency division multiple access (FDMA) scenario.

The Goby AMAC provides two basic types of TDMA:

Detailed documentation for goby-acomms: amac (Medium Access Control).

Software concepts used in goby-acomms

Signal / Slot model for asynchronous events

The layers of goby-acomms use a signal / slot system for asynchronous events such as receipt of an acoustic message. Each signal can be connected (goby::acomms::connect()) to one or more slots, which are functions or member functions matching the signature of the signal. When the signal is emitted, the slots are called in order they were connected. To ensure synchronous behavior and thread-safety throughout goby-acomms, signals are only emitted during a call to a given component's API class do_work method (i.e. goby::acomms::ModemDriverBase::do_work(), goby::acomms::QueueManager::do_work(), goby::acomms::MACManager::do_work()).

For example, if I want to receive data from queue, I need to connect to the signal QueueManager::signal_receive. Thus, I need to define a function or class method with the same signature:

void receive_data(const google::protobuf::Message& msg);

At startup, I then connect the signal to the slot:

goby::acomms::connect(&q_manager.signal_receive, &receive_data);

If instead, I was using a member function such as

class MyApplication
{
public:
void receive_data(const google::protobuf::Message& msg);
};

I would call connect (probably in the constructor for MyApplication) passing the pointer to the class:

MyApplication::MyApplication()
{
goby::acomms::connect(&q_manager.signal_receive, this, &MyApplication::receive_data);
}

The Boost.Signals library is used without modification, so for details see http://www.boost.org/doc/libs/1_46_0/doc/html/signals.html. Member function binding is provided by Boost Bind http://www.boost.org/doc/libs/1_46_0/libs/bind/bind.html

Google Protocol Buffers

Google Protocol Buffers are used as a convenient way of generating data structures (basic classes with accessors, mutators). They can also be serialized efficiently, though this is not generally used within goby-acomms. Protocol buffers messages are defined in .proto files that have a C-like syntax:

message MyMessage
{
   optional uint32 a = 1;
   required string b = 2;
   repeated double c = 3;
}

The identifier "optional" means a proper MyMessage object may or may not contain that field. "required" means that a proper MyMessage always contains such a field. "repeated" means a MyMessage can contain a vector of this field (0 to n entries). The sequence number "= 1" must be unique for each field and determines the serialized format on the wire. For our purposes it is otherwise insignificant. See http://code.google.com/apis/protocolbuffers/docs/proto.html for full details.

The .proto file is pre-compiled into a C++ class that is loosely speaking (see http://code.google.com/apis/protocolbuffers/docs/reference/cpp-generated.html for precise details):

class MyMessage : public google::protobuf::Message
{
public:
MyMessage ();
// set
void set_a(unsigned a);
void set_b(const std::string& b);
void add_c(double c);
// get
unsigned a();
std::string b();
double c(int index);
const RepeatedField<double>& c(); // RepeatedField ~= std::vector
// has
bool has_a();
bool has_b();
int c_size();
// clear
void clear_a();
void clear_b();
void clear_c();
private:
unsigned a_;
std::string b_;
RepeatedField<double> c_; // RepeatedField ~= std::vector
}

Clearly the .proto representation is more compact and amenable to easy modification. All the Protocol Buffers messages used in goby-acomms are placed in the goby::acomms::protobuf namespace for easy identification. This doxygen documentation does not understand Protocol Buffers language so you will need to look at the source code directly for the .proto (e.g. acomms_modem_message.proto).

UML models

Model that gives the sequence for sending a message with goby-acomms:

goby-acomms-send-message-sequence.png

Model that shows the commands needed to start and keep goby-acomms running:

goby-acomms-background-sequence.png
–>