Note: Goby version 1 (shown here) is now considered obsolete. Please use version 2 for new projects, and consider upgrading old projects.

Goby Underwater Autonomy Project  Series: 1.1, revision: 163, released on 2013-02-06 14:23:27 -0500
acomms/chat/chat.cpp

chat.xml

<?xml version="1.0" encoding="UTF-8"?>
<message_set>
  <message>
    <name>Chat</name>
    <id>1</id>
    <size>32</size>
    <queuing>
      <ack>true</ack>
      <newest_first>false</newest_first>
    </queuing>
    <layout>
      <string>
        <name>message</name>
        <max_length>26</max_length>
      </string>      
    </layout>

    <!-- only used by pAcommsHandler (publish/subscribe)-->
    <trigger>publish</trigger> <!-- pack -->
    <trigger_var>OUT_MESSAGE</trigger_var>
    <on_receipt> <!-- unpack -->
      <publish>
        <publish_var>IN_MESSAGE</publish_var>
        <message_var>message</message_var>
      </publish>
    </on_receipt>
    <!-- end used by pAcommsHandler -->

  </message>
</message_set>

chat.cpp

// copyright 2009 t. schneider tes@mit.edu
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This software is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this software.  If not, see <http://www.gnu.org/licenses/>.

// usage: connect two modems and then run
// > chat /dev/tty_modem_A 1 2 log_file_A
// > chat /dev/tty_modem_B 2 1 log_file_B

// type into a window and hit enter to send a message. messages will be queued
// and sent on a fixed rotating cycle

#include <iostream>

#include "goby/acomms/dccl.h"
#include "goby/acomms/queue.h"
#include "goby/acomms/modem_driver.h"
#include "goby/acomms/amac.h"
#include "goby/acomms/bind.h"
#include "goby/util/string.h"
#include "goby/util/time.h"

#include <boost/lexical_cast.hpp>

#include "chat_curses.h"

using goby::util::as;
using goby::util::goby_time;

int startup_failure();
void received_data(const goby::acomms::protobuf::ModemDataTransmission&);
void received_ack(const goby::acomms::protobuf::ModemDataAck&);
std::string decode_received(const std::string& data);
void monitor_mac(const goby::acomms::protobuf::ModemMsgBase* mac_msg);

std::ofstream fout_;
goby::acomms::DCCLCodec dccl_(&fout_);
goby::acomms::QueueManager q_manager_(&fout_);
goby::acomms::MMDriver mm_driver_(&fout_);
goby::acomms::MACManager mac_(&fout_);
ChatCurses curses_;
int my_id_;
int buddy_id_;


