mirror of
https://github.com/fairwaves/openbts-2.8.git
synced 2025-10-23 16:13:51 +00:00
git-svn-id: http://wush.net/svn/range/software/public/openbts/trunk@6168 19bc5d8c-e614-43d4-8b26-e1612bc8e597
523 lines
22 KiB
C++
523 lines
22 KiB
C++
/*
|
|
* Copyright 2011 Range Networks, Inc.
|
|
* All Rights Reserved.
|
|
*
|
|
* This software is distributed under multiple licenses;
|
|
* see the COPYING file in the main directory for licensing
|
|
* information for this specific distribuion.
|
|
*
|
|
* This use of this software may be subject to additional restrictions.
|
|
* See the LEGAL file in the main directory for details.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
*/
|
|
|
|
/**@file Common-use GSM declarations, most from the GSM 04.xx and 05.xx series. */
|
|
|
|
|
|
#ifndef GPRSL2MAC_H
|
|
#define GPRSL2MAC_H
|
|
|
|
#include "MemoryLeak.h"
|
|
#include "GPRSRLC.h"
|
|
#include "GSML1FEC.h"
|
|
#include "GSMTDMA.h"
|
|
#include "GSMTransfer.h" // For GSM::L2Frame
|
|
#include "Interthread.h"
|
|
//#include "GSMCommon.h" // For ChannelType
|
|
#include "GSML3RRElements.h" // For RequestReference
|
|
#include "TBF.h"
|
|
#include "RList.h"
|
|
#include "Utils.h"
|
|
#include <list>
|
|
namespace GPRS {
|
|
extern void mac_debug();
|
|
|
|
// (pat) About BSN (radio block sequence numbers):
|
|
// We need a period for our internal BSNs, and it is somewhat arbitrary.
|
|
// For timing, we need a cyclic period of at least 8 52-multiframes. (GSM03.64 Figure 19)
|
|
// There are specified timeouts of up to 5 seconds over which it would be convenient
|
|
// if radio block numbers were non-repeating, which would be about 1000 frames, 250 radio blocks.
|
|
// But there is no reason not to just use the hyperframe, so we will.
|
|
// A hyperframe is 2048 * 26 * 51 frames; (2048*26*51 * 12/52) = 626688 Radio Blocks.
|
|
// A 52 multiframe takes 240ms, so each radio block averages 20ms.
|
|
// btw, if the block sequence numbers went on forever, stored in an int, it would last 497 days.
|
|
// There are 52 frames for 12 blocks.
|
|
|
|
// In GSM the downlink block numbers trail the uplink block numbers slightly.
|
|
// I observed the incoming blocks are this far behind gBSNNext.
|
|
// If you are expecting an answer at time N,
|
|
// look for it when gBSNext == N+BSNLagTime.
|
|
const int BSNLagTime = 4;
|
|
|
|
extern bool gFixTFIBug;
|
|
extern bool gFixSyncUseClock; // For debugging: Use wall time for service loop synchronization
|
|
// instead of GSM frames. TODO: Get rid of this.
|
|
extern int gFixIdleFrame; // Works around this bug - see code.
|
|
extern int gFixDRX; // Works around DRX mode bug. The value is the number of assignments
|
|
// that are unanswered before we assume the MS is in DRX mode.
|
|
|
|
// Set to 1 to request a poll in the ImmediateAssignment on CCCH.
|
|
// We still have to wait for the poll time anyway, so this is here
|
|
// only for debugging.
|
|
extern bool gFixIAUsePoll;
|
|
extern bool gFixConvertForeignTLLI;
|
|
|
|
|
|
typedef RList<PDCHL1FEC*> PDCHL1FECList_t;
|
|
typedef RList<MSInfo*> MSInfoList_t;
|
|
|
|
struct Stats_t {
|
|
Statistic<double> macServiceLoopTime;
|
|
UInt_z countPDCH;
|
|
UInt_z countMSInfo;
|
|
UInt_z countTBF;
|
|
UInt_z countRach;
|
|
};
|
|
extern struct Stats_t Stats;
|
|
|
|
|
|
|
|
// For now, there is only one pool of TFIs shared by all channels.
|
|
// It should be per-ARFCN, but I expect there to only be one.
|
|
// Sharing TFIs between channels on the ARFCN makes multislot tfi allocation easy.
|
|
// There are 32 uplink and 32 downlink TFIs, which should be enough for some time to come.
|
|
// If this gets congested, can be split up into one pool of TFIs per uplink/downlink channel,
|
|
// but then you have to be careful when allocating multislot tfis that the
|
|
// tfi is unique across all channels.
|
|
// TODO: When we allocate multislot tfis, the tfi must be unique in all slots.
|
|
// The easiest way to do that is to have a single tfilist for the entire system.
|
|
class TBF;
|
|
struct TFIList {
|
|
TBF *mTFIs[2][32]; // One list for uplink, one list for downlink.
|
|
|
|
// 12-22-2011: It looked like the Blackberry abandoned an uplink TBF when
|
|
// a downlink TBF was established using the same TFI. This seems like a horrible
|
|
// bug in the MS, but to work around it, I added the gFixTFIBug which uses
|
|
// a single TFI space for both uplink and downlink. This eliminated
|
|
// a bunch of msStop calls with cause T3101, so I think this is a genuine
|
|
// problem with MSs and we need this fix in permanently.
|
|
// Update: The TFI is reserved during the time after a downlink ends, so the MS
|
|
// may have been justifiably upset about seeing it reissued for an uplink too soon.
|
|
RLCDir::type fixdir(RLCDir::type dir) {
|
|
return gFixTFIBug ? RLCDir::Up : dir;
|
|
}
|
|
|
|
TFIList();
|
|
|
|
TBF *getTFITBF(RLCDirType dir, int tfi) { return mTFIs[fixdir(dir)][tfi]; }
|
|
void setTFITBF(int tfi,RLCDirType dir,TBF *tbf) { mTFIs[fixdir(dir)][tfi] = tbf; }
|
|
int findFreeTFI(RLCDirType dir);
|
|
void tfiDump(std::ostream&os);
|
|
};
|
|
extern struct TFIList *gTFIs;
|
|
#if MAC_IMPLEMENTATION
|
|
TFIList::TFIList() { for (int i=0;i<32;i++) { mTFIs[0][i] = mTFIs[1][i] = NULL; } }
|
|
int TFIList::findFreeTFI(RLCDirType dir)
|
|
{
|
|
static int lasttfi = 0;
|
|
dir = fixdir(dir);
|
|
// TODO: After the TBF the tfi may only be reused by the same MS for some
|
|
// period of time. See "TBF release" section.
|
|
// Temporary work around is to round-robin the tfis.
|
|
for (int i = 0; i < 32; i++) {
|
|
lasttfi++;
|
|
if (lasttfi == 32) { lasttfi = 0; }
|
|
if (!mTFIs[dir][lasttfi]) { return lasttfi; }
|
|
}
|
|
#if 0
|
|
// DEBUG: start at 1 instead of 0
|
|
for (int tfi = 1; tfi < 32; tfi++) {
|
|
// DEBUG: try incrementing tfi to avoid duplication errors:
|
|
if (tfi == lasttfi) { continue; }
|
|
if (!mTFIs[dir][tfi]) {
|
|
lasttfi = tfi;
|
|
return tfi;
|
|
}
|
|
}
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
void TFIList::tfiDump(std::ostream&os)
|
|
{
|
|
int dir, tfi;
|
|
for (dir = 0; dir <= (gFixTFIBug ? 0 : 1); dir++) {
|
|
os << "TFI=(";
|
|
if (!gFixTFIBug) {
|
|
os << RLCDir::name(dir) << ":";
|
|
}
|
|
for (tfi = 0; tfi < 32; tfi++) {
|
|
TBF *tbf = mTFIs[dir][tfi];
|
|
if (tbf) { os << " " << tfi << "=>" << tbf; }
|
|
}
|
|
}
|
|
os << ")\n";
|
|
}
|
|
#endif
|
|
|
|
// The USF associates radio blocks with an MS.
|
|
// It is placed in the downlink block header to indicate that the next uplink block
|
|
// is allocated to the MS assigned that USF.
|
|
// There may be multiple simultaneous uplink TBFs from the same MS; all will use the same USF.
|
|
// The MS does that if a higher priority or throughput TBF comes in while one is in progress.
|
|
// The USF is only 3 bits, and 0x7 is reserved (to indicate PRACH) on PCCCH channels.
|
|
// We are not using PCCCH, but I am going to avoid 0x7 anyway.
|
|
// Additionally, for RACH initiated single block uplink assignments, we need a USF
|
|
// that is not in use by any MS, for which we will reserve USF=0.
|
|
// so really only 6 USFs (1-6) are available per uplink channel, which should be plenty.
|
|
// Note that there are alot more TFIs than USFs, because TFIs are per-TBF,
|
|
// while USFs are per-MS.
|
|
// The USFList information applies to an uplink channel, but it is used primarily by
|
|
// the downlink channel to set the USF in the MAC header of each downlink block.
|
|
// Note that there is no pointer to the TBFs (could be multiple ones) from this USF struct,
|
|
// because arriving uplink blocks are associated with their TBFs using the TFI, not the USF.
|
|
// The USFs are numbered 0..7.
|
|
const int USFMIN = 1;
|
|
const int USFMAX = 6;
|
|
const int USFTotal = 8;
|
|
#define USF_VALID(usf) ((usf) >= USFMIN && (usf) <= USFMAX)
|
|
class USFList
|
|
{
|
|
//PDCHL1FEC *mlchan; // The channel these USFs are being used on.
|
|
// We use the usf as the index, so mlUSFs[0] is unused.
|
|
struct UsfInfo {
|
|
MSInfo *muMS; // The MS assigned this USF on this channel.
|
|
GprsTimer muDeadTime; // When a TBF dies reserve the USF for this ms until this expires.
|
|
};
|
|
UsfInfo mlUSFs[USFTotal]; // Some slots in this array are unused.
|
|
|
|
//int mRandomUSF; // Used to pick one of the USFs.
|
|
|
|
// When the channel is running, we save the usf that is sent on each downlink block,
|
|
// so that we can correlate the uplink responses independently of their content.
|
|
// We save them in an array indexed by bsn, length only has to cover the difference
|
|
// between uplink and downlink BSNs plus some slop, so 32 is way overkill.
|
|
unsigned char sRememberUsf[32]; // The usf transmitted in the downlink block.
|
|
unsigned sRememberUsfBsn[32];
|
|
|
|
public:
|
|
USFList();
|
|
|
|
// Return the usf that was specified on the downlink burst, given the bsn from the uplink burst.
|
|
int getUsf(unsigned upbsn);
|
|
|
|
// Remember the usf transmitted on specified downlink burst. OK to pass 0 for usf.
|
|
void setUsf(unsigned downusf, unsigned downbsn); // Save usf for current downlink burst.
|
|
|
|
// Which MS is using this USF?
|
|
MSInfo *getUSFMS(int usf);
|
|
|
|
int allocateUSF(MSInfo *ms);
|
|
int freeUSF(MSInfo *ms,bool wReserve);
|
|
//int getRandomUSF();
|
|
void usfDump(std::ostream&os);
|
|
};
|
|
|
|
struct RachInfo
|
|
{
|
|
unsigned mRA;
|
|
const GSM::Time mWhen;
|
|
RadData mRadData;
|
|
|
|
// Gotta love this language.
|
|
RachInfo(unsigned wRA, const GSM::Time &wWhen, RadData wRD)
|
|
: mRA(wRA), mWhen(wWhen), mRadData(wRD)
|
|
{ RN_MEMCHKNEW(RachInfo) }
|
|
~RachInfo() { RN_MEMCHKDEL(RachInfo) }
|
|
void serviceRach();
|
|
};
|
|
|
|
|
|
// There is only one of these.
|
|
// It holds the lists used to find all the other stuff.
|
|
class L2MAC
|
|
{
|
|
Thread macThread;
|
|
// The entire MAC runs in a single thread.
|
|
// This Mutex is used at startup to make sure we only start one.
|
|
// Also used to lock the serviceloop so the CLI does not modify MS or TBF lists simultaneously.
|
|
public:
|
|
mutable Mutex macLock;
|
|
|
|
// The RACH bursts come in unsychronized to the rest of the GPRS code.
|
|
// The primary purpose of this queue is just to allow the MAC service loop
|
|
// to handle the RACH in its single thread by saving the RACH until the MAC service
|
|
// loop gets around to it. If GPRS is running, we dont really expect multiple
|
|
// simultaneous RACHs to queue up here because we service the RACH queue on each loop.
|
|
// However, if a RACH comes in while GPRS service is stopped and all channels
|
|
// are in use for RR connections, the as-yet-unserviced RACHs may queue up here.
|
|
// When GPRS service resumes, we should disard RACHs that are too old.
|
|
// Note that there could be multiple RACH for the same MS, a case we cannot detect.
|
|
InterthreadQueue<RachInfo> macRachQ;
|
|
|
|
// We are doing a linear search through these lists, but there should only be a few of them.
|
|
PDCHL1FECList_t macPDCHs; // channels assigned to GPRS.
|
|
PDCHL1FECList_t macPacchs; // The subset of macPDCHs that we assign as PACCH.
|
|
//Mutex macTbfListLock;
|
|
TBFList_t macTBFs; // active TBFs.
|
|
MSInfoList_t macMSs; // The MS we know about.
|
|
|
|
// For debugging, we keep expired TBF and MS around for post-mortem examination:
|
|
TBFList_t macExpiredTBFs;
|
|
MSInfoList_t macExpiredMSs;
|
|
|
|
#define RN_MAC_FOR_ALL_PDCH(ch) RN_FOR_ALL(PDCHL1FECList_t,gL2MAC.macPDCHs,ch)
|
|
#define RN_MAC_FOR_ALL_PACCH(ch) RN_FOR_ALL(PDCHL1FECList_t,gL2MAC.macPacchs,ch)
|
|
#define RN_MAC_FOR_ALL_MS(ms) for (RListIterator<MSInfo*> itr(gL2MAC.macMSs); itr.next(ms); )
|
|
#define RN_MAC_FOR_ALL_TBF(tbf) for (RListIterator<TBF*> itr(gL2MAC.macTBFs); itr.next(tbf); )
|
|
|
|
L2MAC()
|
|
{
|
|
gTFIs = new TFIList();
|
|
}
|
|
~L2MAC() { delete gTFIs; }
|
|
|
|
public:
|
|
unsigned macN3101Max;
|
|
unsigned macN3103Max;
|
|
unsigned macN3105Max;
|
|
unsigned macT3169Value;
|
|
unsigned macT3191Value;
|
|
unsigned macT3193Value;
|
|
unsigned macT3168Value;
|
|
unsigned macT3195Value;
|
|
unsigned macMSIdleMax;
|
|
unsigned macChIdleMax;
|
|
unsigned macChCongestionMax;
|
|
unsigned macDownlinkPersist;
|
|
unsigned macDownlinkKeepAlive;
|
|
unsigned macUplinkPersist;
|
|
unsigned macUplinkKeepAlive;
|
|
float macChCongestionThreshold;
|
|
Float_z macDownlinkUtilization;
|
|
|
|
Bool_z macRunning; // The macServiceLoop is running.
|
|
time_t macStartTime;
|
|
Bool_z macStopFlag; // Set this to terminate the service thread.
|
|
Bool_z macSingleStepMode; // For debugging.
|
|
|
|
MSInfo *macFindMSByTlli(uint32_t tlli, int create = 0);
|
|
void macAddMS(MSInfo *ms);
|
|
void macForgetMS(MSInfo *ms,bool forever);
|
|
|
|
// When deleting tbfs, macForgetTBF could be called on a tbf already removed
|
|
// from the list, which is ok.
|
|
void macAddTBF(TBF *tbf);
|
|
void macForgetTBF(TBF *tbf,bool forever);
|
|
|
|
void macServiceLoop();
|
|
PDCHL1FEC *macPickChannel(); // pick the least busy channel;
|
|
PDCHL1FEC *macFindChannel(unsigned arfcn, unsigned tn); // find specified channel, or null
|
|
unsigned macFindChannels(unsigned arfcn);
|
|
bool macAddChannel(); // Add a GSM RR channel to GPRS use.
|
|
bool macFreeChannel(); // Restore a GPRS channel back to GSM RR use.
|
|
void macForgetCh(PDCHL1FEC*ch);
|
|
void macConfigInit();
|
|
bool macStart(); // Fire it up.
|
|
void macStop(bool channelstoo); // Try to kill it.
|
|
int macActiveChannels(); // Is GPRS running, ie, are there channels allocated?
|
|
int macActiveChannelsC(unsigned cn); // Number of channels on specified 0-based ARFCN
|
|
float macComputeUtilization();
|
|
void macCheckChannels();
|
|
void macServiceRachQ();
|
|
};
|
|
extern L2MAC gL2MAC;
|
|
|
|
//const int TFIInvalid = -1;
|
|
//const int TFIUnknown = -2;
|
|
|
|
// The master clock is not exactly synced up with the radio clock.
|
|
// It is corrected at intervals. This means there is a variable delay
|
|
// between the time we send a message to the MS and when we can expect an answer.
|
|
// It does not affect RRBP reservations, which are relative, but it affects
|
|
// L3 messages sent on CCCH, which must specify an exact time for the response.
|
|
// I'm not sure what to do about this.
|
|
// I am just adding some ExtraDelay, and if reservations are unanswered,
|
|
// increasing this value until they start getting answered.
|
|
// We could probably set this back to 0 when we observe the time() run backwards,
|
|
// which means the clock is synced back up.
|
|
extern int ExtraClockDelay; // in blocks.
|
|
|
|
// This specifies a Radio Block reservation in an uplink channel.
|
|
// Reservations are used for:
|
|
// o response to CCCH Immediate Assignment One BLock initiated by MS on RACH.
|
|
// In this case we dont even know what MS the message was coming from, so if
|
|
// it does not arrive, nothing we can do but wait for the MS to try again later.
|
|
// o For an Uplink TBF: The RLCUpEngine sends AckNack every N blocks.
|
|
// We could require a response, but I dont think we will unless it gets stalled.
|
|
// o For a stalled Uplink TBF: The RLCUpEngine sends an AckNack with an RRBP
|
|
// reservation. The MS may respond with any type of message.
|
|
// If that response does not arrive, the RLCUpEngine network immediately sends
|
|
// another AckNack. Serviced when Uplink serviced.
|
|
// o For a completed Uplink TBF: network sends a final acknack with RRBP reservation,
|
|
// which must be repeated until received.
|
|
// Could be handled by the engine or MsgTransaction.
|
|
// o For a Downlink TBF: send an RRBP reservation every N blocks, which we expect
|
|
// the MS to use to send us an AckNack, or some other message. If we dont get
|
|
// a response, send another RRBP reservation immediately.
|
|
// o For a stalled Downlink TBF: resend the oldest block with another RRBP reservation.
|
|
// Note: a completed Downlink TBF can be destroyed immediately, since we received
|
|
// the final ack nack.
|
|
// The following are handled by the MsgTransaction class:
|
|
// o response to Packet Polling Request message.
|
|
// If the message does not arrive, we may want to try again.
|
|
// o RRBP responses in downlink TBF data blocks or control blocks.
|
|
// If these dont arrive from the MS, it doesnt matter.
|
|
// The response type is actually unknown: it could be a Packet Downlink Ack/Nack,
|
|
// or anything else the MS wants to send. The uplink message will have all the required
|
|
// info so we dont have to save anything in the RLCBlockReservation;
|
|
// o Packet Control Acknowledgement responses. Could come from:
|
|
// - Packet uplink/downlink assignment message, which may require network to resend.
|
|
// - Packet TBF release message, which requires network to resend.
|
|
|
|
// o WRONG: For an Uplink TBF: The RLCUpEngine sends AckNack after N blocks and provides an RRBP
|
|
// uplink response. The MS may respond with any type of message.
|
|
// If that response does not arrive, the RLCUpEngine network immediately sends
|
|
// another AckNack.
|
|
struct RLCBlockReservation : public Text2Str {
|
|
enum type {
|
|
None,
|
|
ForRACH,
|
|
ForPoll, // For the poll response to a downlink immediate assignment when
|
|
// the MS is in packet idle mode. see sendAssignment()
|
|
ForRRBP // This has many subtypes of type MsgTransactionType
|
|
};
|
|
type mrType; // Primary type
|
|
MsgTransactionType mrSubType; // Subtype, only valid if mrType is ForRRBP
|
|
RLCBSN_t mrBSN; // The block number that has been reserved.
|
|
TBF *mrTBF; // tbf if applicable. (Not known for MS initiated RACH.)
|
|
// TODO: Is it stupid to save mrRadData? We will get new data when the MS responds.
|
|
RadData mrRadData; // Saved from a RACH to be put in MS when it responds.
|
|
static const char *name(RLCBlockReservation::type type);
|
|
void text(std::ostream&) const;
|
|
};
|
|
std::ostream& operator<<(std::ostream& os, RLCBlockReservation::type &type);
|
|
std::ostream& operator<<(std::ostream& os, RLCBlockReservation &res);
|
|
|
|
#if MAC_IMPLEMENTATION
|
|
const char *RLCBlockReservation::name(RLCBlockReservation::type mode)
|
|
{
|
|
switch (mode) {
|
|
CASENAME(None)
|
|
CASENAME(ForRACH)
|
|
CASENAME(ForPoll)
|
|
CASENAME(ForRRBP)
|
|
default: return "unrecognized"; // Not reached, but makes gcc happy.
|
|
}
|
|
}
|
|
std::ostream& operator<<(std::ostream& os, RLCBlockReservation::type &type)
|
|
{
|
|
os << RLCBlockReservation::name(type);
|
|
return os;
|
|
}
|
|
void RLCBlockReservation::text(std::ostream &os) const
|
|
{
|
|
os << "res=(";
|
|
os << LOGVAR2("bsn",mrBSN) << " " << name(mrType);
|
|
if (mrTBF) { os << " " << mrTBF; }
|
|
os <<")";
|
|
}
|
|
std::ostream& operator<<(std::ostream& os, RLCBlockReservation &res)
|
|
{
|
|
res.text(os);
|
|
return os;
|
|
}
|
|
#endif
|
|
|
|
// The uplink reservation system.
|
|
// It is used by both uplink and downlink parts.
|
|
// I put it in its own class to avoid clutter elsewhere.
|
|
// Note that reservations are kept around after the current time passes,
|
|
// so that uplink acknowledgements can be paired with the message to which they belong.
|
|
//
|
|
// In order to efficiently utilize the uplink resource, we need to make reservations
|
|
// of future uplink RLCBlocks for various purposes.
|
|
// There is a problem in that the RRBP field is limited to identifying
|
|
// blocks 3-6 blocks in the future. The obvious solution would be to reserve
|
|
// them first, but that will not work because the control messages occur asynchronously
|
|
// with respect to the data streams and (should) have higher priority.
|
|
// My K.I.S.S. system to efficiently use these resources is to reserve even numbered
|
|
// uplink blocks for RRBP responses, which are typically Ack/Nack blocks,
|
|
// but could actually be any type of block, and to reserve odd numbered uplink blocks
|
|
// for all other control blocks, which include Single-Block accesses initiated
|
|
// by RACH (in which case, there is no TFI or TLLI) and all other control block
|
|
// responses to network initiated messages.
|
|
// A minimum sized downlink response is 2 blocks long, so this method tends to fully
|
|
// utilize the channel and still limit latency (as opposed to alternative schemes
|
|
// that would assign fixed slots for various messages, or lump all the blocks together
|
|
// which would mean that RRBP responses would sometimes not have a reservation available.)
|
|
// Note that a single-block downlink resend as a result of an Ack/Nack message with
|
|
// a single Nack may be only one block long, so it is still possible to run
|
|
// out of odd numbered uplink blocks for RRBP responses.
|
|
// When downlink blocks are finally queued for transmission, any unreserved uplink
|
|
// blocks are utilized for current uplink data transfers using dynamic allocation using USF.
|
|
// Using this method, the reservations are also monotonically increasing in each
|
|
// domain (RRBP and non-RRBP) which makes it easy.
|
|
class L1UplinkReservation
|
|
{
|
|
private:
|
|
// TODO: mLock no longer needed because RACH processing synchronous now.
|
|
Mutex mLock; // The reservation controller can be called from GSM threads, so protect it.
|
|
|
|
public:
|
|
// There should only be a few reservations at a time, probably limited to
|
|
// around one per actively attached MS.
|
|
// Update 8-8-2012: well, the MS can be in two sub-modes of transmit mode simultaneously,
|
|
// specifically, persistent keep-alive and reassignment, so I am upgrading this
|
|
// with the sub-type.
|
|
// There are timeouts of up to 5 seconds (250 blocks), so we should keep history that long.
|
|
// The maximum reservation in advance is probably from AGCH, which can stack up
|
|
// waiting for CCCH downlink spots up to a maximum (defined by a config option)
|
|
// in AccessGrantResponder(), but currently 1.5 seconds.
|
|
// There is no penalty for making this array larger, so just go ahead and overkill it.
|
|
static const int mReservationSize = (2*500);
|
|
RLCBlockReservation mReservations[mReservationSize];
|
|
|
|
L1UplinkReservation();
|
|
|
|
private:
|
|
RLCBSN_t makeReservationInt(RLCBlockReservation::type restype, RLCBSN_t afterBSN,
|
|
TBF *tbf, RadData *rd, int *prrbp, MsgTransactionType mttype);
|
|
|
|
public:
|
|
RLCBSN_t makeCCCHReservation(GSM::CCCHLogicalChannel *AGCH,
|
|
RLCBlockReservation::type type, TBF *tbf, RadData *rd, bool forDRX, MsgTransactionType mttype);
|
|
RLCBSN_t makeRRBPReservation(TBF *tbf, int *prrbp, MsgTransactionType ttype);
|
|
|
|
// Get the reservation for the specified block timeslot.
|
|
// Return true if found, and return TFI in *TFI.
|
|
// bsn can be in the past or future.
|
|
RLCBlockReservation *getReservation(RLCBSN_t bsn);
|
|
|
|
void clearReservation(RLCBSN_t bsn, TBF *tbf);
|
|
RLCBlockReservation::type recvReservation(RLCBSN_t bsn, TBF**restbf, RadData *prd,PDCHL1FEC *ch);
|
|
void dumpReservations(std::ostream&os);
|
|
};
|
|
|
|
extern bool setMACFields(MACDownlinkHeader *block, PDCHL1FEC *pdch, TBF *tbf, int makeres,MsgTransactionType mttype,unsigned *pcounter);
|
|
extern int configGetNumQ(const char *name, int defaultvalue);
|
|
extern int configGprsMultislotMaxUplink();
|
|
extern int configGprsMultislotMaxDownlink();
|
|
|
|
// The USF is assigned in each downlink block to indicate if the uplink
|
|
// block in the same frame position is available for uplink data,
|
|
// or reserved for some other purpose.
|
|
// There are only 7 USFs available, so we have to share.
|
|
// TODO: MOVE TO UPLINK RESERVATION:
|
|
//class L1USFTable
|
|
//{
|
|
// TBF *mUSFTable[8];
|
|
// public:
|
|
// void setUSF(RLCBSN_t bsn, TBF* tbf) { mUSFTable[bsn % mUSFTableSize] = tbf; }
|
|
// TBF *getTBFByUSF(RLCBSN_t bsn) { return mUSFTable[bsn % mUSFTableSize]; }
|
|
//
|
|
// L1USFTable() { for (int i = mUSFTableSize-1; i>= 0; i--) { mUSFTable[i] = 0; } }
|
|
//};
|
|
|
|
}; // namespace GPRS
|
|
|
|
#endif
|