00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 #include "OSDLPeriodicalActiveObject.h"
00028 
00029 
00030 #include "OSDLScheduler.h"        
00031 
00032 
00033 
00034 using std::string ;
00035 using std::list ;
00036 
00037 using Ceylan::Maths::Hertz ;
00038 
00039 
00040 
00041 #include "Ceylan.h"               
00042 using namespace Ceylan::Log ;
00043 
00044 
00045 using namespace OSDL::Engine ;
00046 using namespace OSDL::Events ;
00047 
00048 
00049 
00050 
00051 
00052 
00053 PeriodicalActiveObject::PeriodicalActiveObject( 
00054         Ceylan::System::Millisecond periodDuration, 
00055         bool autoRegister,
00056         Ceylan::Maths::Percentage maxErrorPercentage ) : 
00057     ActiveObject(  relaxed,  1 ),
00058     _period( 0 ),
00059     _subslot(  static_cast<Events::Period>( -1 ) )
00060 {
00061 
00062     Scheduler & scheduler = Scheduler::GetExistingScheduler() ;
00063 
00064     
00065     Ceylan::System::Microsecond engineTickDuration =
00066         scheduler.getTimeSliceDuration() ;  
00067         
00068     Events::Period engineTickCount = scheduler.getSimulationTickCount() ;
00069     
00070     Ceylan::System::Microsecond simulationTickDuration = 
00071         engineTickDuration * engineTickCount ;
00072         
00073     _period = Ceylan::Maths::Round( static_cast<Ceylan::Float32>(
00074             (1000 * periodDuration) / simulationTickDuration ) );
00075         
00076     if ( _period == 0 )
00077         _period = 1 ;
00078     
00079     
00080     Ceylan::System::Millisecond computedBackPeriodDuration = 
00081         _period * simulationTickDuration / 1000  ;
00082         
00083     if ( ! Ceylan::Maths::AreRelativelyEqual<Ceylan::Float32>(
00084              periodDuration, computedBackPeriodDuration, 
00085              maxErrorPercentage / 100.0f  ) )
00086         throw SchedulingException(
00087             "PeriodicalActiveObject constructor failed: "
00088             "unable to be within an error percentage of " 
00089             + Ceylan::toNumericalString( maxErrorPercentage ) 
00090             + "%: requested period duration is " 
00091             + Ceylan::toString( periodDuration ) 
00092             + " milliseconds, whereas best determined period duration is " 
00093             + Ceylan::toString( computedBackPeriodDuration ) 
00094             + " milliseconds." ) ;
00095             
00096     if ( autoRegister )
00097         registerToScheduler() ; 
00098              
00099 }
00100 
00101 
00102 
00103 PeriodicalActiveObject::PeriodicalActiveObject( Period period,
00104         bool autoRegister, ObjectSchedulingPolicy policy, Weight weight ) : 
00105     ActiveObject( policy, weight ),
00106     _period( period ),
00107     _subslot(  period + 1 )
00108 {
00109     
00110     if ( period == 0 )
00111         throw SchedulingException( "PeriodicalActiveObject constructor failed: "
00112             "period must not be null." ) ;
00113             
00114     if ( autoRegister )
00115         registerToScheduler() ; 
00116             
00117 }
00118 
00119 
00120     
00121 PeriodicalActiveObject::~PeriodicalActiveObject() throw()
00122 {
00123 
00124     if ( _registered )
00125     {
00126     
00127         try
00128         {
00129     
00130             unregisterFromScheduler() ;
00131             
00132         }
00133         catch( const SchedulingException & e )
00134         {
00135     
00136             LogPlug::error( "PeriodicalActiveObject destructor failed: "
00137                 + e.toString() ) ;
00138     
00139         }
00140         
00141     }
00142     
00143 }
00144 
00145 
00146 
00147 
00148 
00149 
00150 
00151 
00152 void PeriodicalActiveObject::registerToScheduler()
00153 {
00154     
00155     if ( _registered )
00156         throw SchedulingException( 
00157             "PeriodicalActiveObject::registerToScheduler failed: "
00158             "already registered." ) ;
00159             
00160     Scheduler & scheduler = Scheduler::GetExistingScheduler() ;
00161     
00162     
00163     scheduler.registerPeriodicalObject( *this ) ;
00164     
00165 }
00166     
00167                 
00168 
00169 void PeriodicalActiveObject::unregisterFromScheduler() 
00170 {
00171 
00172     
00173     
00174     if ( ! _registered )
00175         throw SchedulingException( 
00176             "PeriodicalActiveObject::unregisterFromScheduler failed: "
00177             "not already registered." ) ;
00178             
00179     Scheduler & scheduler = Scheduler::GetExistingScheduler() ;
00180     
00181     scheduler.unregisterPeriodicalObject( *this ) ;
00182     
00183     _registered = false ;
00184     
00185 }
00186 
00187 
00188 
00189 
00190 
00191 
00192 
00193 
00194 Period PeriodicalActiveObject::getPeriod() const
00195 {
00196 
00197     return _period ;
00198     
00199 }
00200 
00201 
00202 
00203 void PeriodicalActiveObject::setPeriod( Period newPeriod ) 
00204 {
00205 
00206     if ( _registered ) 
00207         throw SchedulingException( "PeriodicalActiveObject::setPeriod failed: "
00208             "already registered to scheduler." ) ;
00209             
00210     _period = newPeriod ;
00211     
00212 }
00213 
00214 
00215 
00216 Hertz PeriodicalActiveObject::setFrequency( Hertz newFrequency ) 
00217 {
00218 
00219     if ( _registered ) 
00220         throw SchedulingException( 
00221             "PeriodicalActiveObject::setFrequency failed: "
00222             "already registered to scheduler." ) ;
00223             
00224 
00225     
00226     Scheduler & scheduler = Scheduler::GetExistingScheduler() ;
00227     
00228     
00229 
00230 
00231 
00232 
00233 
00234 
00235 
00236 
00237 
00238 
00239     
00240     _period = static_cast<Period>( Ceylan::Maths::Round( 1000000.0f / 
00241         ( newFrequency * scheduler.getSimulationTickCount() 
00242             * scheduler.getTimeSliceDuration() ) ) ) ;
00243      
00244      
00245 
00246 
00247 
00248      Hertz actualFrequency = static_cast<Hertz>( 
00249         Ceylan::Maths::Round( 1000000.0f / 
00250             ( _period * scheduler.getSimulationTickCount() 
00251                 * scheduler.getTimeSliceDuration() ) ) ) ;
00252      
00253      
00254      if ( _period < 1 )
00255      {
00256      
00257         LogPlug::warning( "PeriodicalActiveObject::setFrequency: frequency "
00258             + Ceylan::toString( newFrequency ) + "Hz had to be clampled to "
00259             + Ceylan::toString( actualFrequency ) + " Hz." ) ;
00260             
00261         _period = 1 ;
00262      
00263      }
00264      
00265      return actualFrequency ;
00266         
00267 }
00268 
00269 
00270 
00271 Period PeriodicalActiveObject::getSubslotNumber() const 
00272 {
00273 
00274     if ( _subslot >= _period )
00275         throw SchedulingException( "PeriodicalActiveObject::getSubslotNumber: "
00276             "invalid sub-slot, object probably not registered yet." ) ;
00277             
00278     return _subslot ;
00279 
00280 }
00281 
00282 
00283 
00284 void PeriodicalActiveObject::onRegistering( Events::Period subslot ) 
00285 {
00286 
00287     if ( _registered ) 
00288         throw SchedulingException( 
00289             "PeriodicalActiveObject::onRegistering failed: "
00290             "already registered to scheduler." ) ;
00291 
00292     _subslot = subslot ;
00293     
00294     
00295     _registered = true ;
00296     
00297 }
00298 
00299 
00300 
00301 void PeriodicalActiveObject::setBirthTick( 
00302     Events::SimulationTick currentSimulationTick )
00303 {
00304 
00305     
00306 
00307 
00308 
00309 
00310      
00311     
00312 
00313 
00314 
00315 
00316     Events::SimulationTick lastPeriodBegin = 
00317         _period * ( currentSimulationTick / _period ) ;
00318     
00319     
00320     if ( currentSimulationTick % _period < _subslot )
00321     {
00322     
00323         
00324         _birthTick = lastPeriodBegin + _subslot ;
00325     
00326     }
00327     else
00328     {
00329     
00330         
00331         _birthTick = lastPeriodBegin + _period + _subslot ;
00332     
00333     }
00334             
00335 }
00336 
00337 
00338 
00339 OSDL::Events::SimulationTick
00340         PeriodicalActiveObject::convertDurationToActivationCount(
00341     Ceylan::System::Millisecond duration ) const    
00342 {
00343 
00344     Scheduler & scheduler = Scheduler::GetExistingScheduler() ;
00345 
00346     
00347     return static_cast<Events::SimulationTick>( Ceylan::Maths::Round(
00348         static_cast<Ceylan::Float32>( (1000.0f * duration) / 
00349             ( _period * scheduler.getSimulationTickCount() 
00350                 * scheduler.getTimeSliceDuration() ) ) ) ) ;
00351             
00352 }
00353 
00354 
00355             
00356 const string PeriodicalActiveObject::toString( Ceylan::VerbosityLevels level )
00357     const
00358 {   
00359 
00360     string slot ;
00361     
00362     
00363     if ( _subslot == 0 )
00364         slot = ", with no subslot set" ;
00365     else
00366         slot = ", using subslot #" + Ceylan::toString( _subslot ) ;
00367             
00368             
00369     return "Periodical active object, whose period is " 
00370         + Ceylan::toString( _period ) + slot + ". It is an " 
00371         + ActiveObject::toString( level ) ;
00372         
00373 }
00374