From e203a67706ace405047b9a6ef2ac79216fe84ff9 Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 28 Sep 2023 10:17:08 +0100 Subject: [PATCH] Added latest from private --- src/apps/mode4App/Mode4App.cc | 18 +- src/apps/mode4App/Mode4App.h | 4 +- src/apps/mode4App/mode4App.ned | 10 +- src/common/LteCommon.h | 2 + src/common/LteControlInfo.msg | 2 + src/stack/mac/LteMac.ned | 43 +- src/stack/mac/buffer/harq/LteHarqBufferTx.cc | 7 + src/stack/mac/buffer/harq/LteHarqBufferTx.h | 2 + src/stack/mac/layer/LteMacBase.cc | 6 +- src/stack/mac/layer/LteMacVUeMode4.cc | 812 +++++++++++---- src/stack/mac/layer/LteMacVUeMode4.h | 41 +- src/stack/mac/packet/LteSchedulingGrant.h | 55 + src/stack/mac/packet/LteSchedulingGrant.msg | 5 +- src/stack/mac/scheduler/LteSchedulerUeUl.cc | 76 +- src/stack/mac/scheduler/LteSchedulerUeUl.h | 3 + src/stack/phy/LtePhy.ned | 157 +-- src/stack/phy/layer/LtePhyVUeMode4.cc | 961 ++++++++++++++++-- src/stack/phy/layer/LtePhyVUeMode4.h | 40 + .../phy/packet/SpsCandidateResources.msg | 1 + src/stack/phy/packet/cbr.msg | 1 + src/world/radio/ChannelAccess.cc | 18 +- 21 files changed, 1881 insertions(+), 383 deletions(-) diff --git a/src/apps/mode4App/Mode4App.cc b/src/apps/mode4App/Mode4App.cc index 2df77a64..0ef8e14c 100644 --- a/src/apps/mode4App/Mode4App.cc +++ b/src/apps/mode4App/Mode4App.cc @@ -53,14 +53,22 @@ void Mode4App::initialize(int stage) period_ = par("period"); priority_ = par("priority"); duration_ = par("duration"); + delay50ms_ = par("delay50ms"); + delay100ms_ = par("delay100ms"); - sentMsg_ = registerSignal("sentMsg"); + camGen_ = registerSignal("camGen"); delay_ = registerSignal("delay"); rcvdMsg_ = registerSignal("rcvdMsg"); cbr_ = registerSignal("cbr"); - double delay = 0.001 * intuniform(0, 1000, 0); - scheduleAt((simTime() + delay).trunc(SIMTIME_MS), selfSender_); + SimTime jitter = uniform(SimTime(0, SIMTIME_MS), SimTime(1000, SIMTIME_MS)); + if (delay50ms_){ + jitter = uniform(SimTime(0, SIMTIME_MS), SimTime(50, SIMTIME_MS)); + } + else if (delay100ms_){ + jitter = uniform(SimTime(0, SIMTIME_MS), SimTime(100, SIMTIME_MS)); + } + scheduleAt(simTime() + SimTime(100, SIMTIME_MS) + jitter, selfSender_); } } @@ -110,7 +118,7 @@ void Mode4App::handleSelfMessage(cMessage* msg) packet->setControlInfo(lteControlInfo); Mode4BaseApp::sendLowerPackets(packet); - emit(sentMsg_, (long)1); + emit(camGen_, (int)1); scheduleAt(simTime() + period_, selfSender_); } @@ -125,5 +133,5 @@ void Mode4App::finish() Mode4App::~Mode4App() { - binder_->unregisterNode(nodeId_); +// binder_->unregisterNode(nodeId_); } diff --git a/src/apps/mode4App/Mode4App.h b/src/apps/mode4App/Mode4App.h index b6c2897b..7329ffaa 100644 --- a/src/apps/mode4App/Mode4App.h +++ b/src/apps/mode4App/Mode4App.h @@ -38,9 +38,11 @@ class Mode4App : public Mode4BaseApp { int nextSno_; int priority_; int duration_; + bool delay50ms_; + bool delay100ms_; simtime_t period_; - simsignal_t sentMsg_; + simsignal_t camGen_; simsignal_t delay_; simsignal_t rcvdMsg_; simsignal_t cbr_; diff --git a/src/apps/mode4App/mode4App.ned b/src/apps/mode4App/mode4App.ned index 2167111d..6ef9ee7b 100644 --- a/src/apps/mode4App/mode4App.ned +++ b/src/apps/mode4App/mode4App.ned @@ -20,14 +20,16 @@ import lte.apps.mode4App.Mode4BaseApp; simple Mode4App like Mode4BaseApp { parameters: - int packetSize = default(10); // Size of the actual packet itself - int priority = default(3); // Priority of the packets sent + int packetSize = default(190); // Size of the actual packet itself + int priority = default(0); // Priority of the packets sent int duration = default(1000); // MS before packet must be dropped double period @unit("s") = default(0.1s); int macNodeId = default(0); + bool delay50ms = default(false); + bool delay100ms = default(true); - @signal[sentMsg]; - @statistic[sentMsg](title="Messages sent"; unit=""; source="sentMsg"; record=sum,vector); + @signal[camGen]; + @statistic[camGen](title="Messages sent"; unit=""; source="camGen"; record=sum,vector); @signal[delay]; @statistic[delay](title="Message Delay"; unit="s"; source="delay"; record=mean,vector); @signal[rcvdMsg]; diff --git a/src/common/LteCommon.h b/src/common/LteCommon.h index 78581539..30d3722f 100644 --- a/src/common/LteCommon.h +++ b/src/common/LteCommon.h @@ -465,6 +465,7 @@ enum LtePhyFrameType RACPKT, D2DMODESWITCHPKT, SCIPKT, + RESPKT, UNKNOWN_TYPE }; @@ -482,6 +483,7 @@ const LtePhyFrameTable phytypes[] = { ELEM(GRANTPKT), ELEM(D2DMODESWITCHPKT), ELEM(SCIPKT), + ELEM(RESPKT), ELEM(UNKNOWN_TYPE) }; diff --git a/src/common/LteControlInfo.msg b/src/common/LteControlInfo.msg index 8ff17da4..37261157 100644 --- a/src/common/LteControlInfo.msg +++ b/src/common/LteControlInfo.msg @@ -100,6 +100,8 @@ class FlowControlInfoNonIp extends LteControlInfo { long duration; long srcAddr; long dstAddr; + int RRI; + int messageCategory; simtime_t creationTime; } // diff --git a/src/stack/mac/LteMac.ned b/src/stack/mac/LteMac.ned index d26e5422..e138b0a9 100644 --- a/src/stack/mac/LteMac.ned +++ b/src/stack/mac/LteMac.ned @@ -36,6 +36,8 @@ simple LteMacIPBase like LteMac { bool ipBased = default(true); + double delayStartUp @unit(s) = default(0s); + //# Mac Queues int queueSize @unit(B) = default(2MiB); // MAC Buffers queue size @@ -138,7 +140,7 @@ simple LteMacIPBase like LteMac { gates: //# //# Gates connecting RLC and MAC Layers - //# + //# input RLC_to_MAC; // RLC to MAC output MAC_to_RLC; // MAC to RLC @@ -159,6 +161,8 @@ simple LteMacNonIPBase like LteMac { @display("i=block/mac"); bool ipBased = default(false); + + double delayStartUp @unit(s) = default(0s); string interfaceTableModule = default(""); @@ -383,19 +387,37 @@ simple LteMacVUeMode4 extends LteMacNonIPBase double probResourceKeep = default(0.4); bool useCBR = default(false); bool packetDropping = default(false); + bool rriLookup = default(false); + bool crLimit = default(false); + bool limeric = default(false); + bool usage = default(false); + bool adaptiveRRI = default(false); + + double cbrTarget = default(0.68); + double alpha = default(0.016); + double beta = default(0.0012); + double gPlusMax = default(0.0005); + double gMinusMax = default(-0.00025); + double deltaMax = default(0.03); + double deltaMin = default(0.0006); + bool dccMechanism = default(false); + bool adjacencyPSCCHPSSCH = default(true); bool randomScheduling = default(false); + bool nonPeriodic = default(false); + bool alwaysReschedule = default(false); + bool noTransmissions = default(false); bool usePreconfiguredTxParams = default(false); - - // Signals + + // Signals // // Must haves: // Grant break due to no time // Grant break due to no large enough MCS // Selected MCS // Selected number of subchannels - // Packet size on break + // Packet size on break // Maximum capacity on grant break @signal[grantStartTime]; @@ -426,20 +448,23 @@ simple LteMacVUeMode4 extends LteMacNonIPBase @statistic[grantRequests](title="Total number of requested grants"; source="grantRequests"; record=sum,vector); @signal[packetDropDCC]; @statistic[packetDropDCC](title="Packet drop due to DCC mechanism"; source="packetDropDCC"; record=sum,vector); + @signal[rriChange]; + @statistic[rriChange](title="RRI Change due to mechanism"; source="rriChange"; record=sum,vector); @signal[resourceReselectionCounter]; @statistic[resourceReselectionCounter](title="ResourceReselectionCounter selectedNumber of transmissions"; source="resourceReselectionCounter"; record=sum,vector); @signal[retainGrant]; @statistic[retainGrant](title="retainGrant if grant is maintained properly"; source="retainGrant"; record=sum,vector); + @signal[channelOccupancyRatio]; + @statistic[channelOccupancyRatio](title="Channel Occupancy Ratio"; source="channelOccupancyRatio"; record=mean,vector); + @signal[limericDelta]; + @statistic[limericDelta](title="Occupancy limit dictated by limeric"; source="limericDelta"; record=mean,vector); + @signal[crLimit]; + @statistic[crLimit](title="CR limit for node"; source="crLimit"; record=mean,vector); @signal[macNodeID]; @statistic[macNodeID](title="Reports Mac NodeID to allow for trans to nodeID"; source="macNodeID"; record=vector); } -simple LteMacVUeMode4NonSPS extends LteMacVUeMode4 -{ - @class("LteMacVUeMode4NonSPS"); -} - // // eNodeB MAC layer of LTE stack // diff --git a/src/stack/mac/buffer/harq/LteHarqBufferTx.cc b/src/stack/mac/buffer/harq/LteHarqBufferTx.cc index 357c5aa7..54e05a5b 100644 --- a/src/stack/mac/buffer/harq/LteHarqBufferTx.cc +++ b/src/stack/mac/buffer/harq/LteHarqBufferTx.cc @@ -280,6 +280,13 @@ void LteHarqBufferTx::forceDropProcess(unsigned char acid) numEmptyProc_++; } +void LteHarqBufferTx::forceDropSelectedProcess() +{ + (*processes_)[selectedAcid_]->forceDropProcess(); + selectedAcid_ = HARQ_NONE; + numEmptyProc_++; +} + void LteHarqBufferTx::forceDropUnit(unsigned char acid, Codeword cw) { bool reset = (*processes_)[acid]->forceDropUnit(cw); diff --git a/src/stack/mac/buffer/harq/LteHarqBufferTx.h b/src/stack/mac/buffer/harq/LteHarqBufferTx.h index 6906b1d3..3bbdc1c6 100644 --- a/src/stack/mac/buffer/harq/LteHarqBufferTx.h +++ b/src/stack/mac/buffer/harq/LteHarqBufferTx.h @@ -141,6 +141,8 @@ class LteHarqBufferTx */ void dropProcess(unsigned char acid); + void forceDropSelectedProcess(); + /** * Sends simulated HARQNACK to all units of the process which contains * the one whose id is specified as parameter. diff --git a/src/stack/mac/layer/LteMacBase.cc b/src/stack/mac/layer/LteMacBase.cc index e6a20153..a30caa1d 100644 --- a/src/stack/mac/layer/LteMacBase.cc +++ b/src/stack/mac/layer/LteMacBase.cc @@ -309,6 +309,10 @@ void LteMacBase::initialize(int stage) /* Create buffers */ queueSize_ = par("queueSize"); maxBytesPerTti_ = par("maxBytesPerTti"); + simtime_t startUpDelay = par("delayStartUp"); + if (startUpDelay == 0 || startUpDelay < NOW){ + startUpDelay = NOW; + } /* Get reference to binder */ binder_ = getBinder(); @@ -322,7 +326,7 @@ void LteMacBase::initialize(int stage) /* Start TTI tick */ ttiTick_ = new cMessage("ttiTick_"); ttiTick_->setSchedulingPriority(1); // TTI TICK after other messages - scheduleAt(NOW + TTI, ttiTick_); + scheduleAt(startUpDelay + TTI, ttiTick_); totalOverflowedBytes_ = 0; macBufferOverflowDl_ = registerSignal("macBufferOverflowDl"); macBufferOverflowUl_ = registerSignal("macBufferOverflowUl"); diff --git a/src/stack/mac/layer/LteMacVUeMode4.cc b/src/stack/mac/layer/LteMacVUeMode4.cc index 703fd645..c673f168 100644 --- a/src/stack/mac/layer/LteMacVUeMode4.cc +++ b/src/stack/mac/layer/LteMacVUeMode4.cc @@ -21,19 +21,15 @@ #include "stack/mac/buffer/harq/LteHarqBufferRx.h" #include "stack/mac/buffer/LteMacQueue.h" -#include "stack/mac/buffer/harq_d2d/LteHarqBufferRxD2DMirror.h" #include "stack/mac/layer/LteMacVUeMode4.h" #include "stack/mac/scheduler/LteSchedulerUeUl.h" #include "stack/phy/packet/SpsCandidateResources.h" #include "stack/phy/packet/cbr_m.h" -#include "stack/phy/layer/Subchannel.h" -#include "stack/mac/amc/AmcPilotD2D.h" #include "common/LteCommon.h" #include "stack/phy/layer/LtePhyBase.h" #include "inet/networklayer/common/InterfaceEntry.h" -#include "inet/common/ModuleAccess.h" -#include "inet/networklayer/ipv4/IPv4InterfaceData.h" #include "stack/mac/amc/LteMcs.h" +#include "stack/mac/packet/LteMacSduRequest.h" #include Define_Module(LteMacVUeMode4); @@ -65,10 +61,30 @@ void LteMacVUeMode4::initialize(int stage) reselectAfter_ = par("reselectAfter"); useCBR_ = par("useCBR"); packetDropping_ = par("packetDropping"); + rriLookup_ = par("rriLookup"); + crLimit_ = par("crLimit"); + limeric_ = par("limeric"); + alpha_ = par("alpha"); + beta_ = par("beta"); + g_plus_max_ = par("gPlusMax"); + g_minus_max_ = par("gMinusMax"); + delta_max_ = par("deltaMax"); + delta_min_ = par("deltaMin"); + usage_ = par("usage"); + cbrTarget_ = par("cbrTarget"); + dccMechanism_ = par("dccMechanism"); adjacencyPSCCHPSSCH_ = par("adjacencyPSCCHPSSCH"); randomScheduling_ = par("randomScheduling"); + nonPeriodic_ = par("nonPeriodic"); + alwaysReschedule_ = par("alwaysReschedule"); + noTransmissions_ = par("noTransmissions"); + adaptiveRRI_ = par("adaptiveRRI"); maximumCapacity_ = 0; - cbr_=0; + delta_ = delta_max_; // Start delta at max transmission rate (don't want to apply CC unless we have to). + cbr_ = 0.0; + averageCBR_ = 0.0; + channelOccupancyRatio_ = 0.0; + averageCBRIndex_ = 0; currentCw_=0; missedTransmissions_=0; @@ -95,6 +111,14 @@ void LteMacVUeMode4::initialize(int stage) macNodeID = registerSignal("macNodeID"); rrcSelected = registerSignal("resourceReselectionCounter"); retainGrant = registerSignal("retainGrant"); + rriChange = registerSignal("rriChange"); + channelOccupancyRatio = registerSignal("channelOccupancyRatio"); + limericDelta = registerSignal("limericDelta"); + crLimit = registerSignal("crLimit"); + + if (limeric_) { + updateLimeric(); + } } else if (stage == inet::INITSTAGE_NETWORK_LAYER_3) { @@ -380,7 +404,13 @@ void LteMacVUeMode4::macPduMake() uinfo->setLcid(MacCidToLcid(SHORT_BSR)); // First translate MCS to CQI - LteMode4SchedulingGrant* mode4Grant = check_and_cast(schedulingGrant_); + LteMode4SchedulingGrant* mode4Grant = NULL; + map::iterator it; + for (it = grants_.begin(); it != grants_.end(); it++) { + mode4Grant = it->second; + if (mode4Grant->getTransmit()) + break; + } if (usePreconfiguredTxParams_) { @@ -516,6 +546,7 @@ UserTxParams* LteMacVUeMode4::getPreconfiguredTxParams() } double LteMacVUeMode4::calculateChannelOccupancyRatio(int period){ + // TODO: Rework this on the assumption that multiple grants are available int b; int a; int subchannelsUsed = 0; @@ -552,10 +583,34 @@ double LteMacVUeMode4::calculateChannelOccupancyRatio(int period){ return subchannelsUsed /(numSubchannels_ * 1000.0); } +double LteMacVUeMode4::calculateUsage(){ + int subchannelsUsed = 0; + + // determine previous transmissions -> Need to account for if we have already done a drop. Must maintain a + // history of past transmissions i.e. subchannels used and subframe in which they occur. delete entries older + // than 1000. + std::unordered_map::const_iterator it = previousTransmissions_.begin(); + while (it != previousTransmissions_.end()){ + if (it->first < NOW.dbl() - 1){ + it = previousTransmissions_.erase(it); + continue; + } else { + subchannelsUsed += it->second; + } + it++; + } + // calculate usage for last 1000ms + return subchannelsUsed /(numSubchannels_ * 1000.0); +} + void LteMacVUeMode4::handleMessage(cMessage *msg) { if (msg->isSelfMessage()) { + if (strcmp(msg->getName(), "updateLimeric") == 0){ + updateLimeric(); + return; + } LteMacUeRealisticD2D::handleMessage(msg); return; } @@ -584,29 +639,142 @@ void LteMacVUeMode4::handleMessage(cMessage *msg) cbr_ = cbrPkt->getCbr(); if (useCBR_) { - std::vector>::iterator it; - for (it = cbrLevels_.begin(); it!=cbrLevels_.end(); it++) - { - double cbrUpper = (*it).at("cbr-upper"); - double cbrLower = (*it).at("cbr-lower"); - double index = (*it).at("cbr-PSSCH-TxConfig-Index"); - if (cbrLower == 0){ - if (cbr_< cbrUpper) - { - currentCbrIndex_ = (int)index; - break; + + if (dccMechanism_) { + double cbrUpper = cbrLevels_[currentCbrIndex_].at("cbr-upper"); + double cbrLower = cbrLevels_[currentCbrIndex_].at("cbr-lower"); + + if (cbr_ > cbrUpper) { + + cbrDownwardTransitions_.clear(); + + int highest_reachable_state = -1; + for (int i = 0; i < cbrUpwardTransitions_.size(); i++) { + simtime_t time = std::get<0>(cbrUpwardTransitions_[i]); + int index = std::get<1>(cbrUpwardTransitions_[i]); + if ((NOW >= time + 1) && (currentCbrIndex_ != index)) { + if (i > highest_reachable_state) { + highest_reachable_state = i; + } + } } - } else if (cbrUpper == 1){ - if (cbr_ > cbrLower) - { - currentCbrIndex_ = (int)index; - break; + if (highest_reachable_state != -1) { + currentCbrIndex_ = std::get<1>(cbrUpwardTransitions_[highest_reachable_state]); + std::vector < std::tuple < simtime_t, int + >> (cbrUpwardTransitions_.begin() + highest_reachable_state + + 1, cbrUpwardTransitions_.end()).swap(cbrUpwardTransitions_); + } + + std::vector < std::unordered_map < std::string, double >> ::iterator + it; + for (it = cbrLevels_.begin(); it != cbrLevels_.end(); it++) { + double levelUpper = (*it).at("cbr-upper"); + double levelLower = (*it).at("cbr-lower"); + double index = (*it).at("cbr-PSSCH-TxConfig-Index"); + // Check if multiple levels up i.e. is it higher again thus need to record second transition + if (index != currentCbrIndex_ && cbr_ >= levelLower && cbr_ < levelUpper) { + bool new_record = true; + if (cbrUpwardTransitions_.size() != 0) { + for (int j = 0; j < cbrUpwardTransitions_.size(); j++) { + if (std::get<1>(cbrUpwardTransitions_[j]) == index) { + new_record = false; + break; + } + } + } + if (new_record) { + std::tuple transition = std::make_tuple(NOW, index); + cbrUpwardTransitions_.push_back(transition); + } + } + } + } else if (cbr_ <= cbrLower && cbr_ != 0) { + + cbrUpwardTransitions_.clear(); + + int lowest_reachable_state = -1; + for (int i = 0; i < cbrDownwardTransitions_.size(); i++) { + simtime_t time = std::get<0>(cbrDownwardTransitions_[i]); + int index = std::get<1>(cbrDownwardTransitions_[i]); + if ((NOW >= time + 5) && (currentCbrIndex_ != index)) { + if (i > lowest_reachable_state) { + lowest_reachable_state = i; + } + } + } + if (lowest_reachable_state != -1) { + currentCbrIndex_ = std::get<1>(cbrDownwardTransitions_[lowest_reachable_state]); + std::vector < std::tuple < simtime_t, int + >> (cbrDownwardTransitions_.begin() + lowest_reachable_state + + 1, cbrDownwardTransitions_.end()).swap(cbrDownwardTransitions_); + } + + std::vector < std::unordered_map < std::string, double >> ::reverse_iterator it; + for (it = cbrLevels_.rbegin(); it != cbrLevels_.rend(); it++) { + double levelUpper = (*it).at("cbr-upper"); + double levelLower = (*it).at("cbr-lower"); + double index = (*it).at("cbr-PSSCH-TxConfig-Index"); + // Check if multiple levels up i.e. is it higher again thus need to record second transition + if (index != currentCbrIndex_ && cbr_ >= levelLower && cbr_ < levelUpper) { + bool new_record = true; + if (cbrDownwardTransitions_.size() != 0) { + for (int j = 0; j < cbrDownwardTransitions_.size(); j++) { + if (std::get<1>(cbrDownwardTransitions_[j]) == index) { + new_record = false; + break; + } + } + } + if (new_record) { + std::tuple transition = std::make_tuple(NOW, index); + cbrDownwardTransitions_.push_back(transition); + } + } } } else { - if (cbr_ > cbrLower && cbr_<= cbrUpper) - { - currentCbrIndex_ = (int)index; - break; + // We are still in the current range so no transitioning. + cbrUpwardTransitions_.clear(); + cbrDownwardTransitions_.clear(); + } + } else if (limeric_) { + if (cbrRecordings_.size() == 2){ + cbrRecordings_[averageCBRIndex_] = cbr_; + averageCBRIndex_ = 1 - averageCBRIndex_; + averageCBR_ = 0.5 * ((cbrRecordings_[0] + cbrRecordings_[1]) / 2) + 0.5 * averageCBR_; + } else { + cbrRecordings_.push_back(cbr_); + if (cbrRecordings_.size() == 2){ + averageCBR_ = (cbrRecordings_[0] + cbrRecordings_[1]) / 2; + } + else { + averageCBR_ = cbrRecordings_[0]; + } + } + } else { + std::vector>::iterator it; + for (it = cbrLevels_.begin(); it!=cbrLevels_.end(); it++) + { + double cbrUpper = (*it).at("cbr-upper"); + double cbrLower = (*it).at("cbr-lower"); + double index = (*it).at("cbr-PSSCH-TxConfig-Index"); + if (cbrLower == 0){ + if (cbr_< cbrUpper) + { + currentCbrIndex_ = (int)index; + break; + } + } else if (cbrUpper == 1){ + if (cbr_ > cbrLower) + { + currentCbrIndex_ = (int)index; + break; + } + } else { + if (cbr_ > cbrLower && cbr_<= cbrUpper) + { + currentCbrIndex_ = (int)index; + break; + } } } } @@ -616,11 +784,17 @@ void LteMacVUeMode4::handleMessage(cMessage *msg) if (schedulingGrant_ != NULL){ period = schedulingGrant_->getPeriod(); } + + // TODO: This will need to change channelOccupancyRatio_ = calculateChannelOccupancyRatio(period); + emit(channelOccupancyRatio, channelOccupancyRatio_); + // message from PHY_to_MAC gate (from lower layer) emit(receivedPacketFromLowerLayer, pkt); + cbrPkt->setCr(channelOccupancyRatio_); + LteMacBase::sendUpperPackets(cbrPkt); return; @@ -631,30 +805,69 @@ void LteMacVUeMode4::handleMessage(cMessage *msg) if (strcmp(pkt->getName(), "newDataPkt")== 0) { FlowControlInfoNonIp* lteInfo = check_and_cast(pkt->removeControlInfo()); + int newRRI = lteInfo->getRRI(); + int appId = lteInfo->getMessageCategory(); + LteMode4SchedulingGrant* currGrant = NULL; + int currRRI = 1; + if (grants_.count(appId)){ + currGrant = grants_[appId]; + currRRI = currGrant->getPeriod(); + } + bool rriChange = false; + if (adaptiveRRI_ && newRRI != currRRI && newRRI > 0) { + grants_[appId] = currGrant; + emit(rriChange, newRRI); + currRRI = newRRI; + rriChange = true; + } + receivedTime_ = NOW; simtime_t elapsedTime = receivedTime_ - lteInfo->getCreationTime(); remainingTime_ = lteInfo->getDuration() - (elapsedTime.dbl() * 1000); - if (schedulingGrant_ == NULL) + if (currGrant == NULL) { - macGenerateSchedulingGrant(remainingTime_, lteInfo->getPriority(), pkt->getBitLength()); + macGenerateSchedulingGrant(remainingTime_, lteInfo->getPriority(), pkt->getBitLength(), appId, currRRI); + currGrant = grants_[appId]; } - else if ((schedulingGrant_ != NULL && periodCounter_ > remainingTime_)) + else if ((currGrant != NULL && periodCounter_ > remainingTime_) || alwaysReschedule_) { emit(grantBreakTiming, 1); - delete schedulingGrant_; - schedulingGrant_ = NULL; - macGenerateSchedulingGrant(remainingTime_, lteInfo->getPriority(), pkt->getBitLength()); + delete currGrant; + grants_.erase(appId); + macGenerateSchedulingGrant(remainingTime_, lteInfo->getPriority(), pkt->getBitLength(), appId, currRRI); + currGrant = grants_[appId]; } else { - LteMode4SchedulingGrant* mode4Grant = check_and_cast(schedulingGrant_); - mode4Grant->setSpsPriority(lteInfo->getPriority()); + if (rriChange) { + currGrant->setNextPeriod(currRRI * 100); + // Might be an argument for resetting the grant everytime but for the moment this will do. + if (expirationCounter_ <= currGrant->getNextPeriod()) { + // Gotten to the point of the final tranmission must determine if we reselect or not. + double randomReReserve = dblrand(1); + if (randomReReserve < probResourceKeep_) { + int expiration = 0; + if (newRRI == 0.5) { + expiration = intuniform(10, 30, 3); + } else if (newRRI == 0.2) { + expiration = intuniform(25, 75, 3); + } else { + expiration = intuniform(5, 15, 3); + } + currGrant->setResourceReselectionCounter(expiration); + expirationCounter_ = expiration * currGrant->getPeriod(); + emit(rrcSelected, expiration); + emit(retainGrant, 1); + } + } + } + currGrant->setSpsPriority(lteInfo->getPriority()); // Need to get the creation time for this - mode4Grant->setMaximumLatency(remainingTime_); + currGrant->setMaximumLatency(remainingTime_); } // Need to set the size of our grant to the correct size we need to ask rlc for, i.e. for the sdu size. - schedulingGrant_->setGrantedCwBytes((MAX_CODEWORDS - currentCw_), pkt->getBitLength()); + currGrant->setGrantedCwBytes((MAX_CODEWORDS - currentCw_), pkt->getBitLength()); pkt->setControlInfo(lteInfo); } @@ -701,162 +914,148 @@ void LteMacVUeMode4::handleSelfMessage() // no grant available - if user has backlogged data, it will trigger scheduling request // no harq counter is updated since no transmission is sent. - - LteMode4SchedulingGrant* mode4Grant = dynamic_cast(schedulingGrant_); - - if (mode4Grant == NULL) - { - EV << NOW << " LteMacVUeMode4::handleSelfMessage " << nodeId_ << " NO configured grant" << endl; - - // No configured Grant simply continue - } - else if (mode4Grant->getPeriodic() && mode4Grant->getStartTime() <= NOW) - { - // Periodic checks - if(--expirationCounter_ == mode4Grant->getPeriod()) - { - // Gotten to the point of the final tranmission must determine if we reselect or not. - double randomReReserve = dblrand(1); - if (randomReReserve < probResourceKeep_) - { - int expiration = 0; - if (resourceReservationInterval_ == 0.5){ - expiration = intuniform(10, 30, 3); - } else if (resourceReservationInterval_ == 0.2){ - expiration = intuniform(25, 75, 3); - } else { - expiration = intuniform(5, 15, 3); + map::iterator it; + for (it = grants_.begin(); it != grants_.end(); it++) { + LteMode4SchedulingGrant* mode4Grant = it->second; + if (mode4Grant == NULL) { + EV << NOW << " LteMacVUeMode4::handleSelfMessage " << nodeId_ << " NO configured grant" << endl; + // No configured Grant simply continue + } else if (mode4Grant->getPeriodic() && mode4Grant->getStartTime() <= NOW) { + // Periodic checks + int expirationCounter = mode4Grant->getExpirationCounter(); + int periodCounter = mode4Grant->getPeriodCounter(); + if (--expirationCounter == mode4Grant->getNextPeriod()) { + // Gotten to the point of the final tranmission must determine if we reselect or not. + double randomReReserve = dblrand(1); + if (randomReReserve < probResourceKeep_) { + int expiration = 0; + if (resourceReservationInterval_ == 0.5) { + expiration = intuniform(10, 30, 3); + } else if (resourceReservationInterval_ == 0.2) { + expiration = intuniform(25, 75, 3); + } else { + expiration = intuniform(5, 15, 3); + } + mode4Grant->setResourceReselectionCounter(expiration); + mode4Grant->setFirstTransmission(true); + mode4Grant->setExpirationCounter(expiration * mode4Grant->getPeriod()); + emit(rrcSelected, expiration); + emit(retainGrant, 1); } - mode4Grant -> setResourceReselectionCounter(expiration); - mode4Grant -> setFirstTransmission(true); - expirationCounter_ = expiration * mode4Grant->getPeriod(); - emit(rrcSelected, expiration); - emit(retainGrant, 1); + } + if (--periodCounter > 0 && !mode4Grant->getFirstTransmission()) { + mode4Grant->setPeriodCounter(periodCounter); + mode4Grant->setExpirationCounter(expirationCounter); + continue; + } else if (expirationCounter > 0) { + // resetting grant period + mode4Grant->setPeriodCounter(mode4Grant->getNextPeriod()); + mode4Grant->setExpirationCounter(expirationCounter); + // this is periodic grant TTI - continue with frame sending + } else if (expirationCounter <= 0) { + emit(grantBreak, 1); + mode4Grant->setExpirationCounter(0); + // Find a means of removing this + expiredGrant_ = true; } } - if (--periodCounter_>0 && !mode4Grant->getFirstTransmission()) - { - return; - } - else if (expirationCounter_ > 0) - { - // resetting grant period - periodCounter_=mode4Grant->getPeriod(); - // this is periodic grant TTI - continue with frame sending - } - else if (expirationCounter_ <= 0) - { - emit(grantBreak, 1); - mode4Grant->setExpiration(0); - expiredGrant_ = true; - } - } - bool requestSdu = false; - if (mode4Grant!=NULL && mode4Grant->getStartTime() <= NOW) // if a grant is configured - { - if (mode4Grant->getFirstTransmission()) - { - mode4Grant->setFirstTransmission(false); - } - if(!firstTx) + bool requestSdu = false; + if (mode4Grant != NULL && mode4Grant->getStartTime() <= NOW) // if a grant is configured { - EV << "\t currentHarq_ counter initialized " << endl; - firstTx=true; - currentHarq_ = UE_TX_HARQ_PROCESSES - 2; - } - EV << "\t " << schedulingGrant_ << endl; - - EV << NOW << " LteMacVUeMode4::handleSelfMessage " << nodeId_ << " entered scheduling" << endl; - - bool retx = false; - bool availablePdu = false; - - HarqTxBuffers::iterator it2; - LteHarqBufferTx * currHarq; - for(it2 = harqTxBuffers_.begin(); it2 != harqTxBuffers_.end(); it2++) - { - EV << "\t Looking for retx in acid " << (unsigned int)currentHarq_ << endl; - currHarq = it2->second; - - // check if the current process has unit ready for retx - retx = currHarq->getProcess(currentHarq_)->hasReadyUnits(); - CwList cwListRetx = currHarq->getProcess(currentHarq_)->readyUnitsIds(); - - if (it2->second->isSelected()) - { - LteHarqProcessTx* selectedProcess = it2->second->getSelectedProcess(); - // Ensure that a pdu is not already on the HARQ buffer awaiting sending. - if (selectedProcess != NULL) - { - for (int cw=0; cwgetPduLength(cw) != 0) - { - availablePdu = true; + mode4Grant->setTransmit(true); + if (mode4Grant->getFirstTransmission()) { + mode4Grant->setFirstTransmission(false); + } + if (!firstTx) { + EV << "\t currentHarq_ counter initialized " << endl; + firstTx = true; + currentHarq_ = UE_TX_HARQ_PROCESSES - 2; + } + EV << "\t " << schedulingGrant_ << endl; + + EV << NOW << " LteMacVUeMode4::handleSelfMessage " << nodeId_ << " entered scheduling" << endl; + + bool retx = false; + bool availablePdu = false; + + HarqTxBuffers::iterator it2; + LteHarqBufferTx* currHarq; + for (it2 = harqTxBuffers_.begin(); it2 != harqTxBuffers_.end(); it2++) { + EV << "\t Looking for retx in acid " << (unsigned int)currentHarq_ << endl; + currHarq = it2->second; + + // check if the current process has unit ready for retx + retx = currHarq->getProcess(currentHarq_)->hasReadyUnits(); + CwList cwListRetx = currHarq->getProcess(currentHarq_)->readyUnitsIds(); + + if (it2->second->isSelected()) { + LteHarqProcessTx* selectedProcess = it2->second->getSelectedProcess(); + // Ensure that a pdu is not already on the HARQ buffer awaiting sending. + if (selectedProcess != NULL) { + for (int cw = 0; cw < MAX_CODEWORDS; cw++) { + if (selectedProcess->getPduLength(cw) != 0) { + availablePdu = true; + } } } } - } - EV << "\t [process=" << (unsigned int)currentHarq_ << "] , [retx=" << ((retx)?"true":"false") - << "] , [n=" << cwListRetx.size() << "]" << endl; + EV << "\t [process=" << (unsigned int)currentHarq_ << "] , [retx=" << ((retx) ? "true" : "false") << "] , [n=" << cwListRetx.size() << "]" + << endl; - // if a retransmission is needed - if(retx) - { - UnitList signal; - signal.first=currentHarq_; - signal.second = cwListRetx; - currHarq->markSelected(signal,schedulingGrant_->getUserTxParams()->getLayers().size()); + // if a retransmission is needed + if (retx) { + UnitList signal; + signal.first = currentHarq_; + signal.second = cwListRetx; + currHarq->markSelected(signal, mode4Grant->getUserTxParams()->getLayers().size()); + } } - } - // if no retx is needed, proceed with normal scheduling - // TODO: This may yet be changed to appear after MCS selection, issue is that if you pick max then you might get more sdus then you want - // Basing it on the previous mcs value is at least more realistic as to the size of the pdu you will get. - if(!retx && !availablePdu) - { - scheduleList_ = lcgScheduler_->schedule(); - bool sent = macSduRequest(); + // if no retx is needed, proceed with normal scheduling + // TODO: This may yet be changed to appear after MCS selection, issue is that if you pick max then you might get more sdus then you want + // Basing it on the previous mcs value is at least more realistic as to the size of the pdu you will get. + if (!retx && !availablePdu) { + scheduleList_ = lcgScheduler_->schedule(mode4Grant); + bool sent = macSduRequest(mode4Grant); + + if (!sent) { + macPduMake(); + } - if (!sent) - { - macPduMake(); + requestSdu = sent; } - - requestSdu = sent; + // Message that triggers flushing of Tx H-ARQ buffers for all users + // This way, flushing is performed after the (possible) reception of new MAC PDUs + cMessage* flushHarqMsg = new cMessage("flushHarqMsg"); + // Might add a parameter for the appId which results in the flush + flushHarqMsg->setSchedulingPriority(1); // after other messages + scheduleAt(NOW, flushHarqMsg); } - // Message that triggers flushing of Tx H-ARQ buffers for all users - // This way, flushing is performed after the (possible) reception of new MAC PDUs - cMessage* flushHarqMsg = new cMessage("flushHarqMsg"); - flushHarqMsg->setSchedulingPriority(1); // after other messages - scheduleAt(NOW, flushHarqMsg); - } - //============================ DEBUG ========================== - HarqTxBuffers::iterator it; - EV << "\n htxbuf.size " << harqTxBuffers_.size() << endl; + //============================ DEBUG ========================== + HarqTxBuffers::iterator it; - int cntOuter = 0; - int cntInner = 0; - for(it = harqTxBuffers_.begin(); it != harqTxBuffers_.end(); it++) - { - LteHarqBufferTx* currHarq = it->second; - BufferStatus harqStatus = currHarq->getBufferStatus(); - BufferStatus::iterator jt = harqStatus.begin(), jet= harqStatus.end(); + EV << "\n htxbuf.size " << harqTxBuffers_.size() << endl; - EV_DEBUG << "\t cicloOuter " << cntOuter << " - bufferStatus.size=" << harqStatus.size() << endl; - for(; jt != jet; ++jt) - { - EV_DEBUG << "\t\t cicloInner " << cntInner << " - jt->size=" << jt->size() - << " - statusCw(0/1)=" << jt->at(0).second << "/" << jt->at(1).second << endl; + int cntOuter = 0; + int cntInner = 0; + for (it = harqTxBuffers_.begin(); it != harqTxBuffers_.end(); it++) { + LteHarqBufferTx* currHarq = it->second; + BufferStatus harqStatus = currHarq->getBufferStatus(); + BufferStatus::iterator jt = harqStatus.begin(), jet = harqStatus.end(); + + EV_DEBUG << "\t cicloOuter " << cntOuter << " - bufferStatus.size=" << harqStatus.size() << endl; + for (; jt != jet; ++jt) { + EV_DEBUG << "\t\t cicloInner " << cntInner << " - jt->size=" << jt->size() << " - statusCw(0/1)=" << jt->at(0).second << "/" << jt->at(1).second + << endl; + } } - } - //======================== END DEBUG ========================== + //======================== END DEBUG ========================== - if (!requestSdu) - { - // update current harq process id - currentHarq_ = (currentHarq_+1) % harqProcesses_; + if (!requestSdu) { + // update current harq process id + currentHarq_ = (currentHarq_ + 1) % harqProcesses_; + } } EV << "--- END UE MAIN LOOP ---" << endl; @@ -873,7 +1072,8 @@ void LteMacVUeMode4::macHandleSps(cPacket* pkt) SpsCandidateResources* candidatesPacket = check_and_cast(pkt); std::vector> CSRs = candidatesPacket->getCSRs(); - LteMode4SchedulingGrant* mode4Grant = check_and_cast(schedulingGrant_); + int appId = candidatesPacket->getApplicationId(); + LteMode4SchedulingGrant* mode4Grant = grants_[appId]; // Select random element from vector int index = intuniform(0, CSRs.size()-1, 1); @@ -884,12 +1084,12 @@ void LteMacVUeMode4::macHandleSps(cPacket* pkt) emit(grantStartTime, selectedStartTime); - int initiailSubchannel = std::get<2>(selectedCR); - int finalSubchannel = initiailSubchannel + mode4Grant->getNumSubchannels(); // Is this actually one additional subchannel? + int initialSubchannel = std::get<2>(selectedCR); + int finalSubchannel = initialSubchannel + mode4Grant->getNumSubchannels(); // Is this actually one additional subchannel? bool reservedCSR = std::get<3>(selectedCR); // Emit statistic about the use of resources, i.e. the initial subchannel and it's length. - emit(selectedSubchannelIndex, initiailSubchannel); + emit(selectedSubchannelIndex, initialSubchannel); emit(selectedNumSubchannels, mode4Grant->getNumSubchannels()); emit(takingReservedGrant, reservedCSR); @@ -899,7 +1099,7 @@ void LteMacVUeMode4::macHandleSps(cPacket* pkt) if (adjacencyPSCCHPSSCH_){ // Adjacent mode just provide the allocated bands - for (int i=initiailSubchannel;igetNumSubchannels()) ; b++) { grantedBlocks[MACRO][b] = 1; @@ -931,7 +1131,7 @@ void LteMacVUeMode4::macHandleSps(cPacket* pkt) mode4Grant->setTotalGrantedBlocks(totalGrantedBlocks); // account for the 2 RBs used for the sci message mode4Grant->setDirection(D2D_MULTI); mode4Grant->setCodewords(1); - mode4Grant->setStartingSubchannel(initiailSubchannel); + mode4Grant->setStartingSubchannel(initialSubchannel); mode4Grant->setMcs(maxMCSPSSCH_); LteMod mod = _QPSK; @@ -953,6 +1153,9 @@ void LteMacVUeMode4::macHandleSps(cPacket* pkt) currentCw_ = MAX_CODEWORDS - currentCw_; periodCounter_= mode4Grant->getPeriod(); + + // fix expiration to 500-1500ms to avoid extended grant times. + // expirationCounter_= (mode4Grant->getResourceReselectionCounter() * 100) + 1; expirationCounter_= (mode4Grant->getResourceReselectionCounter() * periodCounter_) + 1; // TODO: Setup for HARQ retransmission, if it can't be satisfied then selection must occur again. @@ -962,7 +1165,7 @@ void LteMacVUeMode4::macHandleSps(cPacket* pkt) delete pkt; } -void LteMacVUeMode4::macGenerateSchedulingGrant(double maximumLatency, int priority, int pktSize) +void LteMacVUeMode4::macGenerateSchedulingGrant(double maximumLatency, int priority, int pktSize, int appId, int RRI) { /** * 1. Packet priority @@ -977,9 +1180,11 @@ void LteMacVUeMode4::macGenerateSchedulingGrant(double maximumLatency, int prior // Priority is the most difficult part to figure out, for the moment I will assign it as a fixed value mode4Grant -> setStartTime(NOW + 1000); // Just forces start time into future so we don't accidentally trigger it early mode4Grant -> setSpsPriority(priority); - mode4Grant -> setPeriod(resourceReservationInterval_ * 100); + mode4Grant -> setPeriod(RRI * 100); + mode4Grant -> setNextPeriod(RRI * 100); mode4Grant -> setMaximumLatency(maximumLatency); mode4Grant -> setPossibleRRIs(validResourceReservationIntervals_); + mode4Grant -> setApplicationId(appId); int minSubchannelNumberPSSCH = minSubchannelNumberPSSCH_; int maxSubchannelNumberPSSCH = maxSubchannelNumberPSSCH_; @@ -987,7 +1192,7 @@ void LteMacVUeMode4::macGenerateSchedulingGrant(double maximumLatency, int prior int maxMCS = maxMCSPSSCH_; int numSubchannels = 0; bool foundValidMCS = false; - double resourceReservationInterval = resourceReservationInterval_; + double resourceReservationInterval = RRI; if (useCBR_) { @@ -1064,9 +1269,9 @@ void LteMacVUeMode4::macGenerateSchedulingGrant(double maximumLatency, int prior int mcsCapacity = 0; for (int mcs=minMCS; mcs <= maxMCS; mcs++) { LteMod mod = _QPSK; - if (maxMCSPSSCH_ > 9 && maxMCSPSSCH_ < 17) { + if (mcs > 9 && mcs < 17) { mod = _16QAM; - } else if (maxMCSPSSCH_ > 16 && maxMCSPSSCH_ < 29) { + } else if (mcs > 16 && mcs < 29) { mod = _64QAM; } @@ -1089,9 +1294,9 @@ void LteMacVUeMode4::macGenerateSchedulingGrant(double maximumLatency, int prior } mode4Grant -> setNumberSubchannels(numSubchannels); - if (randomScheduling_){ - mode4Grant -> setResourceReselectionCounter(0); - mode4Grant -> setExpiration(0); + if ((randomScheduling_) || (nonPeriodic_) ){ + mode4Grant -> setResourceReselectionCounter(5); + mode4Grant -> setExpirationCounter(0); mode4Grant -> setPeriodic(false); emit(rrcSelected, 0); } else { @@ -1101,16 +1306,17 @@ void LteMacVUeMode4::macGenerateSchedulingGrant(double maximumLatency, int prior // Again technically this needs to reconfigurable as well. But all of that needs to come in through ini and such. int resourceReselectionCounter = 0; - if (resourceReservationInterval_ == 0.5) { + if (resourceReservationInterval == 0.5) { resourceReselectionCounter = intuniform(10, 30, 3); - } else if (resourceReservationInterval_ == 0.2) { + } else if (resourceReservationInterval == 0.2) { resourceReselectionCounter = intuniform(25, 75, 3); } else { resourceReselectionCounter = intuniform(5, 15, 3); } mode4Grant -> setResourceReselectionCounter(resourceReselectionCounter); - mode4Grant -> setExpiration(resourceReselectionCounter * resourceReservationInterval); + mode4Grant -> setPeriodCounter(resourceReservationInterval * 100); + mode4Grant -> setExpirationCounter((resourceReselectionCounter * resourceReservationInterval) * 100); emit(rrcSelected, resourceReselectionCounter); } @@ -1124,9 +1330,9 @@ void LteMacVUeMode4::macGenerateSchedulingGrant(double maximumLatency, int prior phyGrant->setControlInfo(uinfo); - sendLowerPackets(phyGrant); + grants_[appId] = mode4Grant; - schedulingGrant_ = mode4Grant; + sendLowerPackets(phyGrant); emit(grantRequests, 1); } @@ -1139,16 +1345,25 @@ void LteMacVUeMode4::flushHarqBuffers() // Maintain unit list maybe and that causes retrans? // But purge them once all messages sent. - LteMode4SchedulingGrant* mode4Grant = dynamic_cast(schedulingGrant_); + LteMode4SchedulingGrant* mode4Grant = NULL; + + map::iterator it; + for (it = grants_.begin(); it != grants_.end(); it++) { + mode4Grant = it->second; + if (mode4Grant->getTransmit()) + break; + } int period = 0; - if (schedulingGrant_ != NULL){ - period = schedulingGrant_->getPeriod(); + if (mode4Grant != NULL){ + period = mode4Grant->getPeriod(); } // Ensure CR updated. channelOccupancyRatio_ = calculateChannelOccupancyRatio(period); + bool grantBroken = false; + HarqTxBuffers::iterator it2; for(it2 = harqTxBuffers_.begin(); it2 != harqTxBuffers_.end(); it2++) { @@ -1197,6 +1412,72 @@ void LteMacVUeMode4::flushHarqBuffers() else cbrMaxMCS = (int)got->second; + int rri = mode4Grant->getPeriod(); + if (rriLookup_) { + // RRI Adaptation based on lookup table similar to DCC + got = cbrMap.find("allowedRRI"); + if (got != cbrMap.end()) { + rri = (int) got->second * 100; + } + } + else if (crLimit_) { + got = cbrMap.find("cr-Limit"); + // Calculate an RRI which ensures the channelOccupancyRatio reduces to the point that + // it remains within the cr-limit + emit(crLimit, got->second); + int i = 0; + double newOccupancyRatio = channelOccupancyRatio_; + rri = (int) validResourceReservationIntervals_.at(i) * 100; + while (newOccupancyRatio > got->second && i < validResourceReservationIntervals_.size()){ + rri = (int) validResourceReservationIntervals_.at(i) * 100; + newOccupancyRatio = calculateChannelOccupancyRatio(rri); + i++; + } + } + else if (limeric_){ + // Calculate an RRI which ensures the channelOccupancyRatio reduces to the point that + // it remains within the cr-limit + // Update Limeric Delta + emit(crLimit, delta_); + + int i = 0; + if (usage_) { + if (delta_ > 0 & mode4Grant->getNumSubchannels() > 0) { + double delay = (mode4Grant->getNumSubchannels()/(numSubchannels_ * 1000.0)) / delta_; + if (delay > 0) { + delay = delay * 1000; + rri = std::max(100.0, std::min(delay, 1000.0)); + rri = (rri + 50) / 100 * 100; + } + } else { + // Simply avoid any issues with division by zero + rri = (int) validResourceReservationIntervals_.at(i) * 100; + } + } else { + if (delta_ > 0 & channelOccupancyRatio_ > 0) { + double newOccupancyRatio = channelOccupancyRatio_; + rri = (int) validResourceReservationIntervals_.at(i) * 100; + while (newOccupancyRatio > delta_ && i < validResourceReservationIntervals_.size()){ + rri = (int) validResourceReservationIntervals_.at(i) * 100; + newOccupancyRatio = calculateChannelOccupancyRatio(rri); + i++; + } + } + } + } + + if (rri != mode4Grant->getPeriod()) { + if (mode4Grant->getExpirationCounter() > 0) { + // Only update if the grant isn't ending + int currentRC = mode4Grant->getExpirationCounter() / mode4Grant->getPeriod() * 100; + mode4Grant->setExpirationCounter((rri * currentRC) * 100); + mode4Grant->setPeriod(rri); + mode4Grant->setNextPeriod(rri * 100); + mode4Grant->setPeriodCounter(rri * 100); + emit(rriChange, rri); + } + } + if (maxMCSPSSCH_ < cbrMinMCS || cbrMaxMCS < minMCSPSSCH_) { // No overlap therefore I will use the cbr values (this is left to the UE). @@ -1217,11 +1498,11 @@ void LteMacVUeMode4::flushHarqBuffers() for (int mcs=minMCS; mcs <= maxMCS; mcs++) { LteMod mod = _QPSK; - if (maxMCSPSSCH_ > 9 && maxMCSPSSCH_ < 17) + if (mcs > 9 && mcs < 17) { mod = _16QAM; } - else if (maxMCSPSSCH_ > 16 && maxMCSPSSCH_ < 29 ) + else if (mcs > 16 && mcs < 29 ) { mod = _64QAM; } @@ -1257,10 +1538,15 @@ void LteMacVUeMode4::flushHarqBuffers() phyGrant->setControlInfo(uinfo); - // Send Grant to PHY layer for sci creation - sendLowerPackets(phyGrant); - // Send pdu to PHY layer for sending. - it2->second->sendSelectedDown(); + if (noTransmissions_) { + // Drop the selected Process. + it2->second->forceDropSelectedProcess(); + } else { + // Send Grant to PHY layer for sci creation + sendLowerPackets(phyGrant); + // Send pdu to PHY layer for sending. + it2->second->sendSelectedDown(); + } // Log transmission to A calculation log previousTransmissions_[NOW.dbl()] = mode4Grant->getNumSubchannels(); @@ -1275,8 +1561,9 @@ void LteMacVUeMode4::flushHarqBuffers() if (!foundValidMCS) { // Never found an MCS to satisfy the requirements of the message must regenerate grant - LteMode4SchedulingGrant* mode4Grant = check_and_cast(schedulingGrant_); int priority = mode4Grant->getSpsPriority(); + int appId = mode4Grant->getApplicationId(); + int currRRI = mode4Grant->getNextPeriod(); simtime_t elapsedTime = NOW - receivedTime_; remainingTime_ -= (elapsedTime.dbl() * 1000); @@ -1287,14 +1574,16 @@ void LteMacVUeMode4::flushHarqBuffers() { //emit(droppedTimeout, 1); selectedProcess->forceDropProcess(); - delete schedulingGrant_; - schedulingGrant_ = NULL; + delete mode4Grant; + grantBroken = true; + grants_.erase(appId); } else { - delete schedulingGrant_; - schedulingGrant_ = NULL; - macGenerateSchedulingGrant(remainingTime_, priority, pduLength); + delete mode4Grant; + grants_.erase(appId); + grantBroken = true; + macGenerateSchedulingGrant(remainingTime_, priority, pduLength, appId, currRRI); } } } @@ -1310,20 +1599,82 @@ void LteMacVUeMode4::flushHarqBuffers() if (missedTransmissions_ >= reselectAfter_) { // Simply remove the grant next time we shall reschedule it. - delete schedulingGrant_; - schedulingGrant_ = NULL; + int appId = mode4Grant->getApplicationId(); + delete mode4Grant; + grantBroken = true; + grants_.erase(appId); + missedTransmissions_ = 0; emit(grantBreakMissedTrans, 1); } } } - if (expiredGrant_) { + if (mode4Grant->getExpirationCounter() == 0 && !grantBroken) { // Grant has expired, only generate new grant on receiving next message to be sent. - delete schedulingGrant_; - schedulingGrant_ = NULL; - expiredGrant_ = false; + int appId = mode4Grant->getApplicationId(); + delete mode4Grant; + grants_.erase(appId); + } +} + +void LteMacVUeMode4::updateLimeric() +{ + double cbr_delta = cbrTarget_ - averageCBR_; + + double delta_offset = 0.0; + // If sign(CBRtarget - CBRITS-S) is positive + if (cbr_delta > 0.0) { + // δoffset = min(β x (CBRtarget - CBRITS-S), G_plus_max) + delta_offset = std::min(beta_ * cbr_delta, g_plus_max_); + } else { + // δoffset = max(β x (CBRtarget - CBRITS-S), G_minus_max) + delta_offset = std::max(beta_ * cbr_delta, g_minus_max_); + } + + delta_ = ((1.0 - alpha_) * delta_) + delta_offset; + + if (delta_ > delta_max_){ + delta_ = delta_max_; + } else if (delta_ < delta_min_){ + delta_ = delta_min_; } + + emit(limericDelta, delta_); + + cMessage* updateLimeric = new cMessage("updateLimeric"); + updateLimeric->setSchedulingPriority(0); // Generate the subframe at start of next TTI + scheduleAt(NOW + 0.2, updateLimeric); +} + +bool LteMacVUeMode4::macSduRequest(LteMode4SchedulingGrant* grant) +{ + EV << "----- START LteMacUeRealistic::macSduRequest -----\n"; + bool sent = false; + // Ask for a MAC sdu for each scheduled user on each codeword + LteMacScheduleList::const_iterator it; + for (it = scheduleList_->begin(); it != scheduleList_->end(); it++) + { + MacCid destCid = it->first.first; + Codeword cw = it->first.second; + MacNodeId destId = MacCidToNodeId(destCid); + + // get the number of granted bytes + unsigned int allocatedBytes = grant->getGrantedCwBytes(cw); + + // send the request message to the upper layer + LteMacSduRequest* macSduRequest = new LteMacSduRequest("LteMacSduRequest"); + macSduRequest->setUeId(destId); + macSduRequest->setLcid(MacCidToLcid(destCid)); + macSduRequest->setSduSize(allocatedBytes - MAC_HEADER); // do not consider MAC header size + macSduRequest->setControlInfo((&connDesc_[destCid])->dup()); + sendUpperPackets(macSduRequest); + + sent = true; + } + + EV << "------ END LteMacUeRealistic::macSduRequest ------\n"; + return sent; } void LteMacVUeMode4::finish() @@ -1334,4 +1685,31 @@ void LteMacVUeMode4::finish() delete ueInfo_; } +void +LteMacVUeMode4::updateUserTxParam(cPacket* pkt) +{ + UserControlInfo *lteInfo = check_and_cast + (pkt->getControlInfo()); + + if (lteInfo->getFrameType() != DATAPKT) + return; + + LteMode4SchedulingGrant* mode4Grant; + map::iterator it; + for (it = grants_.begin(); it != grants_.end(); it++) { + mode4Grant = it->second; + if (mode4Grant->getTransmit()) + break; + } + + lteInfo->setUserTxParams(mode4Grant->getUserTxParams()->dup()); + + lteInfo->setTxMode(mode4Grant->getUserTxParams()->readTxMode()); + + int grantedBlocks = mode4Grant->getTotalGrantedBlocks(); + + lteInfo->setGrantedBlocks(mode4Grant->getGrantedBlocks()); + lteInfo->setTotalGrantedBlocks(grantedBlocks); +} + diff --git a/src/stack/mac/layer/LteMacVUeMode4.h b/src/stack/mac/layer/LteMacVUeMode4.h index a93449ed..0c7a33c8 100644 --- a/src/stack/mac/layer/LteMacVUeMode4.h +++ b/src/stack/mac/layer/LteMacVUeMode4.h @@ -21,6 +21,7 @@ #include "stack/mac/layer/LteMacUeRealisticD2D.h" #include "corenetwork/deployer/LteDeployer.h" +#include "stack/mac/packet/LteSchedulingGrant.h" #include //class LteMode4SchedulingGrant; @@ -42,6 +43,8 @@ class LteMacVUeMode4: public LteMacUeRealisticD2D { // Multicast D2D BSR handling bool bsrD2DMulticastTriggered_; + std::map grants_; + // All of the following should be configurable by the OMNet++ ini file and maybe even taken from higher layers if that's possible. double probResourceKeep_; double resourceReservationInterval_; @@ -59,10 +62,29 @@ class LteMacVUeMode4: public LteMacUeRealisticD2D { int currentCbrIndex_; double channelOccupancyRatio_; double cbr_; + bool limeric_; + double cbrTarget_; + double averageCBR_; + double delta_; + double alpha_; + double beta_; + double g_plus_max_; + double g_minus_max_; + double delta_max_; + double delta_min_; + bool usage_; + int averageCBRIndex_; bool useCBR_; bool packetDropping_; + bool rriLookup_; + bool crLimit_; + bool dccMechanism_; bool adjacencyPSCCHPSSCH_; bool randomScheduling_; + bool nonPeriodic_; + bool noTransmissions_; + bool adaptiveRRI_; + bool alwaysReschedule_; int missedTransmissions_; double remainingTime_; @@ -75,9 +97,14 @@ class LteMacVUeMode4: public LteMacUeRealisticD2D { std::vector> cbrPSSCHTxConfigList_; std::vector> cbrLevels_; + std::vector> cbrUpwardTransitions_; + std::vector> cbrDownwardTransitions_; + std::unordered_map previousTransmissions_; std::vector validResourceReservationIntervals_; + std::vector cbrRecordings_; + McsTable dlMcsTable_; McsTable ulMcsTable_; McsTable d2dMcsTable_; @@ -111,6 +138,10 @@ class LteMacVUeMode4: public LteMacUeRealisticD2D { simsignal_t macNodeID; simsignal_t rrcSelected; simsignal_t retainGrant; + simsignal_t rriChange; + simsignal_t channelOccupancyRatio; + simsignal_t limericDelta; + simsignal_t crLimit; // // Lte AMC module // LteAmc *amc_; @@ -128,7 +159,7 @@ class LteMacVUeMode4: public LteMacUeRealisticD2D { /** * Generate a scheduling grant */ - virtual void macGenerateSchedulingGrant(double maximumLatency, int priority, int pktSize); + virtual void macGenerateSchedulingGrant(double maximumLatency, int priority, int pktSize, int appId, int RRI); /** @@ -143,6 +174,8 @@ class LteMacVUeMode4: public LteMacUeRealisticD2D { virtual double calculateChannelOccupancyRatio(int period); + virtual double calculateUsage(); + /** * Analyze gate of incoming packet * and call proper handler @@ -185,8 +218,14 @@ class LteMacVUeMode4: public LteMacUeRealisticD2D { */ void flushHarqBuffers(); + void updateLimeric(); + void finish(); + bool macSduRequest(LteMode4SchedulingGrant* grant); + + void updateUserTxParam(cPacket* pkt); + public: LteMacVUeMode4(); virtual ~LteMacVUeMode4(); diff --git a/src/stack/mac/packet/LteSchedulingGrant.h b/src/stack/mac/packet/LteSchedulingGrant.h index 917b8266..70d888f4 100644 --- a/src/stack/mac/packet/LteSchedulingGrant.h +++ b/src/stack/mac/packet/LteSchedulingGrant.h @@ -149,6 +149,8 @@ class LteMode4SchedulingGrant : public LteSchedulingGrant std::vector possibleRRIs; bool retransmission; bool firstTransmission; + bool transmit; + unsigned int nextPeriod; unsigned int timeGapTransRetrans; unsigned int spsPriority; unsigned int numSubchannels; @@ -157,6 +159,9 @@ class LteMode4SchedulingGrant : public LteSchedulingGrant unsigned int mcs; unsigned int retransSubchannel; // It is possible the retransmission has different resources assigned to it. unsigned int resourceReselectionCounter; + unsigned int periodCounter; + unsigned int expirationCounter; + unsigned int applicationId; public: @@ -165,6 +170,7 @@ class LteMode4SchedulingGrant : public LteSchedulingGrant { numSubchannels = 0; spsPriority = 0; + nextPeriod = 0; maximumLatency = 0; timeGapTransRetrans = 0; startingSubchannel = 0; @@ -172,6 +178,10 @@ class LteMode4SchedulingGrant : public LteSchedulingGrant retransSubchannel = 0; resourceReselectionCounter = 0; firstTransmission = true; + transmit = false; + periodCounter = 0; + expirationCounter = 0; + applicationId = 0; startTime = simTime(); } @@ -191,13 +201,19 @@ class LteMode4SchedulingGrant : public LteSchedulingGrant numSubchannels = other.numSubchannels; spsPriority = other.spsPriority; startTime = other.startTime; + nextPeriod = other.nextPeriod; maximumLatency = other.maximumLatency; timeGapTransRetrans = other.timeGapTransRetrans; startingSubchannel = other.startingSubchannel; mcs = other.mcs; + firstTransmission = other.firstTransmission; + transmit = other.transmit; retransSubchannel = other.retransSubchannel; resourceReselectionCounter = other.resourceReselectionCounter; possibleRRIs = other.possibleRRIs; + periodCounter = other.periodCounter; + expirationCounter = other.expirationCounter; + applicationId = other.applicationId; LteSchedulingGrant::operator=(other); return *this; } @@ -215,6 +231,14 @@ class LteMode4SchedulingGrant : public LteSchedulingGrant { return startTime; } + void setNextPeriod(unsigned int period) + { + nextPeriod = period; + } + unsigned int getNextPeriod() const + { + return nextPeriod; + } void setSpsPriority(unsigned int priority) { spsPriority = priority; @@ -303,6 +327,37 @@ class LteMode4SchedulingGrant : public LteSchedulingGrant { this->firstTransmission = firstTransmission; } + bool getTransmit() const + { + return transmit; + } + void setTransmit(bool transmit) + { + this->transmit = transmit; + } + void setPeriodCounter(unsigned int periodCounter) + { + this->periodCounter = periodCounter; + } + unsigned int getPeriodCounter() const + { + return periodCounter; + } + void setExpirationCounter(unsigned int expirationCounter) + { + this->expirationCounter = expirationCounter; + } + unsigned int getExpirationCounter() const + { + return expirationCounter; + } + unsigned int getApplicationId(){ + return applicationId; + } + void setApplicationId(unsigned int appId) + { + this->applicationId = appId; + } }; #endif diff --git a/src/stack/mac/packet/LteSchedulingGrant.msg b/src/stack/mac/packet/LteSchedulingGrant.msg index afae4254..2fc9b4da 100644 --- a/src/stack/mac/packet/LteSchedulingGrant.msg +++ b/src/stack/mac/packet/LteSchedulingGrant.msg @@ -14,9 +14,10 @@ packet LteSchedulingGrant { @customize(true); // see the generated C++ header for more info + bool periodic; unsigned int period; unsigned int expiration; - // blocks granted on all Remotes, all Bands + // blocks granted on all Remotes, all Bands unsigned int totalGrantedBlocks; // number of codewords unsigned int codewords; @@ -27,4 +28,4 @@ packet LteSchedulingGrant //# const UserTxParams* userTxParams; //# RbMap grantedBlocks; //# -} \ No newline at end of file +} diff --git a/src/stack/mac/scheduler/LteSchedulerUeUl.cc b/src/stack/mac/scheduler/LteSchedulerUeUl.cc index 88ca8f6f..f5663d53 100644 --- a/src/stack/mac/scheduler/LteSchedulerUeUl.cc +++ b/src/stack/mac/scheduler/LteSchedulerUeUl.cc @@ -10,7 +10,6 @@ #include "stack/mac/scheduler/LteSchedulerUeUl.h" #include "stack/mac/layer/LteMacUe.h" #include "stack/mac/amc/UserTxParams.h" -#include "stack/mac/packet/LteSchedulingGrant.h" #include "stack/mac/packet/LteMacPdu.h" #include "stack/mac/scheduler/LcgScheduler.h" #include "stack/mac/scheduler/LcgSchedulerRealistic.h" @@ -106,3 +105,78 @@ LteSchedulerUeUl::schedule() } return &scheduleList_; } + +LteMacScheduleList* +LteSchedulerUeUl::schedule(LteSchedulingGrant* grant) +{ + // 1) Environment Setup + + // clean up old scheduling decisions + scheduleList_.clear(); + + // get the grant +// const LteSchedulingGrant* grant = mac_->getSchedulingGrant(); + Direction dir = grant->getDirection(); + + // get the nodeId of the mac owner node + MacNodeId nodeId = mac_->getMacNodeId(); + + EV << NOW << " LteSchedulerUeUl::schedule - Scheduling node " << nodeId << endl; + + // retrieve Transmission parameters + // const UserTxParams* txPar = grant->getUserTxParams(); + + //! MCW support in UL + unsigned int codewords = grant->getCodewords(); + + // TODO get the amount of granted data per codeword + //unsigned int availableBytes = grant->getGrantedBytes(); + + unsigned int availableBlocks = grant->getTotalGrantedBlocks(); + + // TODO check if HARQ ACK messages should be subtracted from available bytes + + for (Codeword cw = 0; cw < codewords; ++cw) + { + unsigned int availableBytes = grant->getGrantedCwBytes(cw); + + EV << NOW << " LteSchedulerUeUl::schedule - Node " << mac_->getMacNodeId() << " available data from grant are " + << " blocks " << availableBlocks << " [" << availableBytes << " - Bytes] on codeword " << cw << endl; + + // per codeword LCP scheduler invocation + + // invoke the schedule() method of the attached LCP scheduler in order to schedule + // the connections provided + std::map& sdus = lcgScheduler_->schedule(availableBytes, dir); + + // TODO check if this jump is ok + if (sdus.empty()) + continue; + + std::map::const_iterator it = sdus.begin(), et = sdus.end(); + for (; it != et; ++it) + { + // set schedule list entry + std::pair schedulePair(it->first, cw); + scheduleList_[schedulePair] = it->second; + } + + MacCid highestBackloggedFlow = 0; + MacCid highestBackloggedPriority = 0; + MacCid lowestBackloggedFlow = 0; + MacCid lowestBackloggedPriority = 0; + bool backlog = false; + + // get the highest backlogged flow id and priority + backlog = mac_->getHighestBackloggedFlow(highestBackloggedFlow, highestBackloggedPriority); + + if (backlog) // at least one backlogged flow exists + { + // get the lowest backlogged flow id and priority + mac_->getLowestBackloggedFlow(lowestBackloggedFlow, lowestBackloggedPriority); + } + + // TODO make use of above values + } + return &scheduleList_; +} diff --git a/src/stack/mac/scheduler/LteSchedulerUeUl.h b/src/stack/mac/scheduler/LteSchedulerUeUl.h index c7b0d0d9..35d33649 100644 --- a/src/stack/mac/scheduler/LteSchedulerUeUl.h +++ b/src/stack/mac/scheduler/LteSchedulerUeUl.h @@ -11,6 +11,7 @@ #define _LTE_LTE_SCHEDULER_UE_UL_H_ #include "common/LteCommon.h" +#include "stack/mac/packet/LteSchedulingGrant.h" class LteMacUe; class LcgScheduler; @@ -39,6 +40,8 @@ class LteSchedulerUeUl LteMacScheduleList* schedule(); + LteMacScheduleList* schedule(LteSchedulingGrant* grant); + /* * constructor */ diff --git a/src/stack/phy/LtePhy.ned b/src/stack/phy/LtePhy.ned index 64eb1a4a..32c9fb86 100644 --- a/src/stack/phy/LtePhy.ned +++ b/src/stack/phy/LtePhy.ned @@ -86,55 +86,72 @@ simple LtePhyUeD2D extends LtePhyUe { simple LtePhyVUeMode4 extends LtePhyUeD2D { parameters: - @class("LtePhyVUeMode4"); - - bool adjacencyPSCCHPSSCH = default(true); + @class("LtePhyVUeMode4"); - bool rssiFiltering = default(true); - bool rsrpFiltering = default(false); + double delayStartUp @unit(s) = default(0s); - bool randomScheduling = default(false); + bool adjacencyPSCCHPSSCH = default(true); - bool checkAwareness = default(false); + bool rssiFiltering = default(true); + bool rsrpFiltering = default(false); + bool mode2RSRP = default(false); + bool syncCBR = default(false); - int pStep = default(100); - int numSubchannels = default(10); - int subchannelSize = default(5); - int selectionWindowStartingSubframe = default(1); - int thresholdRSSI = default(22); + bool counterMechanism = default(false); + bool oneShotMechanism = default(false); + bool oneShotCsrMechanism = default(false); - int sensingWindowSizeOverride = default(-1); + bool randomScheduling = default(false); - int shapeFactor = default(6); + bool checkAwareness = default(false); - @signal[cbr]; - @statistic[cbr](title="Channel Busy Ratio"; source="cbr"; record=mean,vector); - @signal[cbrPscch]; - @statistic[cbrPscch](title="Channel Busy Ratio for PSCCH"; source="cbrPscch"; record=mean,vector); + int oneShotT2 = default(25); + int oneShotT3 = default(100); + int counterMaximum = default(40); - @signal[threshold]; - @statistic[threshold](title="Increase in RSRP needed to find csr"; source="threshold"; record=mean,vector); + int pStep = default(100); + int numSubchannels = default(10); + int subchannelSize = default(5); + int selectionWindowStartingSubframe = default(1); + int thresholdRSSI = default(22); - @signal[sciSent]; - @statistic[sciSent](title="Number of sci sent"; source="sciSent"; record=sum,vector); + int sensingWindowSizeOverride = default(-1); - @signal[sciReceived]; + int shapeFactor = default(6); + + @signal[cbr]; + @statistic[cbr](title="Channel Busy Ratio"; source="cbr"; record=mean,vector); + @signal[cbrPscch]; + @statistic[cbrPscch](title="Channel Busy Ratio for PSCCH"; source="cbrPscch"; record=mean,vector); + + @signal[threshold]; + @statistic[threshold](title="Increase in RSRP needed to find csr"; source="threshold"; record=mean,vector); + + @signal[sciSent]; + @statistic[sciSent](title="Number of sci sent"; source="sciSent"; record=sum,vector); + + @signal[sciReceived]; @statistic[sciReceived](title="Number of received sci"; source="sciReceived"; record=sum,vector); @signal[sciDecoded]; @statistic[sciDecoded](title="Number of sci successfully decoded"; source="sciDecoded"; record=sum,vector); + @signal[oneShot]; + @statistic[oneShot](title="oneShot sci"; source="oneShot"; record=sum,vector); + + @signal[csrReschedule]; + @statistic[csrReschedule](title="CSR rescheduling "; source="subchannelsUsedToSend"; record=sum,vector); - @signal[sciFailedHalfDuplex]; - @statistic[sciFailedHalfDuplex](title="Number of failed SCIs due to Half Duplex"; source="sciFailedHalfDuplex"; record=sum,vector); - @signal[sciFailedDueToProp]; - @statistic[sciFailedDueToProp](title="Number of failed SCIs due to propogation"; source="sciFailedDueToProp"; record=sum,vector); - @signal[sciFailedDueToInterference]; - @statistic[sciFailedDueToInterference](title="Number of failed SCIs due to interference"; source="sciFailedDueToInterference"; record=sum,vector); + @signal[sciFailedHalfDuplex]; + @statistic[sciFailedHalfDuplex](title="Number of failed SCIs due to Half Duplex"; source="sciFailedHalfDuplex"; record=sum,vector); + @signal[sciFailedDueToProp]; + @statistic[sciFailedDueToProp](title="Number of failed SCIs due to propogation"; source="sciFailedDueToProp"; record=sum,vector); + @signal[sciFailedDueToInterference]; + @statistic[sciFailedDueToInterference](title="Number of failed SCIs due to interference"; source="sciFailedDueToInterference"; record=sum,vector); - @signal[sciUnsensed]; - @statistic[sciUnsensed](title="Number of failed SCIs due to RSRP below threshold"; source="sciUnsensed"; record=sum,vector); + @signal[sciUnsensed]; + @statistic[sciUnsensed](title="Number of failed SCIs due to RSRP below threshold"; source="sciUnsensed"; record=sum,vector); - @signal[txRxDistanceSCI]; - @statistic[txRxDistanceSCI](title="Distance between transmitter and receiver"; source="txRxDistanceSCI"; record=mean,vector); + @signal[txRxDistanceSCI]; + @statistic[txRxDistanceSCI](title="Distance between transmitter and receiver"; source="txRxDistanceSCI"; record=mean,vector); @signal[tbSent]; @statistic[tbSent](title="Number of tb sent"; source="tbSent"; record=sum,vector); @@ -156,50 +173,50 @@ simple LtePhyVUeMode4 extends LtePhyUeD2D { @statistic[periodic](title="Identifies traffic as periodic or aperiodic"; source="periodic"; record=vector); @signal[tbFailedHalfDuplex]; - @statistic[tbFailedHalfDuplex](title="Number of failed TBs due to Half Duplex"; source="tbFailedHalfDuplex"; record=sum,vector); - @signal[tbFailedDueToProp]; - @statistic[tbFailedDueToProp](title="Number of failed TBs due to propogation"; source="tbFailedDueToProp"; record=sum,vector); - @signal[tbFailedDueToInterference]; - @statistic[tbFailedDueToInterference](title="Number of failed TBs due to interference"; source="tbFailedDueToInterference"; record=sum,vector); + @statistic[tbFailedHalfDuplex](title="Number of failed TBs due to Half Duplex"; source="tbFailedHalfDuplex"; record=sum,vector); + @signal[tbFailedDueToProp]; + @statistic[tbFailedDueToProp](title="Number of failed TBs due to propogation"; source="tbFailedDueToProp"; record=sum,vector); + @signal[tbFailedDueToInterference]; + @statistic[tbFailedDueToInterference](title="Number of failed TBs due to interference"; source="tbFailedDueToInterference"; record=sum,vector); @signal[tbFailedDueToPropIgnoreSCI]; - @statistic[tbFailedDueToPropIgnoreSCI](title="Number of failed TBs due to propogation"; source="tbFailedDueToPropIgnoreSCI"; record=sum,vector); - @signal[tbFailedDueToInterferenceIgnoreSCI]; - @statistic[tbFailedDueToInterferenceIgnoreSCI](title="Number of failed TBs due to interference"; source="tbFailedDueToInterferenceIgnoreSCI"; record=sum,vector); - @signal[tbDecodedIgnoreSCI]; - @statistic[tbDecodedIgnoreSCI](title="Number of failed TBs due to interference"; source="tbDecodedIgnoreSCI"; record=sum,vector); + @statistic[tbFailedDueToPropIgnoreSCI](title="Number of failed TBs due to propogation"; source="tbFailedDueToPropIgnoreSCI"; record=sum,vector); + @signal[tbFailedDueToInterferenceIgnoreSCI]; + @statistic[tbFailedDueToInterferenceIgnoreSCI](title="Number of failed TBs due to interference"; source="tbFailedDueToInterferenceIgnoreSCI"; record=sum,vector); + @signal[tbDecodedIgnoreSCI]; + @statistic[tbDecodedIgnoreSCI](title="Number of failed TBs due to interference"; source="tbDecodedIgnoreSCI"; record=sum,vector); - @signal[txRxDistanceTB]; - @statistic[txRxDistanceTB](title="Distance between transmitter and receiver"; source="txRxDistanceTB"; record=mean,vector); + @signal[txRxDistanceTB]; + @statistic[txRxDistanceTB](title="Distance between transmitter and receiver"; source="txRxDistanceTB"; record=mean,vector); - @signal[senderID]; + @signal[senderID]; @statistic[senderID](title="ID of node who sent message"; source="senderID"; record=vector); - @signal[subchannelReceived]; - @statistic[subchannelReceived](title="Initial Subchannel on which packet is received"; source="subchannelReceived"; record=mean,vector); - @signal[subchannelsUsed]; - @statistic[subchannelsUsed](title="Number of Subchannels used for the received packet"; source="subchannelsUsed"; record=mean, vector); - - @signal[subchannelSent]; - @statistic[subchannelSent](title="starting Subchannel used for sent message"; source="subchannelSent"; record=sum,vector); - @signal[subchannelsUsedToSend]; - @statistic[subchannelsUsedToSend](title="Number of subchannels used for message"; source="subchannelsUsedToSend"; record=sum,vector); - - @signal[interPacketDelay]; - @statistic[interPacketDelay](title="Delay between packet receptions from a node"; source="interPacketDelay"; record=mean,vector); - - @signal[awareness1sStat]; - @statistic[awareness1sStat](title="Node Awareness 1s window"; source="awareness1sStat"; record=mean,vector); - @signal[awareness500msStat]; - @statistic[awareness500msStat](title="Node Awareness 500ms window"; source="awareness500msStat"; record=mean,vector); - @signal[awareness200msStat]; - @statistic[awareness200msStat](title="Node Awareness 200ms window"; source="awareness200msStat"; record=mean,vector); - - @signal[posX]; - @statistic[posX](title="X position of node (at reception time)"; source="posX"; record=mean, vector); - @signal[posY]; - @statistic[posY](title="Y position of node (at reception time)"; source="posY"; record=mean, vector); + @signal[subchannelReceived]; + @statistic[subchannelReceived](title="Initial Subchannel on which packet is received"; source="subchannelReceived"; record=mean,vector); + @signal[subchannelsUsed]; + @statistic[subchannelsUsed](title="Number of Subchannels used for the received packet"; source="subchannelsUsed"; record=mean, vector); + + @signal[subchannelSent]; + @statistic[subchannelSent](title="starting Subchannel used for sent message"; source="subchannelSent"; record=sum,vector); + @signal[subchannelsUsedToSend]; + @statistic[subchannelsUsedToSend](title="Number of subchannels used for message"; source="subchannelsUsedToSend"; record=sum,vector); + + @signal[interPacketDelay]; + @statistic[interPacketDelay](title="Delay between packet receptions from a node"; source="interPacketDelay"; record=mean,vector); + + @signal[awareness1sStat]; + @statistic[awareness1sStat](title="Node Awareness 1s window"; source="awareness1sStat"; record=mean,vector); + @signal[awareness500msStat]; + @statistic[awareness500msStat](title="Node Awareness 500ms window"; source="awareness500msStat"; record=mean,vector); + @signal[awareness200msStat]; + @statistic[awareness200msStat](title="Node Awareness 200ms window"; source="awareness200msStat"; record=mean,vector); + + @signal[posX]; + @statistic[posX](title="X position of node (at reception time)"; source="posX"; record=mean, vector); + @signal[posY]; + @statistic[posY](title="Y position of node (at reception time)"; source="posY"; record=mean, vector); } // diff --git a/src/stack/phy/layer/LtePhyVUeMode4.cc b/src/stack/phy/layer/LtePhyVUeMode4.cc index f5f4dd56..6faeb08c 100644 --- a/src/stack/phy/layer/LtePhyVUeMode4.cc +++ b/src/stack/phy/layer/LtePhyVUeMode4.cc @@ -48,12 +48,24 @@ void LtePhyVUeMode4::initialize(int stage) selectionWindowStartingSubframe_ = par("selectionWindowStartingSubframe"); numSubchannels_ = par("numSubchannels"); subchannelSize_ = par("subchannelSize"); + counterMechanism_ = par("counterMechanism"); + counterMax_ = par("counterMaximum"); + currentCounter_ = -1; + counterTriggered_ = false; d2dDecodingTimer_ = NULL; transmitting_ = false; beginTransmission_ = false; rssiFiltering_ = par("rssiFiltering"); rsrpFiltering_ = par("rsrpFiltering"); - + mode2RSRP_ = par("mode2RSRP"); + bool syncCBR = par("syncCBR"); + delayStartUp_ = par("delayStartUp"); + + oneShotMechanism_ = par("oneShotMechanism"); + oneShotT2_ = par("oneShotT2"); + oneShotT3_ = par("oneShotT3"); + oneShotSensing_ = false; + csrSensing_ = false; checkAwareness_ = par("checkAwareness"); int thresholdRSSI = par("thresholdRSSI"); @@ -78,6 +90,7 @@ void LtePhyVUeMode4::initialize(int stage) sciReceived = registerSignal("sciReceived"); sciDecoded = registerSignal("sciDecoded"); + oneShot = registerSignal("oneShot"); csrReschedule = registerSignal("csrReschedule"); sciFailedDueToProp = registerSignal("sciFailedDueToProp"); @@ -89,6 +102,7 @@ void LtePhyVUeMode4::initialize(int stage) sciReceived_ = 0; sciDecoded_ = 0; + oneShot_ = 0; sciFailedHalfDuplex_ = 0; sciFailedDueToProp_ = 0; @@ -156,19 +170,34 @@ void LtePhyVUeMode4::initialize(int stage) sensingWindowFront_ = 0; // Will ensure when we first update the sensing window we don't skip over the first element - cbrCountDown_ = intuniform(0, 1000); + if (syncCBR){ + // Default to 500 just to allow some time for simulation to run before starting to check CBR + cbrCountDown_ = 500; + } else { + cbrCountDown_ = intuniform(0, 1000); + } + } - else if (stage == INITSTAGE_NETWORK_LAYER_2) + else if (stage == inet::INITSTAGE_NETWORK_LAYER_2) { // Need to start initialising the sensingWindow deployer_ = getDeployer(); + + nodeId_ = getAncestorPar("macNodeId"); + int index = intuniform(0, binder_->phyPisaData.maxChannel() - 1); deployer_->lambdaInit(nodeId_, index); deployer_->channelUpdate(nodeId_, intuniform(1, binder_->phyPisaData.maxChannel2())); - nodeId_ = getAncestorPar("macNodeId"); + initComplete_ = false; - initialiseSensingWindow(); + if (delayStartUp_ == 0 || delayStartUp_ < NOW) { + initialiseSensingWindow(); + } else { + cMessage* updateSubframe = new cMessage("updateSubframe"); + updateSubframe->setSchedulingPriority(0); // Generate the subframe at start of next TTI + scheduleAt(delayStartUp_ + TTI, updateSubframe); + } } } @@ -231,6 +260,7 @@ void LtePhyVUeMode4::handleSelfMessage(cMessage *msg) emit(sciFailedHalfDuplex, sciFailedHalfDuplex_); emit(subchannelReceived, subchannelReceived_); emit(subchannelsUsed, subchannelsUsed_); + emit(oneShot, oneShot_); sciReceived_ = 0; sciDecoded_ = 0; @@ -240,6 +270,7 @@ void LtePhyVUeMode4::handleSelfMessage(cMessage *msg) subchannelReceived_ = 0; subchannelsUsed_ = 0; sciUnsensed_ = 0; + oneShot_ = 0; } int countTbs = 0; @@ -333,26 +364,165 @@ void LtePhyVUeMode4::handleSelfMessage(cMessage *msg) } else if (msg->isName("updateSubframe")) { - transmitting_ = false; - if (beginTransmission_){ - transmitting_ = true; - beginTransmission_ = false; + if (!initComplete_){ + initialiseSensingWindow(); + } else { + transmitting_ = false; + if (beginTransmission_) { + transmitting_ = true; + beginTransmission_ = false; + } + updateSubframe(); + if (cbrCountDown_ == 0) { + // Ensures we update CBR every 100ms + updateCBR(); + cbrCountDown_ = 99; + if (checkAwareness_) { + // Function allow to check IPG table to see if nodes have successfully decoded packets + // within a defined range in the last 1s/500ms/200ms + recordAwareness(); + } + } else { + cbrCountDown_--; + } } - updateSubframe(); - if (cbrCountDown_ == 0) { - // Ensures we update CBR every 100ms - updateCBR(); - cbrCountDown_ = 99; - if (checkAwareness_) { - // Function allow to check IPG table to see if nodes have successfully decoded packets - // within a defined range in the last 1s/500ms/200ms - recordAwareness(); + delete msg; + } + else if (msg->isName("oneShotTimer")) + { + // This is the sort of stuff required for sending the SCI before it is sent + // This information has to be made available to the SCI before sending it down. + + // Most likely at this point we will select the resource and generate MOST of the below + + // Then when transmission of the signal goes you select one of the frees send it up + // But you translate it first. + + oneShotSensing_ = false; + + int finalSubchannel = oneShotSubchannel_ + 1; + + // Determine the RBs on which we will send our message + RbMap grantedBlocks; + int totalGrantedBlocks = 0; + if (adjacencyPSCCHPSSCH_){ + // Adjacent mode just provide the allocated bands + + for (int i=oneShotSubchannel_;isetSourceId(nodeId_); + uinfo->setDestId(nodeId_); + uinfo->setFrameType(RESPKT); + uinfo->setTxNumber(1); + uinfo->setGrantedBlocks(grantedBlocks); + uinfo->setTotalGrantedBlocks(totalGrantedBlocks); + uinfo->setDirection(D2D_MULTI); + + // Subframe Index has to be translated correctly the subchannel is less of an issue. + int breakOut = 100; + int selectedSubframe = intuniform(1000 + oneShotT2_, 1100, 1); + while (oneShotCSRs_.find(selectedSubframe) == oneShotCSRs_.end() & breakOut > 0){ + selectedSubframe = intuniform(1000 + oneShotT2_ + 1, 1100, 1); + breakOut--; + } + + auto it = std::begin(oneShotCSRs_[selectedSubframe]); + // 'advance' the iterator n times + int n = intuniform(0, oneShotCSRs_[selectedSubframe].size() - 1, 1); + std::advance(it,n); + int selectedSubchannel = *it; + + int sensingWindowLength = pStep_ * 10; + if (sensingWindowSizeOverride_ > 0){ + sensingWindowLength = sensingWindowSizeOverride_; + } + + simtime_t elapsed_time = NOW.trunc(SIMTIME_MS) - oneShotStartTime_.trunc(SIMTIME_MS); + + int elapsed_ms = elapsed_time.dbl() * 1000; + + selectedSubframe = selectedSubframe - elapsed_ms - sensingWindowLength; + + sendOneShotMessage(uinfo, selectedSubframe - 1, selectedSubchannel); // -1 ensures the correct subframe logged i.e. account for trans time. + + beginTransmission_ = true; + + for (int i=0; isetSensed(false); } + + std::vector> orderedCSRs; + + orderedCSRs.push_back(std::make_tuple(-std::numeric_limits::infinity(), selectedSubframe, + selectedSubchannel, false)); + + // Send the packet up to the MAC layer where it will choose the CSR and the retransmission if that is specified + // Need to generate the message that is to be sent to the upper layers. + SpsCandidateResources* candidateResourcesMessage = new SpsCandidateResources("CSRs"); + candidateResourcesMessage->setCSRs(orderedCSRs); + send(candidateResourcesMessage, upperGateOut_); + + delete msg; + } + else if (msg->isName("csrTimer")) + { + csrSensing_ = false; + + int selectedSubframe = csrSubframe_; + int selectedSubchannel = csrSubchannel_; + + simtime_t elapsed_time = NOW.trunc(SIMTIME_MS) - csrStartTime_.trunc(SIMTIME_MS); + + int elapsed_ms = elapsed_time.dbl() * 1000; + + selectedSubframe = selectedSubframe - elapsed_ms; + + std::vector> orderedCSRs; + + orderedCSRs.push_back(std::make_tuple(-std::numeric_limits::infinity(), selectedSubframe, + selectedSubchannel, false)); + + // Send the packet up to the MAC layer where it will choose the CSR and the retransmission if that is specified + // Need to generate the message that is to be sent to the upper layers. + SpsCandidateResources* candidateResourcesMessage = new SpsCandidateResources("CSRs"); + candidateResourcesMessage->setCSRs(orderedCSRs); + send(candidateResourcesMessage, upperGateOut_); + delete msg; } + else if (msg->isName("CounterMessage")) + { + counterMechanism(); + } else LtePhyUe::handleSelfMessage(msg); } @@ -426,7 +596,11 @@ void LtePhyVUeMode4::handleUpperMessage(cMessage* msg) { // Generate CSRs or save the grant use when generating SCI information LteMode4SchedulingGrant* grant = check_and_cast(msg); - if (grant->getTotalGrantedBlocks() == 0){ + if (counterMechanism_){ + grant->setControlInfo(lteInfo); + sciGrant_ = grant; + } + else if (grant->getTotalGrantedBlocks() == 0){ // Generate a vector of CSRs and send it to the MAC layer if (randomScheduling_){ computeRandomCSRs(grant); @@ -434,6 +608,9 @@ void LtePhyVUeMode4::handleUpperMessage(cMessage* msg) computeCSRs(grant); } delete lteInfo; + if (!oneShotMechanism_){ + delete grant; + } } else { @@ -442,7 +619,9 @@ void LtePhyVUeMode4::handleUpperMessage(cMessage* msg) lteInfo->setGrantedBlocks(sciGrant_->getGrantedBlocks()); lteInfo->setTotalGrantedBlocks(sciGrant_->getTotalGrantedBlocks()); lteInfo->setDirection(D2D_MULTI); - if (!sciGrant_->getPeriodic()) { + if (oneShotMechanism_){ + lteInfo->setPeriodic(false); + } else if (!sciGrant_->getPeriodic()) { lteInfo->setPeriodic(false); } else { lteInfo->setPeriodic(true); @@ -461,31 +640,90 @@ void LtePhyVUeMode4::handleUpperMessage(cMessage* msg) frame = new LteAirFrame("harqFeedback-grant"); } - // if this is a multicast/broadcast connection, send the frame to all neighbors in the hearing range - // otherwise, send unicast to the destination + if (counterMechanism_){ + msg->setControlInfo(lteInfo); + counterMessage_ = msg; + counterMechanism(); + } else { + // if this is a multicast/broadcast connection, send the frame to all neighbors in the hearing range + // otherwise, send unicast to the destination - EV << "LtePhyVUeMode4::handleUpperMessage - " << nodeTypeToA(nodeType_) << " with id " << nodeId_ - << " sending message to the air channel. Dest=" << lteInfo->getDestId() << endl; + EV << "LtePhyVUeMode4::handleUpperMessage - " << nodeTypeToA(nodeType_) << " with id " << nodeId_ + << " sending message to the air channel. Dest=" << lteInfo->getDestId() << endl; - // Mark that we are in the process of transmitting a packet therefore when we go to decode messages we can mark as failure due to half duplex - beginTransmission_ = true; + // Mark that we are in the process of transmitting a packet therefore when we go to decode messages we can mark as failure due to half duplex + beginTransmission_ = true; - lteInfo->setGrantedBlocks(availableRBs_); + lteInfo->setGrantedBlocks(availableRBs_); + + if (oneShotMechanism_){ + lteInfo->setPeriodic(false); + } else if (sciGrant_->getPeriodic()) { + lteInfo->setPeriodic(true); + } else { + lteInfo->setPeriodic(false); + } + + frame = prepareAirFrame(msg, lteInfo); + + emit(tbSent, 1); - if (!sciGrant_->getPeriodic()) { - lteInfo->setPeriodic(false); - }else { - lteInfo->setPeriodic(true); + if (lteInfo->getDirection() == D2D_MULTI) + sendBroadcast(frame); + else + sendUnicast(frame); + + delete sciGrant_; } +} - frame = prepareAirFrame(msg, lteInfo); +void LtePhyVUeMode4::sendOneShotMessage(UserControlInfo* lteInfo, int subframe, int subchannelIndex) +{ + RbMap rbMap = lteInfo->getGrantedBlocks(); + UserControlInfo* SCIInfo = lteInfo->dup(); + LteAirFrame* frame = NULL; - emit(tbSent, 1); + lteInfo->setPeriodic(false); - if (lteInfo->getDirection() == D2D_MULTI) - sendBroadcast(frame); - else - sendUnicast(frame); + // Store the RBs used for transmission. For interference computation + UsedRBs info; + info.time_ = NOW; + info.rbMap_ = rbMap; // We are only using these in this situation + + usedRbs_.push_back(info); + + std::vector::iterator it = usedRbs_.begin(); + while (it != usedRbs_.end()) // purge old allocations + { + if (it->time_ < NOW) + usedRbs_.erase(it++); + else + ++it; + } + lastActive_ = NOW; + + SCIInfo->setFrameType(RESPKT); + SCIInfo->setGrantedBlocks(rbMap); + SCIInfo->setTotalGrantedBlocks(lteInfo->getTotalGrantedBlocks()); + + /* + * Need to prepare the airframe were sending + * Ensure that it will fit into it's grant + * if not don't send anything except a break reservation message + */ + EV << NOW << " LtePhyVUeMode4::handleUpperMessage - message from stack" << endl; + + // create LteAirFrame and encapsulate the received packet + SidelinkControlInformation* SCI = createOneShotSCIMessage(subframe, subchannelIndex); + + LteAirFrame* sciFrame = prepareAirFrame(SCI, SCIInfo); + + emit(sciSent, 1); + emit(subchannelSent, subchannelIndex); + emit(subchannelsUsedToSend, 1); + sendBroadcast(sciFrame); + + delete lteInfo; } RbMap LtePhyVUeMode4::sendSciMessage(cMessage* msg, UserControlInfo* lteInfo) @@ -588,7 +826,6 @@ RbMap LtePhyVUeMode4::sendSciMessage(cMessage* msg, UserControlInfo* lteInfo) emit(subchannelsUsedToSend, sciGrant_->getNumSubchannels()); sendBroadcast(sciFrame); - delete sciGrant_; delete lteInfo; return (rbMap); @@ -778,7 +1015,7 @@ void LtePhyVUeMode4::computeCSRs(LteMode4SchedulingGrant* &grant) { for (int q = 1; q <= Q; q++) { - for (int j = 1; j <= cResel + 1; j++) { + for (int j = 1; j <= cResel; j++) { int disallowedSubframe = (z + (j * pRsvpTxPrime)) - (pStep_ * q * (*k)); // Only mark as disallowed if it corresponds with a frame in the selection window if (disallowedSubframe >= minSelectionIndex && disallowedSubframe <= maxSelectionIndex) { @@ -814,7 +1051,7 @@ void LtePhyVUeMode4::computeCSRs(LteMode4SchedulingGrant* &grant) { // It's possible that a grant might span multiple subchannels, if this is the case then check all for // An SCI and record the information for each independently for the later calculation - std::vector averageRSRPs; + std::vector RSRPs; std::vector priorities; std::vector rris; @@ -842,22 +1079,58 @@ void LtePhyVUeMode4::computeCSRs(LteMode4SchedulingGrant* &grant) { rris.push_back(rri); } double totalRSRPLinear = 0; - // Specifically the average should be for the part of the subchannel we will end up using - for (int l = j; l < j + grantLength; l++) { - if (sensingWindow_[translatedZ][l]->getAverageRSRP() != - -std::numeric_limits::infinity()) { - totalRSRPLinear += dBmToLinear(sensingWindow_[translatedZ][l]->getAverageRSRP()); + + if (mode2RSRP_) { + // Specifically the average should be for the part of the subchannel we will end up using + for (int l = j; l < j + grantLength; l++) { + if (sensingWindow_[translatedZ][l]->getAverageRSRP() != + -std::numeric_limits::infinity()) { + totalRSRPLinear += dBmToLinear( + sensingWindow_[translatedZ][l]->getAverageRSRP()); + } + } + if (totalRSRPLinear != 0) { + subchannelUsed = true; + RSRPs.push_back(linearToDBm(totalRSRPLinear / grantLength)); + } + } else { + int subchannelsUsed = 0; + int searchRRI = 0; + while (searchRRI < sensingWindow_.size()){ + for (int l = j; l < j + grantLength; l++) { + int historicalZ = translateIndex(sensingWindowLength - z - searchRRI); + if (historicalZ >= 1000) { + break; + } + double subchannelRSRP = sensingWindow_[historicalZ][l]->getAverageRSRP(); + if (subchannelRSRP != -std::numeric_limits::infinity()) { + totalRSRPLinear += dBmToLinear(subchannelRSRP); + } + } + searchRRI += rri * 100; + subchannelsUsed += grantLength; + } + if (totalRSRPLinear != 0) { + subchannelUsed = true; + RSRPs.push_back(linearToDBm(totalRSRPLinear / subchannelsUsed)); } - } - if (totalRSRPLinear != 0) { - subchannelUsed = true; - averageRSRPs.push_back(linearToDBm(totalRSRPLinear / grantLength)); } k += grantLength; + } else if (sensingWindow_[translatedZ][k]->getTimeGapRetrans() > 0){ + int oneShotSubframe = sensingWindow_[translatedZ][k]->getTimeGapRetrans() + z; + if (oneShotSubframe > 1000){ + // we have a future resource which is reserved and needs to be removed from the possible CSRs + int oneShotSubchannel = sensingWindow_[translatedZ][k]->getOneShotSubchannelIndex(); + possibleCSRs[oneShotSubframe].erase(oneShotSubchannel); + if (possibleCSRs[oneShotSubframe].size() == 0){ + // If the subframe is now empty then erase it also. + possibleCSRs.erase(oneShotSubframe); + } + } } } - // Increment K to the next subchannel - k++; + // Increment K to the next subchannel + k++; } if (subchannelReserved && subchannelUsed) { subchannelReserved = false; @@ -868,8 +1141,8 @@ void LtePhyVUeMode4::computeCSRs(LteMode4SchedulingGrant* &grant) { // Get the priorities of both messages int messagePriority = grant->getSpsPriority(); - for (int l = 0; l < averageRSRPs.size(); l++) { - double averageRSRP = averageRSRPs[l]; + for (int l = 0; l < RSRPs.size(); l++) { + double RSRP = RSRPs[l]; int receivedPriority = priorities[l]; double receivedRri = rris[l]; @@ -878,11 +1151,11 @@ void LtePhyVUeMode4::computeCSRs(LteMode4SchedulingGrant* &grant) { int threshold = ThresPSSCHRSRPvector_[index]; int thresholdDbm = (-128 + (threshold - 1) * 2); - if (averageRSRP > thresholdDbm) { + if (RSRP > thresholdDbm) { // Must determine the number of increases required to make this a CSR. int thresholdIncreaseFactor = 1; thresholdBreach = true; - while (averageRSRP > thresholdDbm) { + while (RSRP > thresholdDbm) { thresholdDbm += 3; ++thresholdIncreaseFactor; } @@ -1011,6 +1284,40 @@ void LtePhyVUeMode4::computeCSRs(LteMode4SchedulingGrant* &grant) { optimalCSRs = selectBestRSSIs(possibleCSRs, grant, totalPossibleCSRs, reservedCSRs); } else if (rsrpFiltering_) { optimalCSRs = selectBestRSRPs(possibleCSRs, grant, totalPossibleCSRs, reservedCSRs); + } else if (oneShotMechanism_) { + + oneShotCSRs_ = possibleCSRs; + + int breakOut = 100; + int selectedSubframe = intuniform(1002, 1000 + oneShotT2_, 1); + while (oneShotCSRs_.find(selectedSubframe) == oneShotCSRs_.end() & breakOut > 0){ + selectedSubframe = intuniform(1002, 1000 + oneShotT2_, 1); + breakOut--; + } + + auto it = std::begin(oneShotCSRs_[selectedSubframe]); + // 'advance' the iterator n times + int n = intuniform(0, oneShotCSRs_[selectedSubframe].size() - 1, 1); + std::advance(it,n); + int selectedSubchannel = *it; + + simtime_t selectedStartTime = (simTime().trunc(SIMTIME_MS) + SimTime(selectedSubframe - sensingWindowLength -1, SIMTIME_MS)).trunc(SIMTIME_MS); + + oneShotSubchannel_ = selectedSubchannel; + + sciGrant_ = grant; + + sendOneShotSignal_ = new cMessage("oneShotTimer"); + sendOneShotSignal_->setSchedulingPriority(1); // Generate the subframe at start of next TTI + scheduleAt(selectedStartTime, sendOneShotSignal_); + + oneShotSignalTime_ = selectedStartTime; + + oneShotStartTime_ = NOW.trunc(SIMTIME_MS); + + oneShotSensing_ = true; + + return; } else { // Simply convert the possible CSRs to the correct format and shuffle them and return 20% of them as normal. std::vector > orderedCSRs; @@ -1050,10 +1357,39 @@ void LtePhyVUeMode4::computeCSRs(LteMode4SchedulingGrant* &grant) { optimalCSRs = orderedCSRs; } + if (oneShotMechanism_){ + // Select random element from vector + int index = intuniform(0, optimalCSRs.size()-1, 1); + + std::tuple selectedCR = optimalCSRs[index]; + // Gives us the time at which we will send the subframe. + simtime_t selectedStartTime = (simTime() + SimTime(std::get<1>(selectedCR), SIMTIME_MS) - (TTI * 2)).trunc(SIMTIME_MS); + + csrSubframe_ = std::get<1>(selectedCR); + csrSubchannel_ = std::get<2>(selectedCR); + + sciGrant_ = grant; + + csrSignal_ = new cMessage("csrTimer"); + csrSignal_->setSchedulingPriority(1); // Generate the subframe at start of next TTI + scheduleAt(selectedStartTime, csrSignal_); + + csrSignalTime_ = selectedStartTime; + + csrStartTime_ = NOW.trunc(SIMTIME_MS); + + csrSensing_ = true; + + nonOneShotCSRs_ = optimalCSRs; + + return; + } + // Send the packet up to the MAC layer where it will choose the CSR and the retransmission if that is specified // Need to generate the message that is to be sent to the upper layers. SpsCandidateResources* candidateResourcesMessage = new SpsCandidateResources("CSRs"); candidateResourcesMessage->setCSRs(optimalCSRs); + candidateResourcesMessage->setApplicationId(grant->getApplicationId()); send(candidateResourcesMessage, upperGateOut_); } @@ -1375,6 +1711,100 @@ SidelinkControlInformation* LtePhyVUeMode4::createSCIMessage() return sci; } +SidelinkControlInformation* LtePhyVUeMode4::createOneShotSCIMessage(int subframe, int subchannelIndex) +{ + EV << NOW << " LtePhyVUeMode4::createOneShotSCIMessage - Start creating SCI..." << endl; + + SidelinkControlInformation* sci = new SidelinkControlInformation("SCI Message"); + + /* + * Priority (based on upper layer) + * 0-7 + * Mapping unknown, so possibly just take the priority max and min and map to 0-7 + * This needs to be integrated from the application layer. + * Will take this from the scheduling grant. + */ + sci->setPriority(sciGrant_->getSpsPriority()); + + /* Resource Interval + * + * 0 -> 16 + * 0 = not reserved + * 1 = 100ms (1) RRI [Default] + * 2 = 200ms (2) RRI + * ... + * 10 = 1000ms (10) RRI + * 11 = 50ms (0.5) RRI + * 12 = 20ms (0.2) RRI + * 13 - 15 = Reserved + * + */ + + // This is always 0 for one shot as they don't maintain the grant at all. + sci->setResourceReservationInterval(0); + + /* frequency Resource Location + * Based on another parameter RIV + * but size is + * Log2(Nsubchannel(Nsubchannel+1)/2) (rounded up) + * 0 - 8 bits + * 0 - 256 different values + * + * Based on TS36.213 14.1.1.4C + * if SubchannelLength -1 < numSubchannels/2 + * RIV = numSubchannels(SubchannelLength-1) + subchannelIndex + * else + * RIV = numSubchannels(numSubchannels-SubchannelLength+1) + (numSubchannels-1-subchannelIndex) + */ + unsigned int riv; + // + if (sciGrant_->getNumSubchannels() -1 <= (numSubchannels_/2)) + { + // RIV calculation for less than half+1 + riv = ((numSubchannels_ * (sciGrant_->getNumSubchannels() - 1)) + oneShotSubchannel_); + } + else + { + // RIV calculation for more than half size + riv = ((numSubchannels_ * (numSubchannels_ - sciGrant_->getNumSubchannels() + 1)) + (numSubchannels_ - 1 - sciGrant_->getStartingSubchannel())); + } + + sci->setFrequencyResourceLocation(riv); + + /* TimeGapRetrans + * 1 - 15 + * ms from init to retrans + */ + + // So this is where we need to add the proper time gap between now and the future transmission this is where most logic will be + sci->setTimeGapRetrans(subframe); + + + /* mcs + * 5 bits + * 26 combos + * Technically the MAC layer determines the MCS that it wants the message sent with and as such it will be in the packet + */ + sci->setMcs(sciGrant_->getMcs()); + + /* retransmissionIndex + * 0 / 1 + * if 0 retrans is in future/this is the first transmission + * if 1 retrans is in the past/this is the retrans + */ + sci->setRetransmissionIndex(0); + + // Put in the number of the selected subchannel to send on. + sci->setOneShotLocation(subchannelIndex); + + /* Filler up to 32 bits + * Can just set the length to 32 bits and ignore the issue of adding filler + */ + sci->setBitLength(32); + + return sci; +} + LteAirFrame* LtePhyVUeMode4::prepareAirFrame(cMessage* msg, UserControlInfo* lteInfo){ // Helper function to prepare airframe for sending. LteAirFrame* frame = new LteAirFrame("airframe"); @@ -1430,7 +1860,7 @@ void LtePhyVUeMode4::storeAirFrame(LteAirFrame* newFrame) avgSinr = avgSinr / countAssignedRbs; // Need to be able to figure out which subchannel is associated to the Rbs in this case - if (newInfo->getFrameType() == SCIPKT){ + if (newInfo->getFrameType() == SCIPKT || newInfo->getFrameType() == RESPKT){ sciInfo_.push_back(std::make_tuple(newFrame, rsrpVector, rssiVector, sinrVector, attenuation, avgSinr)); } else{ tbInfo_.push_back(std::make_tuple(newFrame, rsrpVector, rssiVector, sinrVector, attenuation, avgSinr)); @@ -1447,7 +1877,264 @@ void LtePhyVUeMode4::decodeAirFrame(LteAirFrame* frame, UserControlInfo* lteInfo cPacket* pkt = frame->decapsulate(); - if(lteInfo->getFrameType() == SCIPKT) + if(lteInfo->getFrameType() == RESPKT) + { + double pkt_dist = getCoord().distance(lteInfo->getCoord()); + emit(txRxDistanceSCI, pkt_dist); + oneShot_ = 1; + + SidelinkControlInformation *sci = check_and_cast(pkt); + std::tuple indexAndLength = decodeRivValue(sci, lteInfo); + int subchannelIndex = std::get<0>(indexAndLength); + int lengthInSubchannels = std::get<1>(indexAndLength); + + subchannelReceived_ = subchannelIndex; + subchannelsUsed_ = lengthInSubchannels; + emit(senderID, lteInfo->getSourceId()); + + if (!transmitting_) + { + + sciReceived_ += 1; + + bool notSensed = false; + double erfParam = (lteInfo->getD2dTxPower() - attenuation - -90.5) / (3 * sqrt(2)); + double erfValue = erf(erfParam); + double packetSensingRatio = 0.5 * (1 + erfValue); + double er = dblrand(1); + + if (er >= packetSensingRatio){ + // Packet was not sensed so mark as such and delete it. + lteInfo->setDeciderResult(false); + sciUnsensed_ += 1; + } else { + std::tuple res = channelModel_->error_Mode4(frame, lteInfo, rsrpVector, sinrVector, 0); + prop_result = get<0>(res); + interference_result = get<1>(res); + + RbMap::iterator mt; + std::map::iterator nt; + RbMap usedRbs = lteInfo->getGrantedBlocks(); + std::vector < Subchannel * > currentSubframe = sensingWindow_[sensingWindowFront_]; + Subchannel *currentSubchannel = currentSubframe[subchannelIndex]; + std::vector::iterator lt; + std::vector allocatedBands = currentSubchannel->getOccupiedBands(); + for (lt = allocatedBands.begin(); lt != allocatedBands.end(); lt++) { + // Record RSRP and RSSI for this band depending if it was used or not + bool used = false; + + //for each Remote unit used to transmit the packet + for (mt = usedRbs.begin(); mt != usedRbs.end(); ++mt) { + //for each logical band used to transmit the packet + for (nt = mt->second.begin(); nt != mt->second.end(); ++nt) { + if (nt->first == *lt) { + currentSubchannel->addRsrpValue(rsrpVector[(*lt)], (*lt)); + currentSubchannel->addRssiValue(rssiVector[(*lt)], (*lt)); + used = true; + break; + } + } + } + } + + // Need to ensure that we haven't previously decoded a higher SINR packet. + if (interference_result & !sensingWindow_[sensingWindowFront_][subchannelIndex]->getReserved()) { + for (int i = subchannelIndex; i < subchannelIndex + lengthInSubchannels; i++) { + Subchannel *currentSubchannel = currentSubframe[i]; + // Record the SCI info in the subchannel. + currentSubchannel->setPriority(sci->getPriority()); + currentSubchannel->setResourceReservationInterval(sci->getResourceReservationInterval()); + currentSubchannel->setFrequencyResourceLocation(sci->getFrequencyResourceLocation()); + currentSubchannel->setTimeGapRetrans(sci->getTimeGapRetrans()); + currentSubchannel->setMcs(sci->getMcs()); + currentSubchannel->setRetransmissionIndex(sci->getRetransmissionIndex()); + currentSubchannel->setSciSubchannelIndex(subchannelIndex); + currentSubchannel->setSciLength(lengthInSubchannels); + currentSubchannel->setOneShotSubchannelIndex(sci->getOneShotLocation()); + currentSubchannel->setReserved(true); + + if (csrSensing_){ + if (sci->getTimeGapRetrans() > 0) { + // We need to get this and look at subchannels in T2->T3 which overlap + int subframe_in_future = sci->getTimeGapRetrans(); + int subchannel_in_future = sci->getOneShotLocation(); + + double ttis_in_future = sci->getTimeGapRetrans(); + ttis_in_future = (ttis_in_future-1) * TTI; + simtime_t reservationTime = (NOW + ttis_in_future).trunc(SIMTIME_MS); + if (reservationTime == csrSignalTime_ && + subchannel_in_future == csrSubchannel_) { + // Need to defer or decide on having the collision if this is the last subchannel + // and subframe in the selection window then send, otherwise defer + int breakOut = 100; + + // emit csr Rescheduled. + + + simtime_t elapsed_time = + NOW.trunc(SIMTIME_MS) - csrStartTime_.trunc(SIMTIME_MS); + + int elapsed_ms = elapsed_time.dbl() * 1000; + + // If no other possible resource then simply maintain the default + int selectedSubframe = csrSubframe_; + int selectedSubchannel = csrSubchannel_; + + if (elapsed_ms < 100) { // Assume selection window of 100ms + // Can defer this transmission + + std::vector>::iterator csrIt; + for (csrIt=nonOneShotCSRs_.begin(); csrIt < nonOneShotCSRs_.end(); csrIt++){ + simtime_t selectedStartTime = (csrStartTime_ + SimTime(std::get<1>(*csrIt), SIMTIME_MS) - (TTI * 2)).trunc(SIMTIME_MS); + if (selectedStartTime > (simTime() + (TTI * 2))) { + selectedSubframe = std::get<1>(*csrIt); + selectedSubchannel = std::get<2>(*csrIt); + break; + } + } + simtime_t selectedStartTime = (csrStartTime_.trunc(SIMTIME_MS) + + SimTime(selectedSubframe -2, + SIMTIME_MS)).trunc(SIMTIME_MS); + + csrSubframe_ = selectedSubframe; + csrSubchannel_ = selectedSubchannel; + + cancelEvent(csrSignal_); // Cancel the previous signal + + emit(csrReschedule, 1); + + csrSignal_ = new cMessage("csrTimer"); + csrSignal_->setSchedulingPriority( + 1); // Generate the subframe at start of next TTI + scheduleAt(selectedStartTime, csrSignal_); + + csrSignalTime_ = selectedStartTime; + + csrSensing_ = true; + } + } else { + // Remove from list if it appears in the list v rare + + simtime_t elapsed_time = NOW.trunc(SIMTIME_MS) - csrStartTime_.trunc(SIMTIME_MS); + int elapsed_ms = elapsed_time.dbl() * 1000; + + std::vector>::iterator csrIt; + for (csrIt=nonOneShotCSRs_.begin(); csrIt < nonOneShotCSRs_.end(); csrIt++){ + if ((subframe_in_future == std::get<1>(*csrIt) - elapsed_ms) & + (subchannel_in_future == std::get<2>(*csrIt))){ + nonOneShotCSRs_.erase(csrIt); + break; + } + } + } + } + } + + if (oneShotSensing_) { + if (sci->getTimeGapRetrans() > 0) { + // We need to get this and look at subchannels in T2->T3 which overlap + int subframe_in_future = sci->getTimeGapRetrans(); + + double ttis_in_future = sci->getTimeGapRetrans(); + ttis_in_future = (ttis_in_future-1) * TTI; + // setFrequencyResourceLocation will determine the subchannel which will be used for + // future transmissions. + int subchannel_in_future = sci->getOneShotLocation(); + + simtime_t reservationTime = (NOW + ttis_in_future).trunc(SIMTIME_MS); + + if (reservationTime == oneShotSignalTime_ && + subchannel_in_future == oneShotSubchannel_) { + // Need to defer or decide on having the collision if this is the last subchannel and subframe in t1t2 then send + // otherwise defer + int breakOut = 100; + + simtime_t elapsed_time = NOW.trunc(SIMTIME_MS) - oneShotStartTime_.trunc(SIMTIME_MS); + + int elapsed_ms = elapsed_time.dbl() * 1000; + + elapsed_ms = elapsed_ms + 1000; + + if (elapsed_ms < 1000 + oneShotT2_) { + // Can defer this transmission + + int selectedSubframe = intuniform(elapsed_ms + 2, 1000 + oneShotT2_, 1); + while (oneShotCSRs_.find(selectedSubframe) == oneShotCSRs_.end() & + breakOut > 0) { + selectedSubframe = intuniform(elapsed_ms + 2, 1000 + oneShotT2_, 1); + breakOut--; + } + + auto it = std::begin(oneShotCSRs_[selectedSubframe]); + // 'advance' the iterator n times + int n = intuniform(0, oneShotCSRs_[selectedSubframe].size() - 1, 1); + std::advance(it, n); + int selectedSubchannel = *it; + + int sensingWindowLength = pStep_ * 10; + if (sensingWindowSizeOverride_ > 0) { + sensingWindowLength = sensingWindowSizeOverride_; + } + + simtime_t selectedStartTime = (oneShotStartTime_.trunc(SIMTIME_MS) + SimTime(selectedSubframe - sensingWindowLength - 1, SIMTIME_MS)).trunc(SIMTIME_MS); + + oneShotSubchannel_ = selectedSubchannel; + + cancelEvent(sendOneShotSignal_); // Cancel the previous signal + + sendOneShotSignal_ = new cMessage("oneShotTimer"); + sendOneShotSignal_->setSchedulingPriority(1); // Generate the subframe at start of next TTI + scheduleAt(selectedStartTime, sendOneShotSignal_); + + oneShotSignalTime_ = selectedStartTime; + + oneShotSensing_ = true; + } + } else { + + simtime_t elapsed_time = NOW.trunc(SIMTIME_MS) - oneShotStartTime_.trunc(SIMTIME_MS); + + int elapsed_ms = elapsed_time.dbl() * 1000; + + int subframe = elapsed_ms + subframe_in_future + 1000; + + if (subframe < 1100) { + // Erase the subchannel + oneShotCSRs_[subframe].erase(subchannel_in_future); + + if (oneShotCSRs_[subframe].size() == 0) { + // If the subframe is now empty then erase it also. + oneShotCSRs_.erase(subframe); + } + } + } + } + } + } + lteInfo->setDeciderResult(true); + sciDecoded_ += 1; + } else if (!prop_result) { + lteInfo->setDeciderResult(false); + sciFailedDueToProp_ += 1; + } else { + lteInfo->setDeciderResult(false); + interference_result = false; + sciFailedDueToInterference_ += 1; + } + } + // No longer need the packet can delete it. + delete lteInfo; + delete pkt; + } + else + { + sciFailedHalfDuplex_ += 1; + delete lteInfo; + delete pkt; + } + delete frame; + } + else if(lteInfo->getFrameType() == SCIPKT) { double pkt_dist = getCoord().distance(lteInfo->getCoord()); emit(txRxDistanceSCI, pkt_dist); @@ -1465,6 +2152,7 @@ void LtePhyVUeMode4::decodeAirFrame(LteAirFrame* frame, UserControlInfo* lteInfo { sciReceived_ += 1; + oneShot_ = 0; bool notSensed = false; double erfParam = (lteInfo->getD2dTxPower() - attenuation - -90.5) / (3 * sqrt(2)); @@ -1682,6 +2370,160 @@ void LtePhyVUeMode4::decodeAirFrame(LteAirFrame* frame, UserControlInfo* lteInfo << (interference_result ? "RECEIVED" : "NOT RECEIVED") << endl; } +void LtePhyVUeMode4::counterMechanism() +{ + // If not started counter + // Setup counter 0,CW-1 + if (currentCounter_ == -1 & !counterTriggered_){ + // Have not setup the counter so time to do so + currentCounter_ = intuniform(1, counterMax_-1, 2); + counterTriggered_ = true; + + cMessage* updateSubframe = new cMessage("CounterMessage"); + updateSubframe->setSchedulingPriority(1); // Check the last subframe at start of the subframe + scheduleAt(NOW + TTI, updateSubframe); + } else { + // Else + // Check the last subframe and determine Num subchannels RSRP/RSSI > threshold (use CBR calc for this) + // Counter -= numFree subchannels + + int lastSubframe = 0; + if (sensingWindowFront_ > 0){ + lastSubframe = sensingWindowFront_ - 1; + } else { + lastSubframe = (pStep_ * 10) - 1; + if (sensingWindowSizeOverride_ > 0){ + lastSubframe = sensingWindowSizeOverride_ - 1; + } + } + int freeCount = 0; + std::vector currentSubframe = sensingWindow_[lastSubframe]; + for (int i = 0; i < currentSubframe.size(); i++) { + if (currentSubframe[i]->getSensed()) { + if (currentSubframe[i]->getAverageRSSI() < thresholdRSSI_) { + freeCount++; + } + } + } + + currentCounter_ -= freeCount; + + if (currentCounter_ <= 0) { + // If counter == 0 + // Select a free subchannel (technically based on the usual SPS mechanism but for now just pick @ random as purely + // aperiodic not mixed + int previousSubframe = (sensingWindowFront_ + 1) - (pStep_); + if (previousSubframe < 0){ + // If we are negative we know we must wrap around + previousSubframe = (pStep_ * 10) + previousSubframe; + } + + std::vector possibleSubchannels; + std::vector currentSubframe = sensingWindow_[previousSubframe]; + for (int i = 0; i < currentSubframe.size(); i++) { + if (currentSubframe[i]->getSensed()) { + if (!currentSubframe[i]->getReserved()){ + // If we sensed and know the subchannel is unreserved then it can be selected + possibleSubchannels.push_back(i); + } + } + } + + if (possibleSubchannels.size() > 0) { + auto it = std::begin(possibleSubchannels); + // 'advance' the iterator n times + int n = intuniform(0, possibleSubchannels.size() - 1, 1); + std::advance(it,n); + int selectedSubchannel = *it; + + counterMechanismSend(selectedSubchannel); + + currentCounter_ = -1; + counterTriggered_ = false; + return; + } + } + cMessage* updateSubframe = new cMessage("CounterMessage"); + updateSubframe->setSchedulingPriority(1); // Check the last subframe at start of the subframe + scheduleAt(NOW + TTI, updateSubframe); + } +} + +void LtePhyVUeMode4::counterMechanismSend(int initialSubchannel) +{ + // About to transmit so make sure that we mark this as a transmission + beginTransmission_ = true; + + cMessage* msg = counterMessage_; + + UserControlInfo* lteInfo = check_and_cast(msg->removeControlInfo()); + UserControlInfo* sciInfo = check_and_cast(sciGrant_->removeControlInfo()); + + LteAirFrame* frame; + + // So at this point we know we have to send and we need to setup the correct resources for sending + // Determine the RBs on which we will send our message + RbMap grantedBlocks; + int totalGrantedBlocks = 0; + + int finalSubchannel = initialSubchannel + sciGrant_->getNumSubchannels(); + if (adjacencyPSCCHPSSCH_){ + // Adjacent mode just provide the allocated bands + + for (int i=initialSubchannel;igetNumSubchannels()) ; b++) { + grantedBlocks[MACRO][b] = 1; + ++totalGrantedBlocks; + } + } + + // We got to the counter mechanism which is good + sciInfo->setGrantedBlocks(grantedBlocks); + sciInfo->setTotalGrantedBlocks(totalGrantedBlocks); + sciInfo->setDirection(D2D_MULTI); + sciInfo->setPeriodic(false); + availableRBs_ = sendSciMessage(msg, sciInfo); + for (int i=0; isetSensed(false); + } + + lteInfo->setGrantedBlocks(availableRBs_); + lteInfo->setPeriodic(false); + + frame = prepareAirFrame(msg, lteInfo); + + emit(tbSent, 1); + + if (lteInfo->getDirection() == D2D_MULTI) + sendBroadcast(frame); + else + sendUnicast(frame); + + counterMessage_ = NULL; + sciGrant_ = NULL; +} + std::tuple LtePhyVUeMode4::decodeRivValue(SidelinkControlInformation* sci, UserControlInfo* sciInfo) { EV << NOW << " LtePhyVUeMode4::decodeRivValue - Decoding RIV value of SCI allows correct placement in sensing window..." << endl; @@ -1792,6 +2634,7 @@ void LtePhyVUeMode4::updateCBR() Cbr* cbrPkt = new Cbr("CBR"); cbrPkt->setCbr(cbrValue); + cbrPkt->setCr(0.0); // Will be filled in MAC layer send(cbrPkt, upperGateOut_); } @@ -1911,6 +2754,8 @@ void LtePhyVUeMode4::initialiseSensingWindow() { EV << NOW << " LtePhyVUeMode4::initialiseSensingWindow - creating subframes to be added to sensingWindow..." << endl; + initComplete_ = true; + simtime_t subframeTime = NOW - TTI; int sensingWindowLength = pStep_ * 10; diff --git a/src/stack/phy/layer/LtePhyVUeMode4.h b/src/stack/phy/layer/LtePhyVUeMode4.h index 8ec3fab0..733f44d0 100644 --- a/src/stack/phy/layer/LtePhyVUeMode4.h +++ b/src/stack/phy/layer/LtePhyVUeMode4.h @@ -36,10 +36,39 @@ class LtePhyVUeMode4 : public LtePhyUeD2D bool transmitting_; bool beginTransmission_; bool randomScheduling_; + bool oneShotMechanism_; + bool oneShotSensing_; + bool csrSensing_; bool checkAwareness_; + bool initComplete_; + simtime_t delayStartUp_; + int maxX_; + int minX_; + + std::unordered_map> oneShotCSRs_; + std::vector> nonOneShotCSRs_; + + int oneShotT2_; + int oneShotT3_; + int oneShotSubchannel_; + simtime_t oneShotSignalTime_; + simtime_t oneShotStartTime_; + cMessage* sendOneShotSignal_; + + int csrSubchannel_; + int csrSubframe_; + simtime_t csrSignalTime_; + simtime_t csrStartTime_; + cMessage* csrSignal_; bool rssiFiltering_; bool rsrpFiltering_; + bool mode2RSRP_; + bool counterMechanism_; + int counterMax_; + int currentCounter_; + bool counterTriggered_; + cMessage* counterMessage_; std::map previousTransmissionTimes_; @@ -62,6 +91,7 @@ class LtePhyVUeMode4 : public LtePhyUeD2D simsignal_t sciReceived; simsignal_t sciDecoded; + simsignal_t oneShot; simsignal_t csrReschedule; simsignal_t sciFailedHalfDuplex; @@ -78,6 +108,8 @@ class LtePhyVUeMode4 : public LtePhyUeD2D int sciFailedDueToProp_; int sciFailedDueToInterference_; int sciUnsensed_; + int oneShot_; + // Tb Stats simsignal_t tbSent; @@ -160,6 +192,10 @@ class LtePhyVUeMode4 : public LtePhyUeD2D virtual RbMap sendSciMessage(cMessage* sci, UserControlInfo* lteInfo); + virtual SidelinkControlInformation* createOneShotSCIMessage(int subframe, int subchannelIndex); + + virtual void sendOneShotMessage(UserControlInfo* lteInfo, int subframe, int subchannelIndex); + // Compute Candidate Single Subframe Resources which the MAC layer can use for transmission virtual void computeCSRs(LteMode4SchedulingGrant* &grant); @@ -185,6 +221,10 @@ class LtePhyVUeMode4 : public LtePhyUeD2D virtual int translateIndex(int index); + virtual void counterMechanism(); + + virtual void counterMechanismSend(int initialSubchannel); + public: LtePhyVUeMode4(); virtual ~LtePhyVUeMode4(); diff --git a/src/stack/phy/packet/SpsCandidateResources.msg b/src/stack/phy/packet/SpsCandidateResources.msg index 7d58d1f6..39b9fe78 100644 --- a/src/stack/phy/packet/SpsCandidateResources.msg +++ b/src/stack/phy/packet/SpsCandidateResources.msg @@ -18,4 +18,5 @@ // packet SpsCandidateResources { @customize(true); + int applicationId; } diff --git a/src/stack/phy/packet/cbr.msg b/src/stack/phy/packet/cbr.msg index 39d7076d..29a741fc 100644 --- a/src/stack/phy/packet/cbr.msg +++ b/src/stack/phy/packet/cbr.msg @@ -17,5 +17,6 @@ // TODO generated message class // packet Cbr { + double cr; double cbr; } diff --git a/src/world/radio/ChannelAccess.cc b/src/world/radio/ChannelAccess.cc index edcff236..19d31b4e 100644 --- a/src/world/radio/ChannelAccess.cc +++ b/src/world/radio/ChannelAccess.cc @@ -70,21 +70,11 @@ void ChannelAccess::initialize(int stage) { if (!positionUpdateArrived && hostModule->isSubscribed(inet::IMobility::mobilityStateChangedSignal, this)) { - // ...else, get the initial position from the display string - radioPos.x = parseInt(hostModule->getDisplayString().getTagArg("p", 0), -1); - radioPos.y = parseInt(hostModule->getDisplayString().getTagArg("p", 1), -1); + cModule* mobilityModule = hostModule->getSubmodule("mobility"); - if (radioPos.x == -1 || radioPos.y == -1) - error("The coordinates of '%s' host are invalid. Please set coordinates in " - "'@display' attribute, or configure Mobility for this host.", - hostModule->getFullPath().c_str()); - - const char *s = hostModule->getDisplayString().getTagArg("p", 2); - if (s && *s) - error("The coordinates of '%s' host are invalid. Please remove automatic arrangement" - " (3rd argument of 'p' tag)" - " from '@display' attribute, or configure Mobility for this host.", - hostModule->getFullPath().c_str()); + radioPos.x = mobilityModule->par("initialX").doubleValue(); + radioPos.y = mobilityModule->par("initialY").doubleValue(); + radioPos.z = mobilityModule->par("initialZ").doubleValue(); } myRadioRef = cc->registerRadio(this); cc->setRadioPosition(myRadioRef, radioPos);