![]() |
User Manual, Developers Guide and API Documentation |
![]() |
00001 /****************************************************************************** 00002 * WiFiMac * 00003 * This file is part of openWNS (open Wireless Network Simulator) 00004 * _____________________________________________________________________________ 00005 * 00006 * Copyright (C) 2004-2007 00007 * Chair of Communication Networks (ComNets) 00008 * Kopernikusstr. 16, D-52074 Aachen, Germany 00009 * phone: ++49-241-80-27910, 00010 * fax: ++49-241-80-22242 00011 * email: info@openwns.org 00012 * www: http://www.openwns.org 00013 * _____________________________________________________________________________ 00014 * 00015 * openWNS is free software; you can redistribute it and/or modify it under the 00016 * terms of the GNU Lesser General Public License version 2 as published by the 00017 * Free Software Foundation; 00018 * 00019 * openWNS is distributed in the hope that it will be useful, but WITHOUT ANY 00020 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 00021 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 00022 * details. 00023 * 00024 * You should have received a copy of the GNU Lesser General Public License 00025 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00026 * 00027 ******************************************************************************/ 00028 00029 #include <WIFIMAC/convergence/PhyUser.hpp> 00030 #include <WIFIMAC/convergence/TxDurationSetter.hpp> 00031 #include <WIFIMAC/helper/CholeskyDecomposition.hpp> 00032 00033 #include <DLL/StationManager.hpp> 00034 00035 #include <WNS/ldk/fun/FUN.hpp> 00036 #include <WNS/pyconfig/View.hpp> 00037 #include <WNS/logger/Logger.hpp> 00038 #include <WNS/module/Base.hpp> 00039 #include <WNS/ldk/concatenation/Concatenation.hpp> 00040 00041 #include <boost/numeric/ublas/matrix.hpp> 00042 #include <boost/bind.hpp> 00043 00044 using namespace wifimac::convergence; 00045 00046 STATIC_FACTORY_REGISTER_WITH_CREATOR( 00047 wifimac::convergence::PhyUser, 00048 wns::ldk::FunctionalUnit, 00049 "wifimac.convergence.PhyUser", 00050 wns::ldk::FUNConfigCreator); 00051 00052 PhyUser::PhyUser(wns::ldk::fun::FUN* fun, const wns::pyconfig::View& _config) : 00053 wns::ldk::fu::Plain<PhyUser, PhyUserCommand>(fun), 00054 config(_config), 00055 logger(config.get<wns::pyconfig::View>("logger")), 00056 tune(), 00057 dataTransmission(NULL), 00058 notificationService(NULL), 00059 phyModes(config.getView("myConfig.phyModesDeliverer")), 00060 managerName(config.get<std::string>("managerName")), 00061 txDurationProviderCommandName(config.get<std::string>("txDurationProviderCommandName")), 00062 txrxTurnaroundDelay(config.get<wns::simulator::Time>("myConfig.txrxTurnaroundDelay")), 00063 bfEnabled(config.get<bool>("myConfig.bfEnabled")), 00064 phyUserStatus(receiving), 00065 currentTxCompound(), 00066 lastTxRxTurnaround(0.0) 00067 { 00068 tune.frequency = config.get<double>("myConfig.initFrequency"); 00069 tune.bandwidth = config.get<double>("myConfig.initBandwidthMHz"); 00070 tune.numberOfSubCarrier = 1; 00071 } 00072 // PhyUser 00073 00074 00075 PhyUser::~PhyUser() 00076 { 00077 } 00078 00079 void PhyUser::onFUNCreated() 00080 { 00081 friends.manager = getFUN()->findFriend<wifimac::lowerMAC::Manager*>(managerName); 00082 } // onFUNCreated 00083 00084 bool PhyUser::doIsAccepting(const wns::ldk::CompoundPtr& /* compound */) const 00085 { 00086 // we only accept if we are not currently transmitting 00087 return (phyUserStatus != transmitting); 00088 } // isAccepting 00089 00090 void PhyUser::doSendData(const wns::ldk::CompoundPtr& compound) 00091 { 00092 assure(compound, "sendData called with an invalid compound."); 00093 assure(phyUserStatus != transmitting, "Cannot send data during transmission"); 00094 00095 if(friends.manager->getFrameType(compound->getCommandPool()) != PREAMBLE) 00096 { 00097 // signal tx start to the MAC 00098 this->wns::Subject<ITxStartEnd>::forEachObserver(OnTxStartEnd(compound, start)); 00099 } 00100 00101 wns::simulator::Time frameTxDuration = getFUN()->getCommandReader(txDurationProviderCommandName)-> 00102 readCommand<wifimac::convergence::TxDurationProviderCommand>(compound->getCommandPool())->getDuration(); 00103 00104 PhyUserCommand* command = activateCommand(compound->getCommandPool()); 00105 00106 wns::Power defaultTxPower = getDataTransmissionService()->getMaxPowerPerSubband(); 00107 00108 // to schedule the startBroadcast function, we have to indicate to 00109 // boost::bind the correct function, as startBroadcast has two different 00110 // signatures (with number of streams and phyMode). Therefore, we first 00111 // create a variable of the desired function signature type and assign using 00112 // desired member function. This will resolve the correct function thanks 00113 // to the signature including the argument types. 00114 if(bfEnabled and friends.manager->getReceiverAddress(compound->getCommandPool()).isValid()) 00115 { 00116 void (wns::service::phy::ofdma::NonBFTransmission::*fn)(wns::osi::PDUPtr, wns::node::Interface*, int, wns::Power, int) = 00117 &wns::service::phy::ofdma::NonBFTransmission::startUnicast; 00118 00119 wns::service::dll::UnicastAddress destination = friends.manager->getReceiverAddress(compound->getCommandPool()); 00120 wns::node::Interface* n = this->getFUN()->getLayer<dll::ILayer2*>()->getStationManager()->getStationByMAC(destination)->getNode(); 00121 00122 // Now boost::bind can be used to schedue the start of the transmission 00123 wns::simulator::getEventScheduler()->scheduleDelay( 00124 boost::bind(fn, 00125 this->getDataTransmissionService(), 00126 compound, 00127 n, 00128 0, 00129 defaultTxPower, 00130 friends.manager->getPhyMode(compound->getCommandPool()).getNumberOfSpatialStreams()), 00131 0.0); 00132 } 00133 else 00134 { 00135 void (wns::service::phy::ofdma::NonBFTransmission::*fn)(wns::osi::PDUPtr, int, wns::Power, int) = 00136 &wns::service::phy::ofdma::NonBFTransmission::startBroadcast; 00137 00138 // Now boost::bind can be used to schedue the start of the transmission 00139 wns::simulator::getEventScheduler()->scheduleDelay( 00140 boost::bind(fn, 00141 this->getDataTransmissionService(), 00142 compound, 00143 0, 00144 defaultTxPower, 00145 friends.manager->getPhyMode(compound->getCommandPool()).getNumberOfSpatialStreams()), 00146 0.0); 00147 } 00148 // schedule end of transmission similarly 00149 wns::simulator::getEventScheduler()->scheduleDelay( 00150 boost::bind(&wns::service::phy::ofdma::DataTransmission::stopTransmission, 00151 this->getDataTransmissionService(), 00152 compound, 00153 0), 00154 frameTxDuration); 00155 00156 MESSAGE_SINGLE(NORMAL, logger, "Transmission, rx disabled for " << frameTxDuration); 00157 if(phyUserStatus == txrxTurnaround) 00158 { 00159 setNewTimeout(frameTxDuration); 00160 } 00161 else 00162 { 00163 setTimeout(frameTxDuration); 00164 } 00165 // we are transmitting! 00166 phyUserStatus = transmitting; 00167 00168 this->currentTxCompound = compound; 00169 00170 } // doSendData 00171 00172 void PhyUser::doOnData(const wns::ldk::CompoundPtr& compound) 00173 { 00174 assure(compound, "onData called with an invalid compound."); 00175 00176 getDeliverer()->getAcceptor(compound)->onData(compound); 00177 } // doOnData 00178 00179 void PhyUser::doWakeup() 00180 { 00181 assure(false, "PhyUser doWakeup will never be called -- nobody is below"); 00182 } // doWakeup 00183 00184 void PhyUser::onData(wns::osi::PDUPtr pdu, wns::service::phy::power::PowerMeasurementPtr rxPowerMeasurement) 00185 { 00186 assure(wns::dynamicCast<wns::ldk::Compound>(pdu), "not a CompoundPtr"); 00187 00188 if(phyUserStatus != receiving) 00189 { 00190 // During transmission, the receiver is off 00191 return; 00192 } 00193 // FIRST: create a copy instead of working on the real compound 00194 wns::ldk::CompoundPtr compound = wns::staticCast<wns::ldk::Compound>(pdu)->copy(); 00195 00196 if(not getFUN()->getProxy()->commandIsActivated(compound->getCommandPool(), this)) 00197 { 00198 // if the phyUserCommand is not activated, the compound was not send 00199 // from a WIFIMAC node! 00200 return; 00201 } 00202 00203 wns::simulator::Time frameRxDuration = getFUN()->getCommandReader(txDurationProviderCommandName)-> 00204 readCommand<wifimac::convergence::TxDurationProviderCommand>(compound->getCommandPool())->getDuration(); 00205 00206 if(lastTxRxTurnaround > (wns::simulator::getEventScheduler()->getTime() - frameRxDuration)) 00207 { 00208 // The received frame started BEFORE the last txrxTurnaround -> not readable! 00209 return; 00210 } 00211 00212 // check if we have enough antennas to receive all streams 00213 unsigned int nss = friends.manager->getPhyMode(compound->getCommandPool()).getNumberOfSpatialStreams(); 00214 if(nss > friends.manager->getNumAntennas()) 00215 { 00216 MESSAGE_BEGIN(NORMAL, logger, m, "Transmission "); 00217 m << "from " << friends.manager->getTransmitterAddress(compound->getCommandPool()); 00218 m << " has " << nss; 00219 m << " spatial streams, but receiver has only " << friends.manager->getNumAntennas() << " antennas -> drop"; 00220 MESSAGE_END(); 00221 return; 00222 } 00223 else 00224 { 00225 MESSAGE_BEGIN(NORMAL, logger, m, "Transmission "); 00226 m << "from " << friends.manager->getTransmitterAddress(compound->getCommandPool()); 00227 m << " has " << nss; 00228 m << " spatial streams, receiver has " << friends.manager->getNumAntennas() << " antennas"; 00229 MESSAGE_END(); 00230 } 00231 00232 PhyUserCommand* phyCommand = getCommand(compound->getCommandPool()); 00233 00234 // store measured signal into Command 00235 phyCommand->local.rxPower = rxPowerMeasurement->getRxPower(); 00236 phyCommand->local.interference = rxPowerMeasurement->getInterferencePower(); 00237 phyCommand->local.postSINRFactor = rxPowerMeasurement->getPostProcessingSINRFactor(); 00238 00239 this->wns::ldk::FunctionalUnit::onData(compound); 00240 } // onData 00241 00242 wns::Ratio PhyUser::getExpectedPostSINRFactor(unsigned int nss, unsigned int numRx) 00243 { 00244 assure(numRx >= nss, "Nss must be smaller or equal to numRx"); 00245 00246 double cF = 1.0; 00247 00248 double mimoCorrelation = 1.0; 00249 if(mimoCorrelation > 0.0) 00250 { 00251 // there is a correlation among the MIMO channels, thus we have a 00252 // correlation factor < 1.0 00253 00254 // generate covariance matrix 00255 boost::numeric::ublas::matrix<double> m(nss, nss); 00256 for(unsigned int i = 0; i < nss; ++i) 00257 { 00258 for(unsigned int j = 0; j < nss; ++j) 00259 { 00260 if(i == j) 00261 { 00262 m(i,j) = 1; 00263 } 00264 else 00265 { 00266 m(i,j) = mimoCorrelation; 00267 } 00268 } 00269 } 00270 00271 // compute correlation matrix & correlation factor 00272 choleskyDecompose< boost::numeric::ublas::matrix<double> >(m); 00273 cF = m(nss-1, nss-1)*m(nss-1, nss-1); 00274 } 00275 00276 return( wns::Ratio::from_factor(cF * (static_cast<double>(numRx - nss + 1)) / (static_cast<double>(nss)))); 00277 } 00278 00279 void PhyUser::onTimeout() 00280 { 00281 assure(phyUserStatus != receiving, "Timeout although not transmitting"); 00282 if(phyUserStatus == transmitting) 00283 { 00284 // finished transmission, start turnaround 00285 MESSAGE_SINGLE(NORMAL, logger, "Timout, finished transmission"); 00286 phyUserStatus = txrxTurnaround; 00287 setTimeout(txrxTurnaroundDelay); 00288 00289 assure(this->currentTxCompound, "currentTxCompound is NULL"); 00290 if(friends.manager->getFrameType(this->currentTxCompound->getCommandPool()) != PREAMBLE) 00291 { 00292 // signal tx end to MAC 00293 MESSAGE_SINGLE(NORMAL, logger, "No preamble -> signal tx end"); 00294 this->wns::Subject<ITxStartEnd>::forEachObserver(OnTxStartEnd(this->currentTxCompound, end)); 00295 } 00296 00297 this->currentTxCompound = wns::ldk::CompoundPtr(); 00298 00299 // wakeup: we are ready to transmit another compound 00300 this->getReceptor()->wakeup(); 00301 return; 00302 } 00303 00304 if(phyUserStatus == txrxTurnaround) 00305 { 00306 // finished turnaround, ready to receive 00307 phyUserStatus = receiving; 00308 lastTxRxTurnaround = wns::simulator::getEventScheduler()->getTime(); 00309 return; 00310 } 00311 00312 assure(false, "Unknown phyUserStatus"); 00313 } 00314 00315 void PhyUser::setDataTransmissionService(wns::service::Service* phy) 00316 { 00317 assure(phy, "must be non-NULL"); 00318 assureType(phy, wns::service::phy::ofdma::DataTransmission*); 00319 dataTransmission = dynamic_cast<wns::service::phy::ofdma::DataTransmission*>(phy); 00320 dataTransmission->setRxTune(tune); 00321 dataTransmission->setTxTune(tune); 00322 } // setDataTransmissionService 00323 00324 wns::service::phy::ofdma::DataTransmission* PhyUser::getDataTransmissionService() const 00325 { 00326 assure(dataTransmission, "no ofdma::DataTransmission set. Did you call setDataTransmission()?"); 00327 return dataTransmission; 00328 } // getDataTransmissionService 00329 00330 void PhyUser::setNotificationService(wns::service::Service* phy) 00331 { 00332 assure(phy, "must be non-NULL"); 00333 assureType(phy, wns::service::phy::ofdma::Notification*); 00334 notificationService = dynamic_cast<wns::service::phy::ofdma::Notification*>(phy); 00335 00336 // attach handler (there can be only one) 00337 notificationService->registerHandler(this); 00338 00339 } // setNotificationService 00340 00341 wns::service::phy::ofdma::Notification* PhyUser::getNotificationService() const 00342 { 00343 assure(notificationService, "no ofdma::Notification set. Did you call setNotificationService()?"); 00344 return notificationService; 00345 } // getNotificationService 00346 00347 void PhyUser::setFrequency(double frequency) 00348 { 00349 if(dataTransmission == NULL) 00350 { 00351 MESSAGE_SINGLE(NORMAL, logger, "cannot yet set RxFrequency, save for after inialisation"); 00352 tune.frequency = frequency; 00353 } 00354 else 00355 { 00356 MESSAGE_SINGLE(NORMAL, logger, "setRxFrequency to f: " << frequency << " MHz"); 00357 tune.frequency = frequency; 00358 dataTransmission->setRxTune(tune); 00359 dataTransmission->setTxTune(tune); 00360 } 00361 } 00362 00363 PhyModeProvider* PhyUser::getPhyModeProvider() 00364 { 00365 return &phyModes; 00366 } 00367 00368
1.5.5