MobileNode.cc

00001 // Copyright 2008 Michael Marsh, University of Maryland.
00002 //
00003 // This file is part of pydtn.
00004 //
00005 // pydtn is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation, either version 3 of the License, or
00008 // (at your option) any later version.
00009 //
00010 // pydtn is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with pydtn.  If not, see <http://www.gnu.org/licenses/>.
00017 //
00018 // The views and conclusions contained in the software and documentation
00019 // are those of the authors and should not be interpreted as representing
00020 // official policies, either expressed or implied, of the University
00021 // of Maryland.
00022 //
00023 // pydtn extends and embeds the Python interpreter, which is
00024 // Copyright 2001-2006 Python Software Foundation, All Rights Reserved,
00025 // and is released under the PSF License Agreement.
00026 //
00027 // RANLUX random number generation uses the Boost library,
00028 // Copyright 1994-2006 by various authors (details in individual files),
00029 // which is released under the Boost Software License, Version 1.0.
00030 
00031 #include "simlpy/interpreter_defs.h"
00032 #include "simlpy/interpreter_hooks.h"
00033 
00034 #include "MobileNode.h"
00035 #include "BeaconConsumer.h"
00036 #include "MobileApp.h"
00037 #include "pydtn/BundleEvent.h"
00038 #include "simlpy/Clock.h"
00039 #include "simlpy/SimulationException.h"
00040 
00041 #include <iostream>
00042 #include <stdlib.h>
00043 
00044 using namespace Mobility;
00045 
00046 const std::string MobileNode::kIdentifier( "node:mobile" );
00047 
00048 MobileNode::MobileNode() :
00049    m_beaconTime( 0 )
00050 {
00051    m_beaconC = new BeaconConsumer( this );
00052    addConsumer( m_beaconC );
00053 }
00054 
00055 MobileNode::~MobileNode()
00056 {
00057    // We don't hold the memory to the BeaconConsumer here.
00058 }
00059 
00060 Entity*
00061 MobileNode::create() const
00062 {
00063    MobileNode* n = new MobileNode;
00064    n->trigger();
00065    return n;
00066 }
00067 
00068 void
00069 MobileNode::configure( const ArgList& args )
00070 {
00071    unsigned int nargs = args.size();
00072    if ( nargs < 2 )
00073    {
00074       std::cerr << "config() takes at least 2 arguments ("
00075                 << nargs << " given)"
00076                 << std::endl;
00077       throw SimulationException( __FILE__ , __LINE__ );
00078    }
00079    std::string command = parse_string(args[0]);
00080    if ( "position" == command )
00081    {
00082       if ( nargs < 2 )
00083       {
00084          std::cerr << "config('position') requires at least two coordinates"
00085                    << std::endl;
00086          throw SimulationException( __FILE__ , __LINE__ );
00087       }
00088       Position pos = parse_position( args[1] );
00089       setWaypoint( Presence( Clock::time(), pos, Time() ) );
00090       return;
00091    }
00092    if ( "beacon" == command )
00093    {
00094       if ( nargs < 2 )
00095       {
00096          std::cerr << "config('beacon') requires at least two coordinates"
00097                    << std::endl;
00098          throw SimulationException( __FILE__ , __LINE__ );
00099       }
00100       if ( 0 == m_beaconC )
00101       {
00102          std::cerr << "No beacon manager was found at this node." << std::endl;
00103          throw SimulationException( __FILE__ , __LINE__ );
00104       }
00105       m_beaconTime = parse_double( args[1] );
00106       double t = 3 * m_beaconTime;
00107       long int ts = (long int) ::floor( t );
00108       long int tus = (long int) ( Time::MILLION * ( t - ::floor(t) ) );
00109       m_beaconC->setTimeout( Time(ts,tus) );
00110       return;
00111    }
00112    WrapNode::configure(args);
00113 }
00114 
00115 void
00116 MobileNode::emit( const ArgList& args )
00117 {
00118    unsigned int nargs = args.size();
00119    if ( nargs < 3 )
00120    {
00121       std::cerr << "emit() takes at least 3 arguments ("
00122                 << nargs << " given)"
00123                 << std::endl;
00124       throw SimulationException( __FILE__ , __LINE__ );
00125    }
00126 
00127    Time t = parse_time(args[0]);
00128 
00129    std::string command = parse_string(args[1]);
00130 
00131    if ( "waypoint" == command )
00132    {
00133       if ( nargs < 6 )
00134       {
00135          std::cerr << "emit(t,'waypoint') takes at least 6 arguments ("
00136                    << nargs << " given)"
00137                    << std::endl;
00138          throw SimulationException( __FILE__ , __LINE__ );
00139       }
00140       Time wpt = parse_time(args[2]);
00141       Time wpd = parse_time(args[3]);
00142       Position pos = parse_position( args[4] );
00143       Clock::schedule( new WaypointEvent(this,this,t,Presence(wpt,pos,wpd)) );
00144       return;
00145    }
00146 
00147    WrapNode::emit(args);
00148 }
00149 
00150 InterpreterItem
00151 MobileNode::get( const ArgList& args )
00152 {
00153    unsigned int nargs = args.size();
00154    if ( 0 == nargs )
00155    {
00156       std::cerr << "No attribute specified" << std::endl;
00157       throw SimulationException( __FILE__ , __LINE__ );
00158    }
00159 
00160    std::string attr = parse_string(args[0]);
00161 
00162    if ( "position" == attr )
00163    {
00164       Position p = position();
00165       ArgList alist;
00166       alist.push_back( construct_double( p.x() ) );
00167       alist.push_back( construct_double( p.y() ) );
00168       alist.push_back( construct_double( p.z() ) );
00169       return construct_list( alist );
00170    }
00171    if ( "beacon_interval" == attr )
00172    {
00173       return construct_double( m_beaconTime );
00174    }
00175    if ( "last_beacon" == attr )
00176    {
00177       ArgList alist;
00178       alist.push_back( construct_long( m_lastBeacon.tv.tv_sec ) );
00179       alist.push_back( construct_long( m_lastBeacon.tv.tv_usec ) );
00180       return construct_list( alist );
00181    }
00182    if ( "visible" == attr )
00183    {
00184       if ( 0 == m_beaconC )
00185       {
00186          std::cerr << "mobile node has no beacon consumer attached"
00187                    << std::endl;
00188          throw SimulationException( __FILE__ , __LINE__ );
00189       }
00190       return m_beaconC->visible_list();
00191    }
00192 
00193    return WrapNode::get(args);
00194 }
00195 
00196 void
00197 MobileNode::addMobileApp( MobileApp* app )
00198 {
00199    if ( 0 == app ) return;
00200    addApplication(app);
00201    m_mobileApps.push_back(app);
00202 }
00203 
00204 bool
00205 MobileNode::handler( WaypointEvent& event )
00206 {
00207    setWaypoint( event.waypoint() );
00208    return true;
00209 }
00210 
00211 bool
00212 MobileNode::handler( HelloTrigger& event )
00213 {
00214    if ( 0 == m_beaconC ) return false;
00215    Time t = Clock::time();
00216 
00217    // Do we need to send a HELLO message?
00218    bool needBeacon = m_beaconC->lastSend() <= m_lastBeacon;
00219    m_lastBeacon = m_beaconC->lastSend();
00220    if ( needBeacon )
00221    {
00222       DTN::Bundle::BundleType type =
00223          DTN::Bundle::kBcast | DTN::Bundle::kNoACK;
00224       Time e = t + bundleLifetime();
00225       DTN::Bundle* b =
00226          new DTN::Bundle( node().nextSeq(),
00227                           addr(),
00228                           addr(),
00229                           DTN::ByteString(),
00230                           t.tv,
00231                           e.tv,
00232                           type );
00233       if ( 0 != b )
00234       {
00235          // We don't add this bundle to the stable store, hence the "false".
00236          Clock::tentative( new BundleEvent(this,this,t,t,b,false) );
00237          m_lastBeacon = t;
00238       }
00239    }
00240 
00241    // Schedule the next trigger event.
00242    double d = m_beaconTime/2 + m_beaconTime*prng();
00243    long int ds = (long int) ::floor(d);
00244    long int dus = (long int) ( Time::MILLION * ( d - ::floor(d) ) );
00245    Time tTrig = t + Time(ds,dus);
00246    Clock::tentative( new HelloTrigger(this,this,tTrig) );
00247 
00248    m_beaconC->clean();
00249    return true;
00250 }
00251 
00252 Position
00253 MobileNode::position() const
00254 {
00255    return position( Clock::time() );
00256 }
00257 
00258 Position
00259 MobileNode::position( const Time& t ) const
00260 {
00261    // We need at least one actual point for this to be meaningful.
00262    if ( 0 == m_waypoints.size() ) return Position();
00263 
00264    Presence key( t, Position(), Time() );
00265    PresenceSet::const_iterator after = m_waypoints.lower_bound(key);
00266    PresenceSet::const_iterator before = after;
00267    --before;
00268 
00269    // The specified time is after the last movement completed.
00270    if ( m_waypoints.end() == after )
00271    {
00272       return before->position();
00273    }
00274 
00275    // We're exactly at a waypoint.
00276    if ( *after == t )
00277    {
00278       return after->position();
00279    }
00280    // Or we're paused at a waypoint.
00281    if ( ( t - before->time() ) < before->duration() )
00282    {
00283       return before->position();
00284    }
00285 
00286    // We're before the first waypoint (which shouldn't generally happen).
00287    if ( m_waypoints.begin() == after )
00288    {
00289       return Position();
00290    }
00291 
00292    // The normal case.  We need to interpolate the position.
00293    Presence current = before->towards( *after, t );
00294 
00295    return current.position();
00296 }
00297 
00298 bool
00299 MobileNode::visible( const DTN::ByteString& addr )
00300 {
00301    if ( 0 == m_beaconC ) return false;
00302    return m_beaconC->visible(addr);
00303 }
00304 
00305 void
00306 MobileNode::trigger()
00307 {
00308    Clock::tentative( new HelloTrigger(this,this,Clock::time()) );
00309 }
00310 
00311 void
00312 MobileNode::notifyApps( const DTN::ByteString& addr )
00313 {
00314    MobileAppList::iterator itr = m_mobileApps.begin();
00315    MobileAppList::iterator end = m_mobileApps.end();
00316    for ( ; itr != end ; ++itr )
00317    {
00318       (*itr)->newNeighbor(addr);
00319    }
00320 }
00321 
00322 void
00323 MobileNode::setWaypoint( const Presence& wp )
00324 {
00325    if ( wp.time() < Clock::time() )
00326    {
00327       std::cerr << "Cannot schedule a waypoint in the past"
00328                 << std::endl;
00329       throw SimulationException( __FILE__ , __LINE__ );
00330    }
00331    m_waypoints.insert( wp );
00332 }
00333 
00334 Position
00335 MobileNode::parse_position( const InterpreterItem p )
00336 {
00337    double x = 0;
00338    double y = 0;
00339    double z = 0;
00340    if ( ! PyList_Check( p ) )
00341    {
00342       throw SimulationException( __FILE__ , __LINE__ );
00343    }
00344    int n = PyList_Size( p );
00345 
00346    if ( n < 2 )
00347    {
00348       throw SimulationException( __FILE__ , __LINE__ );
00349    }
00350    x = parse_double( PyList_GetItem(p,0) );
00351    y = parse_double( PyList_GetItem(p,1) );
00352    if ( n > 2 )
00353    {
00354       z = parse_double( PyList_GetItem(p,2) );
00355    }
00356    return Position( x, y, z );
00357 }

Generated on Mon Mar 24 11:15:45 2008 for Pydtn Simulator by  doxygen 1.5.4