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