Пример #1
0
// 5-27-2012 pat added:
// Routines for CCCH messages to add real paging channels.
// Added in the simplest possible way to avoid destabilizing anything.
// GPRS still needs a pretty major rewrite of the underlying CCCHLogicalChannel class
// to reduce the latency, but paging queues at least relieve the congestion on CCCH.
// In DRX [Discontinuous Reception] mode the MS listens only to a subset of CCCH based on its IMSI.
// This is a GPRS thing but dependent on the configuration of CCCH in our system.
// See: GSM 05.02 6.5.2: Determination of CCCH_GROUP and PAGING_GROUP for MS in idle mode.
void GSMConfig::crackPagingFromImsi(	
	unsigned imsiMod1000	// The phones imsi mod 1000, so just atoi the last 3 digits.
	unsigned &paging_block_index,	// Returns which of the paging ccchs to use.
	unsigned &multiframe_index	// Returns which 51-multiframe to use.
	)
{
	L3ControlChannelDescription mCC;

	// BS_CCCH_SDCCH_COMB is defined in GSM 05.02 3.3.2.3;
	int bs_cc_chans;			// The number of ccch timeslots per 51-multiframe.
	bool bs_ccch_sdcch_comb;	// temp var indicates if sdcch is on same TS as ccch.
	switch (mCC.mCCCH_CONF) {
	case 0: bs_cc_chans=1; bs_ccch_sdcch_comb=false; break;
	case 1: bs_cc_chans=1; bs_ccch_sdcch_comb=true; break;
	case 2: bs_cc_chans=2; bs_ccch_sdcch_comb=false; break;
	case 4: bs_cc_chans=3; bs_ccch_sdcch_comb=false; break;
	case 6: bs_cc_chans=4; bs_ccch_sdcch_comb=false; break;
	default:
		LOG(ERR) << "Invalid GSM.CCCH.CCCH-CONF value:"<<mCC.mCCCH_CONF <<" GPRS will fail until fixed";
		return NULL;	// There will be no reliable GPRS service until you fix this.
	}

	// BS_PA_MFRMS is the number of 51-multiframes used for paging.
	unsigned bs_pa_mfrms = mCC.getBS_PA_MFRMS();

	// Here are some example numbers:
	// We currently use CCCH_CONF=1 so cc_chans=1, so agch_avail=3.
	// Since BS_CC_CHANS=1, then CCCH_GROUP is always 0.
	// For BS_PA_MFRMS=2, BS_AG_BLKS_RES=2:
	//	N=2; tmp = imsi % 2; CCCH_GROUP = 0; PAGING_GROUP = imsi % 2;
	// For BS_PA_MFRMS=2, BS_AG_BLKS_RES=1:
	//	N=4; tmp = imsi % 4; PAGING_GROUP = imsi % 4;
	// For BS_PA_MFRMS=2, BS_AG_BLKS_RES=0:
	//	N=6; tmp = imsi % 6; PAGING_GROUP = imsi % 6;
	// For BS_PA_MFRMS=3, BS_AG_BLKS_RES=0:
	//	N=9; tmp = imsi % 9; PAGING_GROUP = imsi % 9;
	// Paging block index = PAGING_GROUP % BS_PA_MFRMS
	// Multiframe index = PAGING_GROUP / pch_avail;
	// correct multiframe when: multiframe_index == (FN div 51) % BA_PA_MFRMS

	// From GSM 05.02 Clause 7 table 5 (located after sec 6.5)
	unsigned agch_avail = bs_ccch_sdcch_comb ? 3 : 8;
	// If you hit this assertion, go fix L3ControlChannelDescription
	// to make sure you leave some paging channels available.
	assert(agch_avail > mPCC.mBS_AG_BLKS_RES);

	// GSM 05.02 6.5.2: N is number of paging blocks "available" on one CCCH.
	// The "available" is in quotes and not specifically defined, but I believe
	// they mean after subtracting out BS_AG_BLKS_RES, as per 6.5.1 paragraph v).
	unsigned pch_avail = agch_avail - mPCC.mBS_AG_BLKS_RES;
	unsigned Ntotal = pch_avail * bs_pa_mfrms;
	unsigned tmp = (imsiMod1000 % (bs_cc_chans * Ntotal)) % Ntotal;
	unsigned paging_group = tmp % Ntotal;
	paging_block_index = paging_group / (Ntotal / bs_pa_mfrms);
	// And I quote: The required 51-multiframe occurs when:
	// PAGING_GROUP div (N div BS_PA_MFRMS) = (FN div 51) mod (BS_PA_MFRMS)
	multiframe_index = paging_group / (Ntotal % bs_pa_mfrms); 
}
Пример #2
0
// (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";
		}
	}
}
Пример #3
0
// (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;
}