bool RadioInterface::driveReceiveRadio() { radioVector *burst = NULL; if (!mOn) return false; pullBuffer(); GSM::Time rcvClock = mClock.get(); rcvClock.decTN(receiveOffset); unsigned tN = rcvClock.TN(); int recvSz = recvBuffer[0]->getAvailSamples(); const int symbolsPerSlot = gSlotLen + 8; int burstSize; if (mSPSRx == 4) burstSize = 625; else burstSize = symbolsPerSlot + (tN % 4 == 0); /* * Pre-allocate head room for the largest correlation size * so we can later avoid a re-allocation and copy * */ size_t head = GSM::gRACHSynchSequence.size(); /* * Form receive bursts and pass up to transceiver. Use repeating * pattern of 157-156-156-156 symbols per timeslot */ while (recvSz > burstSize) { for (size_t i = 0; i < mChans; i++) { burst = new radioVector(rcvClock, burstSize, head, mMIMO); for (size_t n = 0; n < mMIMO; n++) unRadioifyVector(burst->getVector(n), i); if (mReceiveFIFO[i].size() < 32) mReceiveFIFO[i].write(burst); else delete burst; } mClock.incTN(); rcvClock.incTN(); recvSz -= burstSize; tN = rcvClock.TN(); if (mSPSRx != 4) burstSize = (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx; } return true; }
double Clock::systime(const GSM::Time& when) const { ScopedLock lock(mLock); const double slotMicroseconds = (48.0 / 13e6) * 156.25; const double frameMicroseconds = slotMicroseconds * 8.0; int32_t elapsedFrames = when.FN() - mBaseFN; if (elapsedFrames<0) elapsedFrames += gHyperframe; double elapsedUSec = elapsedFrames * frameMicroseconds + when.TN() * slotMicroseconds; double baseSeconds = mBaseTime.sec() + mBaseTime.usec()*1e-6; double st = baseSeconds + 1e-6*elapsedUSec; return st; }
// (pat) BUG TODO: TO WHOM IT MAY CONCERN: // I am not sure this routine works properly. If there is no CCCH message (an L3Frame) // in the queue immediately after the previous frame is sent, an idle frame is inserted. // If a subsequent valid CCCH message (paging response or MS initiated RR call or packet // uplink request) arrives it will be blocked until the idle frame is sent. // Probably doesnt matter for RR establishment, but for packets, the extra 1/4 sec // delay (length of a 51-multiframe) is going to hurt. // Note that a GPRS Immediate Assignment message must know when this CCCH gets sent. // Right now, it has to guess. // pats TODO: Send the transceiver an idle frame rather than doing it here. // This should be architecturally changed to a pull-system instead of push. // Among other things, that would let us prioritize the responses // (eg, emergency calls go first) and let the packet Immediate Assignment message be // created right before being sent, when we are certain when the // Immediate Assignment is being sent. void CCCHLogicalChannel::serviceLoop() { // build the idle frame static const L3PagingRequestType1 filler; static const L3Frame idleFrame(filler,UNIT_DATA); #if ENABLE_PAGING_CHANNELS L3ControlChannelDescription mCC; unsigned bs_pa_mfrms = mCC.getBS_PA_MFRMS(); #endif // prime the first idle frame LogicalChannel::send(idleFrame); // run the loop while (true) { L3Frame* frame = NULL; #if ENABLE_PAGING_CHANNELS // Check for paging message for this specific paging slot first, // and if none, send any message in the mQ. // The multiframe paging logic is from GSM 05.02 6.5.3. // See documentation at crackPagingFromImsi() which is used to // get the messages into the proper mPagingQ. GSM::Time next = getNextWriteTime(); unsigned multiframe_index = (next.FN() / 51) % bs_pa_mfrms; frame = mPagingQ[multiframe_index].read(); #endif if (frame == NULL) { frame = mQ.read(); // (pat) This is a blocking read; mQ is an InterThreadQueue } if (frame) { // (pat) This tortuously calls XCCCHL1Encoder::transmit (see my documentation // at LogicalChannel::send), which blocks until L1Encoder::mPrevWriteTime. // Note: The q size is 0 while we are blocked here, so if we are trying // to determine the next write time by adding the qsize, we are way off. // Thats why there is an mWaitingToSend flag. mWaitingToSend = true; // Waiting to send this block at mNextWriteTime. LogicalChannel::send(*frame); mWaitingToSend = false; OBJLOG(DEBUG) << "CCCHLogicalChannel::serviceLoop sending " << *frame << " load: " << load() << " time: " << getNextWriteTime(); delete frame; } if (mQ.size()==0) { // (pat) The radio continues to send the last frame forever, // so we only send one idle frame here. // Unfortunately, this slows the response. // TODO: Send a static idle frame to the Transciever and rewrite this. mWaitingToSend = true; // Waiting to send an idle frame at mNextWriteTime. LogicalChannel::send(idleFrame); mWaitingToSend = false; OBJLOG(DEBUG) << "CCCHLogicalChannel::serviceLoop sending idle frame"; } } }
bool CCCHLogicalChannel::sendGprsCcchMessage(NewPagingEntry *gprsMsg, GSM::Time &frameTime) { if (! gprsPageCcchSetTime(gprsMsg->mGprsClient,gprsMsg->mImmAssign,frameTime.FN())) { return false; } L2LogicalChannelBase::l2sendm(*(gprsMsg->mImmAssign),L3_UNIT_DATA); return true; }
// (pat) This routine is going to be entirely replaced with one that works better for gprs. // In the meantime, just return a number that is large enough to cover // the worst case, which assumes that the messages in mQ also // must go out on the paging timeslot. Time GSM::CCCHLogicalChannel::getNextPchSendTime(unsigned multiframe_index) { L3ControlChannelDescription mCC; // Paging is distributed over this many multi-frames. unsigned bs_pa_mfrms = mCC.getBS_PA_MFRMS(); GSM::Time next = getNextWriteTime(); unsigned next_multiframe_index = (next.FN() / 51) % bs_pa_mfrms; assert(bs_pa_mfrms > 1); assert(multiframe_index < bs_pa_mfrms); assert(next_multiframe_index < bs_pa_mfrms); int achload = mQ.size(); if (mWaitingToSend) { achload++; } // Total wait time is time needed to empty queue, plus the time until the first // paging opportunity, plus 2 times the number of guys waiting in the paging queue, // but it is all nonsense because if a new agch comes in, // it will displace the paging message because the q is sent first. // This just needs to be totally redone, and the best way is not to figure out // when the message will be sent at all, but rather use a call-back to gprs // just before the message is finally sent. int multiframesToWait = 0; if (achload) { multiframesToWait = bs_pa_mfrms - 1; // Assume worst case. } else { // If there is nothing else waiting, we can estimate better: while (next_multiframe_index != multiframe_index) { multiframe_index = (multiframe_index+1) % bs_pa_mfrms; multiframesToWait++; } } int total = achload + multiframesToWait + bs_pa_mfrms * mPagingQ[multiframe_index].size(); int fnresult = (next.FN() + total * 51) % gHyperframe; GSM::Time result(fnresult); LOG(DEBUG) << "CCCHLogicalChannel::getNextSend="<< next.FN() <<" load="<<achload<<LOGVAR(mWaitingToSend) <<" now="<<gBTS.time().FN()<<LOGVAR(fnresult); return result; }
Time GSM::CCCHLogicalChannel::getNextMsgSendTime() { // Get the current frame. // DAB GPRS - This should call L1->resync() first, otherwise, in an idle system, // DAB GPRS - you can get times well into the past.. // (pat) Above is done in the underlying getNextWriteTime() // Pats note: This may return the current frame number if it is ready to send now. // 3-18-2012: FIXME: This result is not monotonically increasing!! // That is screwing up GPRS sendAssignment. GSM::Time next = getNextWriteTime(); int achload = load(); if (mWaitingToSend) { achload++; } //old: GSM::Time result = next + (achload+3) * 51; // add one to be safe. // (pat) TODO: We are adding a whole 51-multframe for each additional // CCCH message, which may not be correct. // Note: We dont need to carefully make sure the frame // numbers are valid (eg, by rollForward), because this code is used by GPRS // which is going to convert it to an RLC block time anyway. int fnresult = (next.FN() + achload * 51) % gHyperframe; GSM::Time result(fnresult); LOG(DEBUG) << "CCCHLogicalChannel::getNextSend="<< next.FN() <<" load="<<achload<<LOGVAR(mWaitingToSend) <<" now="<<gBTS.time().FN()<<LOGVAR(fnresult); return result; }
void RadioInterface::driveReceiveRadio() { if (!mOn) return; if (mReceiveFIFO.size() > 8) return; pullBuffer(); GSM::Time rcvClock = mClock.get(); rcvClock.decTN(receiveOffset); unsigned tN = rcvClock.TN(); int rcvSz = rcvCursor/2; int readSz = 0; const int symbolsPerSlot = gSlotLen + 8; // while there's enough data in receive buffer, form received // GSM bursts and pass up to Transceiver // Using the 157-156-156-156 symbols per timeslot format. while (rcvSz > (symbolsPerSlot + (tN % 4 == 0))*samplesPerSymbol) { signalVector rxVector((symbolsPerSlot + (tN % 4 == 0))*samplesPerSymbol); unRadioifyVector(rcvBuffer+readSz*2,rxVector); GSM::Time tmpTime = rcvClock; if (rcvClock.FN() >= 0) { //LOG(DEBUG) << "FN: " << rcvClock.FN(); int dummyARFCN = 0; radioVector *rxBurst = NULL; if (!loadTest) rxBurst = new radioVector(rxVector,tmpTime,dummyARFCN); else { if (tN % 4 == 0) rxBurst = new radioVector(*finalVec9,tmpTime,dummyARFCN); else rxBurst = new radioVector(*finalVec,tmpTime,dummyARFCN); } mReceiveFIFO.put(rxBurst); } mClock.incTN(); rcvClock.incTN(); //if (mReceiveFIFO.size() >= 16) mReceiveFIFO.wait(8); //LOG(DEBUG) << "receiveFIFO: wrote radio vector at time: " << mClock.get() << ", new size: " << mReceiveFIFO.size() ; readSz += (symbolsPerSlot+(tN % 4 == 0))*samplesPerSymbol; rcvSz -= (symbolsPerSlot+(tN % 4 == 0))*samplesPerSymbol; tN = rcvClock.TN(); } if (readSz > 0) { memcpy(rcvBuffer,rcvBuffer+2*readSz,sizeof(short)*2*(rcvCursor/2-readSz)); rcvCursor = rcvCursor-2*readSz; } }
void RadioInterface::driveReceiveRadio() { pullBuffer(); if (!rcvBuffer) { return;} GSM::Time rcvClock = mClock.get(); rcvClock.decTN(receiveOffset); unsigned tN = rcvClock.TN(); int rcvSz = rcvBuffer->size(); int readSz = 0; const int symbolsPerSlot = gSlotLen + 8; // while there's enough data in receive buffer, form received // GSM bursts and pass up to Transceiver // Using the 157-156-156-156 symbols per timeslot format. while (rcvSz > (symbolsPerSlot + (tN % 4 == 0))*samplesPerSymbol) { signalVector rxVector(rcvBuffer->begin(), readSz, (symbolsPerSlot + (tN % 4 == 0))*samplesPerSymbol); GSM::Time tmpTime = rcvClock; if (rcvClock.FN() >= 0) { LOG(DEEPDEBUG) << "FN: " << rcvClock.FN(); radioVector* rxBurst = new radioVector(rxVector,tmpTime); mReceiveFIFO.write(rxBurst); } mClock.incTN(); rcvClock.incTN(); if (mReceiveFIFO.size() >= 16) mReceiveFIFO.wait(8); LOG(DEEPDEBUG) << "receiveFIFO: wrote radio vector at time: " << mClock.get() << ", new size: " << mReceiveFIFO.size() ; readSz += (symbolsPerSlot+(tN % 4 == 0))*samplesPerSymbol; rcvSz -= (symbolsPerSlot+(tN % 4 == 0))*samplesPerSymbol; tN = rcvClock.TN(); } signalVector *tmp = new signalVector(rcvBuffer->size()-readSz); rcvBuffer->segmentCopyTo(*tmp,readSz,tmp->size()); delete rcvBuffer; rcvBuffer = tmp; }
bool RadioInterface::driveReceiveRadio() { radioVector *burst = NULL; if (!mOn) return false; pullBuffer(); GSM::Time rcvClock = mClock.get(); rcvClock.decTN(receiveOffset); unsigned tN = rcvClock.TN(); int recvSz = recvCursor; int readSz = 0; const int symbolsPerSlot = gSlotLen + 8; int burstSize = (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx; /* * Pre-allocate head room for the largest correlation size * so we can later avoid a re-allocation and copy * */ size_t head = GSM::gRACHSynchSequence.size(); /* * Form receive bursts and pass up to transceiver. Use repeating * pattern of 157-156-156-156 symbols per timeslot */ while (recvSz > burstSize) { for (size_t i = 0; i < mChans; i++) { burst = new radioVector(rcvClock, burstSize, head, mMIMO); for (size_t n = 0; n < mMIMO; n++) { unRadioifyVector((float *) (recvBuffer[mMIMO * i + n]->begin() + readSz), *burst->getVector(n)); } if (mReceiveFIFO[i].size() < 32) mReceiveFIFO[i].write(burst); else delete burst; } mClock.incTN(); rcvClock.incTN(); readSz += burstSize; recvSz -= burstSize; tN = rcvClock.TN(); burstSize = (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx; } if (readSz > 0) { for (size_t i = 0; i < recvBuffer.size(); i++) { memmove(recvBuffer[i]->begin(), recvBuffer[i]->begin() + readSz, (recvCursor - readSz) * 2 * sizeof(float)); } recvCursor -= readSz; } return true; }