int main(int argc, char* argv[])
{
    //
    // 1. Deal with command line parameters
    //
    
    if(argc != 5) return startup_failure();
    
    std::string serial_port = argv[1];
    try
    {
        my_id_ = boost::lexical_cast<int>(argv[2]);
        buddy_id_ = boost::lexical_cast<int>(argv[3]);
    }
    catch(boost::bad_lexical_cast&)
    {
        std::cerr << "bad value for my_id: " << argv[2] << " or buddy_id: " << argv[3] << ". these must be unsigned integers." << std::endl;
        return startup_failure();        
    }

    std::string log_file = argv[4];
    fout_.open(log_file.c_str());
    if(!fout_.is_open())
    {
        std::cerr << "bad value for log_file: " << log_file << std::endl;
        return startup_failure();        
    }    

    // bind the signals of these libraries
    bind(mm_driver_, q_manager_, mac_);
    
    //
    // Initiate DCCL (libdccl)
    //
    goby::acomms::protobuf::DCCLConfig dccl_cfg;
    dccl_cfg.add_message_file()->set_path(ACOMMS_EXAMPLES_DIR "/chat/chat.xml");
    
    //
    // Initiate queue manager (libqueue)
    //
    goby::acomms::protobuf::QueueManagerConfig q_manager_cfg;
    q_manager_cfg.set_modem_id(my_id_);
    goby::acomms::connect(&q_manager_.signal_receive, &received_data);
    goby::acomms::connect(&q_manager_.signal_ack, &received_ack);
    for(int i = 0, n = dccl_cfg.message_file_size(); i < n; ++i)
        q_manager_cfg.add_message_file()->CopyFrom(dccl_cfg.message_file(i));

    //
    // Initiate modem driver (libmodemdriver)
    //
    goby::acomms::protobuf::DriverConfig driver_cfg;
    driver_cfg.set_modem_id(my_id_);
    driver_cfg.set_serial_port(serial_port);
    driver_cfg.AddExtension(MicroModemConfig::nvram_cfg, "SRC," + as<std::string>(my_id_));

    //
    // Initiate medium access control (libamac)
    //
    goby::acomms::protobuf::MACConfig mac_cfg;
    mac_cfg.set_type(goby::acomms::protobuf::MAC_FIXED_DECENTRALIZED);
    mac_cfg.set_modem_id(my_id_);
    goby::acomms::connect(&mac_.signal_initiate_transmission, &monitor_mac);
    
    goby::acomms::protobuf::Slot my_slot;
    my_slot.set_src(my_id_);
    my_slot.set_dest(buddy_id_);
    my_slot.set_rate(0);
    my_slot.set_slot_seconds(12);  
    my_slot.set_type(goby::acomms::protobuf::SLOT_DATA);
    
    goby::acomms::protobuf::Slot buddy_slot;
    buddy_slot.set_src(buddy_id_);
    buddy_slot.set_dest(my_id_);
    buddy_slot.set_rate(0);
    buddy_slot.set_slot_seconds(12);
    buddy_slot.set_type(goby::acomms::protobuf::SLOT_DATA);

    if(my_id_ < buddy_id_)
    {
        mac_cfg.add_slot()->CopyFrom(my_slot);
        mac_cfg.add_slot()->CopyFrom(buddy_slot);
    }
    else
    {
        mac_cfg.add_slot()->CopyFrom(buddy_slot);
        mac_cfg.add_slot()->CopyFrom(my_slot);
    }    
    
    //
    // Start up everything
    //
    try
    {
        dccl_.set_cfg(dccl_cfg);
        q_manager_.set_cfg(q_manager_cfg);
        mac_.startup(mac_cfg);
        mm_driver_.startup(driver_cfg);
    }
    catch(std::runtime_error& e)
    {
        std::cerr << "exception at startup: " << e.what() << std::endl;
        return startup_failure();
    }
    
    curses_.set_modem_id(my_id_);    
    curses_.startup();
    
    //
    // Loop until terminated (CTRL-C)
    //
    for(;;)
    {
        std::string line;
        curses_.run_input(line);

        if(!line.empty())
        {
            std::map<std::string, goby::acomms::DCCLMessageVal> vals;
            vals["message"] = line;

            std::string bytes_out;

            unsigned message_id = 1;
            dccl_.encode(message_id, bytes_out, vals);
            
            goby::acomms::protobuf::ModemDataTransmission message_out;
            message_out.set_data(bytes_out);
            // send this message to my buddy!
            message_out.mutable_base()->set_dest(buddy_id_);
            // set the time of this message
            message_out.mutable_base()->set_time(as<std::string>(goby_time()));

            message_out.mutable_queue_key()->set_id(message_id);
            q_manager_.push_message(message_out);
        }
            
        try
        {
            mm_driver_.do_work();
            mac_.do_work();
            q_manager_.do_work();
        }
        catch(std::runtime_error& e)
        {
            curses_.cleanup();
            std::cerr << "exception while running: " << e.what() << std::endl;
            return 1;
        }
    }
    
    return 0;
}

int startup_failure()
{
    std::cerr << "usage: chat /dev/tty_modem my_id buddy_id log_file" << std::endl;
    return 1;
}

void monitor_mac(const goby::acomms::protobuf::ModemMsgBase* mac_msg)
{
    if(mac_msg->src() == my_id_)
        curses_.post_message("{control} starting send to my buddy");
    else if(mac_msg->src() == buddy_id_)
        curses_.post_message("{control} my buddy might be sending to me now");
}

void received_data(const goby::acomms::protobuf::ModemDataTransmission& message_in)
{    
    curses_.post_message(message_in.base().src(), decode_received(message_in.data()));
}

void received_ack(const goby::acomms::protobuf::ModemDataAck& ack_message)
{   
    curses_.post_message
        (ack_message.base().src(),
         std::string("{ acknowledged receiving message starting with: "
                     + decode_received(ack_message.orig_msg().data()).substr(0,5)) + " }");
}

std::string decode_received(const std::string& data)
{
    std::map<std::string, goby::acomms::DCCLMessageVal> vals;
    dccl_.decode(data, vals);
    return vals["message"];
}
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends