sync of openbts

git-svn-id: http://wush.net/svn/range/software/public/openbts/trunk@6168 19bc5d8c-e614-43d4-8b26-e1612bc8e597
This commit is contained in:
Kurtis Heimerl
2013-08-14 00:52:14 +00:00
parent 1baba59e14
commit 5289a229d9
219 changed files with 42413 additions and 4213 deletions

22
GSM/AppInfTest.cpp Normal file
View File

@@ -0,0 +1,22 @@
#include <iostream>
#include <GSML3RRMessages.h>
#include <GSMTransfer.h>
// Load configuration from a file.
ConfigurationTable gConfig("OpenBTS.config");
int main()
{
GSM::L3ApplicationInformation ai();
static const char init_request_msbased_gps[4] = {'@', '\x01', 'x', '\xa8'}; // pre encoded PER for the following XER:
static std::vector<char> request_msbased_gps(init_request_msbased_gps,
init_request_msbased_gps + sizeof(init_request_msbased_gps));
GSM::L3ApplicationInformation ai2(request_msbased_gps);
GSM::L3Frame f(ai2);
std::cout << f;
return 0;
}

View File

@@ -1,24 +1,14 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/

View File

@@ -1,21 +1,14 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/

View File

@@ -1,29 +1,22 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2011 Range Networks, Inc.
* Copyright 2011, 2013 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
#include <Globals.h>
#include "GSMCommon.h"
using namespace GSM;
@@ -47,6 +40,9 @@ const char* GSM::CallStateString(GSM::CallState state)
case ReleaseRequest: return "release-request";
case SMSDelivering: return "SMS-delivery";
case SMSSubmitting: return "SMS-submission";
case HandoverInbound: return "HANDOVER Inbound";
case HandoverProgress: return "HANDOVER Progress";
case HandoverOutbound: return "HANDOVER Outbound";
case BusyReject: return "Busy Reject";
default: return NULL;
}
@@ -56,7 +52,7 @@ ostream& GSM::operator<<(ostream& os, GSM::CallState state)
{
const char* str = GSM::CallStateString(state);
if (str) os << str;
else os << "?" << state << "?";
else os << "?" << ((int)state) << "?";
return os;
}
@@ -131,17 +127,17 @@ unsigned GSM::uplinkFreqKHz(GSMBand band, unsigned ARFCN)
{
switch (band) {
case GSM850:
assert((ARFCN<252)&&(ARFCN>129));
assert((ARFCN>=128)&&(ARFCN<=251));
return 824200+200*(ARFCN-128);
case EGSM900:
if (ARFCN<=124) return 890000+200*ARFCN;
assert((ARFCN>974)&&(ARFCN<1024));
assert((ARFCN>=975)&&(ARFCN<=1023));
return 890000+200*(ARFCN-1024);
case DCS1800:
assert((ARFCN>511)&&(ARFCN<886));
assert((ARFCN>=512)&&(ARFCN<=885));
return 1710200+200*(ARFCN-512);
case PCS1900:
assert((ARFCN>511)&&(ARFCN<811));
assert((ARFCN>=512)&&(ARFCN<=810));
return 1850200+200*(ARFCN-512);
default:
assert(0);
@@ -241,6 +237,19 @@ int32_t Clock::FN() const
return currentFN;
}
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;
}
void Clock::wait(const Time& when) const
{
@@ -320,7 +329,13 @@ ostream& GSM::operator<<(ostream& os, TypeAndOffset tao)
case SDCCH_8_5: os << "SDCCH/8-5"; break;
case SDCCH_8_6: os << "SDCCH/8-6"; break;
case SDCCH_8_7: os << "SDCCH/8-7"; break;
case TDMA_BEACON: os << "(beacon)"; break;
case TDMA_BEACON: os << "BCH"; break;
case TDMA_BEACON_BCCH: os << "BCCH"; break;
case TDMA_BEACON_CCCH: os << "CCCH"; break;
case TDMA_PDCH: os << "PDCH"; break;
case TDMA_PACCH: os << "PACCH"; break;
case TDMA_PTCCH: os << "PTCCH"; break;
case TDMA_PDIDLE: os << "PDIDLE"; break;
default: os << "?" << (int)tao << "?";
}
return os;
@@ -343,8 +358,14 @@ ostream& GSM::operator<<(ostream& os, ChannelType val)
case AnyTCHType: os << "any TCH"; break;
case LoopbackFullType: os << "Loopback Full"; break;
case LoopbackHalfType: os << "Loopback Half"; break;
case PDTCHCS1Type: os << "PDTCHCS1"; break;
case PDTCHCS2Type: os << "PDTCHCS2"; break;
case PDTCHCS3Type: os << "PDTCHCS3"; break;
case PDTCHCS4Type: os << "PDTCHCS4"; break;
case PSingleBlock1PhaseType: os << "GPRS_SingleBlock1Phase"; break;
case PSingleBlock2PhaseType: os << "GPRS_SingleBlock2Phase"; break;
case AnyDCCHType: os << "any DCCH"; break;
default: os << "?" << (int)val << "?";
default: os << "?" << (int)val << "?"; break;
}
return os;
}

View File

@@ -1,25 +1,19 @@
/**@file Common-use GSM declarations, most from the GSM 04.xx and 05.xx series. */
/*
* Copyright 2008-2011 Free Software Foundation, Inc.
* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
* Copyright 2011 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -28,6 +22,7 @@
#ifndef GSMCOMMON_H
#define GSMCOMMON_H
#include "Defines.h"
#include <stdlib.h>
#include <sys/time.h>
#include <ostream>
@@ -38,8 +33,6 @@
#include <BitVector.h>
namespace GSM {
/**@namespace GSM This namespace covers L1 FEC, L2 and L3 message translation. */
@@ -82,7 +75,6 @@ std::ostream& operator<<(std::ostream& os, CallState state);
/** A base class for GSM exceptions. */
class GSMError {};
/** Duration ofa GSM frame, in microseconds. */
@@ -221,6 +213,7 @@ enum ChannelType {
CCCHType, ///< common control, a combination of several sub-types
RACHType, ///< random access
SACCHType, ///< slow associated control (acutally dedicated, but...)
CBCHType, ///< cell broadcast channel
//@}
///@name Dedicated control channels (DCCHs).
//@{
@@ -232,6 +225,19 @@ enum ChannelType {
TCHFType, ///< full-rate traffic
TCHHType, ///< half-rate traffic
AnyTCHType, ///< any TCH type
//@{
//@name Packet channels for GPRS.
PDTCHCS1Type,
PDTCHCS2Type,
PDTCHCS3Type,
PDTCHCS4Type,
//@}
//@{
//@name Packet CHANNEL REQUEST responses
// These are used only as return value from decodeChannelNeeded(), and do not correspond
// to any logical channels.
PSingleBlock1PhaseType,
PSingleBlock2PhaseType,
//@}
///@name Special internal channel types.
//@{
@@ -240,6 +246,7 @@ enum ChannelType {
AnyDCCHType, ///< any dedicated control channel
UndefinedCHType, ///< undefined
//@}
//@}
};
@@ -274,7 +281,12 @@ enum TypeAndOffset {
/// Some extra ones for our internal use.
TDMA_BEACON_BCCH=253,
TDMA_BEACON_CCCH=252,
TDMA_BEACON=255
TDMA_BEACON=255,
//TDMA_PDTCHF, // packet data traffic logical channel, full speed.
TDMA_PDCH, // packet data channel, inclusive
TDMA_PACCH, // packet control channel, shared with data but distinguished in MAC header.
TDMA_PTCCH, // packet data timing advance logical channel
TDMA_PDIDLE // Handles the packet channel idle frames.
};
std::ostream& operator<<(std::ostream& os, TypeAndOffset);
@@ -297,7 +309,7 @@ enum L3PD {
L3PDSS2PD=0x04,
L3MobilityManagementPD=0x05,
L3RadioResourcePD=0x06,
L3MobilityManagementGPRSPD=0x08,
L3GPRSMobilityManagementPD=0x08,
L3SMSPD=0x09,
L3GPRSSessionManagementPD=0x0a,
L3NonCallSSPD=0x0b,
@@ -328,6 +340,7 @@ extern const unsigned RACHWaitSParam[];
/**@name Modulus operations for frame numbers. */
//@{
/** The GSM hyperframe is largest time period in the GSM system, GSM 05.02 4.3.3. */
// It is 2715648
const uint32_t gHyperframe = 2048UL * 26UL * 51UL;
/** Get a clock difference, within the modulus, v1-v2. */
@@ -547,6 +560,9 @@ class Clock {
/** Block until the clock passes a given time. */
void wait(const Time&) const;
/** Return the system time associated with a given timestamp. */
double systime(const Time&) const;
};

View File

@@ -1,24 +1,14 @@
/*
* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -26,21 +16,27 @@
#include "GSMConfig.h"
#include "GSMTransfer.h"
#include "GSMLogicalChannel.h"
#include "GPRSExport.h"
#include <ControlCommon.h>
#include <Logger.h>
#include <NeighborTable.h>
#include <Reporting.h>
#include <Globals.h>
using namespace std;
using namespace GSM;
GSMConfig::GSMConfig()
:
:mCBCH(NULL),
mSI5Frame(UNIT_DATA),mSI6Frame(UNIT_DATA),
mStartTime(::time(NULL))
mSI1(NULL),mSI2(NULL),mSI3(NULL),mSI4(NULL),
mSI5(NULL),mSI6(NULL),
mStartTime(::time(NULL)),
mChangemark(0)
{
}
@@ -48,7 +44,7 @@ void GSMConfig::init()
{
mBand = (GSMBand)gConfig.getNum("GSM.Radio.Band");
mT3122 = gConfig.getNum("GSM.Timer.T3122Min");
regenerateBeacon();
regenerateBeacon();
}
void GSMConfig::start()
@@ -56,6 +52,12 @@ void GSMConfig::start()
mPowerManager.start();
// Do not call this until the paging channels are installed.
mPager.start();
// If requested, start gprs to allocate channels at startup.
// Otherwise, channels are allocated on demand, if possible.
if (GPRS::configGprsChannelsMin() > 0) {
// Start gprs.
GPRS::gprsStart();
}
// Do not call this until AGCHs are installed.
mAccessGrantThread.start(Control::AccessGrantServiceLoop,NULL);
}
@@ -65,10 +67,13 @@ void GSMConfig::start()
void GSMConfig::regenerateBeacon()
{
// FIXME -- Need to implement BCCH_CHANGE_MARK
gReports.incr("OpenBTS.GSM.RR.BeaconRegenerated");
mChangemark++;
// Update everything from the configuration.
LOG(NOTICE) << "regenerating system information messages";
LOG(NOTICE) << "regenerating system information messages, changemark " << mChangemark;
// BSIC components
mNCC = gConfig.getNum("GSM.Identity.BSIC.NCC");
@@ -79,61 +84,100 @@ void GSMConfig::regenerateBeacon()
// MCC/MNC/LAC
mLAI = L3LocationAreaIdentity();
std::vector<unsigned> neighbors = gNeighborTable.ARFCNList();
// if the neighbor list is emtpy, put ourselves on it
if (neighbors.size()==0) neighbors.push_back(gConfig.getNum("GSM.Radio.C0"));
// Now regenerate all of the system information messages.
// SI1
L3SystemInformationType1 SI1;
LOG(INFO) << SI1;
L3SystemInformationType1 *SI1 = new L3SystemInformationType1;
if (mSI1) delete mSI1;
mSI1 = SI1;
LOG(INFO) << *SI1;
L3Frame SI1L3(UNIT_DATA);
SI1.write(SI1L3);
SI1->write(SI1L3);
L2Header SI1Header(L2Length(SI1L3.L2Length()));
mSI1Frame = L2Frame(SI1Header,SI1L3);
LOG(DEBUG) << "mSI1Frame " << mSI1Frame;
// SI2
L3SystemInformationType2 SI2;
LOG(INFO) << SI2;
L3SystemInformationType2 *SI2 = new L3SystemInformationType2(neighbors);
if (mSI2) delete mSI2;
mSI2 = SI2;
LOG(INFO) << *SI2;
L3Frame SI2L3(UNIT_DATA);
SI2.write(SI2L3);
SI2->write(SI2L3);
L2Header SI2Header(L2Length(SI2L3.L2Length()));
mSI2Frame = L2Frame(SI2Header,SI2L3);
LOG(DEBUG) << "mSI2Frame " << mSI2Frame;
// SI3
L3SystemInformationType3 SI3;
LOG(INFO) << SI3;
L3SystemInformationType3 *SI3 = new L3SystemInformationType3;
if (mSI3) delete mSI3;
mSI3 = SI3;
LOG(INFO) << *SI3;
L3Frame SI3L3(UNIT_DATA);
SI3.write(SI3L3);
SI3->write(SI3L3);
L2Header SI3Header(L2Length(SI3L3.L2Length()));
mSI3Frame = L2Frame(SI3Header,SI3L3);
mSI3Frame = L2Frame(SI3Header,SI3L3,true);
LOG(DEBUG) << "mSI3Frame " << mSI3Frame;
// SI4
L3SystemInformationType4 SI4;
L3SystemInformationType4 *SI4 = new L3SystemInformationType4;
if (mSI4) delete mSI4;
mSI4 = SI4;
LOG(INFO) << *SI4;
LOG(INFO) << SI4;
L3Frame SI4L3(UNIT_DATA);
SI4.write(SI4L3);
SI4->write(SI4L3);
//printf("SI4 bodylength=%d l2len=%d\n",SI4.l2BodyLength(),SI4L3.L2Length());
//printf("SI4L3.size=%d\n",SI4L3.size());
L2Header SI4Header(L2Length(SI4L3.L2Length()));
mSI4Frame = L2Frame(SI4Header,SI4L3);
mSI4Frame = L2Frame(SI4Header,SI4L3,true);
LOG(DEBUG) << "mSI4Frame " << mSI4Frame;
#if GPRS_PAT | GPRS_TEST
// SI13. pat added 8-2011 to advertise GPRS support.
L3SystemInformationType13 *SI13 = new L3SystemInformationType13;
LOG(INFO) << *SI13;
L3Frame SI13L3(UNIT_DATA);
//printf("start=%d\n",SI13L3.size());
SI13->write(SI13L3);
//printf("end=%d\n",SI13L3.size());
//printf("SI13 bodylength=%d l2len=%d\n",SI13.l2BodyLength(),SI13L3.L2Length());
//printf("SI13L3.size=%d\n",SI13L3.size());
L2Header SI13Header(L2Length(SI13L3.L2Length()));
mSI13Frame = L2Frame(SI13Header,SI13L3,true);
LOG(DEBUG) << "mSI13Frame " << mSI13Frame;
#endif
// SI5
L3SystemInformationType5 SI5;
LOG(INFO) << SI5;
SI5.write(mSI5Frame);
LOG(DEBUG) << "mSI5Frame " << mSI5Frame;
regenerateSI5();
// SI6
L3SystemInformationType6 SI6;
LOG(INFO) << SI6;
SI6.write(mSI6Frame);
L3SystemInformationType6 *SI6 = new L3SystemInformationType6;
if (mSI6) delete mSI6;
mSI6 = SI6;
LOG(INFO) << *SI6;
SI6->write(mSI6Frame);
LOG(DEBUG) "mSI6Frame " << mSI6Frame;
}
void GSMConfig::regenerateSI5()
{
std::vector<unsigned> neighbors = gNeighborTable.ARFCNList();
// if the neighbor list is emtpy, put ourselves on it
if (neighbors.size()==0) neighbors.push_back(gConfig.getNum("GSM.Radio.C0"));
L3SystemInformationType5 *SI5 = new L3SystemInformationType5(neighbors);
if (mSI5) delete mSI5;
mSI5 = SI5;
LOG(INFO) << *SI5;
SI5->write(mSI5Frame);
LOG(DEBUG) << "mSI5Frame " << mSI5Frame;
}
CCCHLogicalChannel* GSMConfig::minimumLoad(CCCHList &chanList)
{
@@ -158,43 +202,190 @@ CCCHLogicalChannel* GSMConfig::minimumLoad(CCCHList &chanList)
template <class ChanType> ChanType* getChan(vector<ChanType*>& chanList)
template <class ChanType> ChanType* getChan(vector<ChanType*>& chanList, bool forGprs)
{
const unsigned sz = chanList.size();
LOG(DEBUG) << "sz=" << sz;
if (sz==0) return NULL;
// Start the search from a random point in the list.
//unsigned pos = random() % sz;
// HACK -- Try in-order allocation for debugging.
for (unsigned i=0; i<sz; i++) {
ChanType *chan = chanList[i];
//ChanType *chan = chanList[pos];
if (chan->recyclable()) return chan;
//pos = (pos+1) % sz;
// (pat) Dont randomize for GPRS! GPRS requires that channels are returned
// in order for the initial channels allocated on C0.
// We shouldnt randomize at all because we want RR TCH to come from the
// front of the list and GPRS from the back.
unsigned pos = 0;
const char *configRandomize = "GSM.Channels.Randomize";
if (gConfig.defines(configRandomize)) {
if (forGprs) {
// If the parameter is 'required', the gConfig.remove fails, but dont print a zillion messages.
static bool once = true;
if (once) {
LOG(ALERT) << "Config parameter '" << configRandomize << "' is incompatible with GPRS, removed";
once = false;
}
gConfig.remove(configRandomize);
} else {
pos = random() % sz;
}
}
for (unsigned i=0; i<sz; i++, pos = (pos+1)%sz) {
LOG(DEBUG) << "pos=" << pos << " " << i << "/" << sz;
ChanType *chan = chanList[pos];
if (! chan->inUseByGPRS() && chan->recyclable()) return chan;
}
return NULL;
}
// Are the two channels adjacent?
template <class ChanType>
bool testAdjacent(ChanType *ch1, ChanType *ch2)
{
return (ch1->CN() == ch2->CN() && ch1->TN() == ch2->TN()-1);
}
// Return the goodness of this possible match of gprs channels.
// Higher numbers are gooder.
template <class ChanType>
int testGoodness(vector<ChanType*>& chanList, int lo, int hi)
{
int goodness = 0;
if (lo > 0) {
ChanType *ch1 = chanList[lo-1]; // ch1 is below to ch lo.
if (testAdjacent(ch1,chanList[lo])) {
// The best match is adjacent to other gprs channels.
if (ch1->inUseByGPRS()) { goodness += 2; }
// The next best is an empty adjacent channel.
else if (ch1->recyclable()) { goodness += 1; }
}
}
if (hi < (int)chanList.size()-1) {
ChanType *ch2 = chanList[hi+1]; // ch2 is above ch hi
if (testAdjacent(ch2,chanList[hi])) {
if (ch2->inUseByGPRS()) { goodness += 2; }
else if (ch2->recyclable()) { goodness += 1; }
}
}
return goodness;
}
// (pat) 6-20-2012: To increase the likelihood that GPRS channels will be adjacent,
// GSM RR channels will be allocated from the front of the channel list
// and GPRS from the end.
// This function allocates a group of channels for gprs.
// Look for the largest group of adjacent channels <= groupSize.
// Give preference to channels that are adjacent to channels already
// allocated for gprs, or to empty channels.
// Give second preference to groups near the end of the channel list.
// Return the allocated channels in the array pointed to by results and
// return number of channels found.
template <class ChanType>
static unsigned getChanGroup(vector<ChanType*>& chanList, ChanType **results)
{
const unsigned sz = chanList.size();
if (sz==0) return 0;
const bool backwards = true; // Currently we always search backwards.
// To search forwards, dont forget to invert besti,bestn below
ChanType *prevFreeCh = NULL; // unneeded initialization
int curN = 0; // current number of adjacent free channels.
int bestI=0, bestN=0; // best match
int bestGoodness = 0; // goodness of best match
for (unsigned i=0; i<sz; i++) {
ChanType *chan = chanList[backwards ? sz-i-1 : i];
if (chan->inUseByGPRS()) { continue; }
if (! chan->recyclable()) { continue; }
if (bestN == 0) {
bestI = i;
curN = bestN = 1;
bestGoodness = testGoodness(chanList,bestI,bestN);
} else {
if (testAdjacent<ChanType>(chan,prevFreeCh)) {
curN++; // chan is adjacent to prevCh.
int curGoodness = testGoodness(chanList,i,curN);
if (curN > bestN || (curN == bestN && curGoodness > bestGoodness)) {
// Best so far, so remember it.
bestN = curN;
bestI = i;
bestGoodness = curGoodness;
// optional early termination test
//if (bestN >= groupSize && bestIsAdjacent) { goto finished; }
}
} else {
curN = 0;
}
}
prevFreeCh = chan;
}
//finished:
for (int j = 0; j < bestN; j++) {
results[j] = chanList[bestI+j];
}
return bestN;
}
// Allocate a group of channels for gprs.
// See comments at getChanGroup.
int GSMConfig::getTCHGroup(int groupSize,TCHFACCHLogicalChannel **results)
{
ScopedLock lock(mLock);
int nfound = getChanGroup<TCHFACCHLogicalChannel>(mTCHPool,results);
for (int i = 0; i < nfound; i++) {
results[i]->debugGetL1()->setGPRS(true,NULL);
}
return nfound;
}
SDCCHLogicalChannel *GSMConfig::getSDCCH()
{
LOG(DEBUG);
ScopedLock lock(mLock);
SDCCHLogicalChannel *chan = getChan<SDCCHLogicalChannel>(mSDCCHPool);
LOG(DEBUG);
SDCCHLogicalChannel *chan = getChan<SDCCHLogicalChannel>(mSDCCHPool,0);
LOG(DEBUG);
if (chan) chan->open();
LOG(DEBUG);
return chan;
}
TCHFACCHLogicalChannel *GSMConfig::getTCH()
// (pat) By a very tortuous path, chan->open() calls L1Encoder::open() and L1Decoder::open(),
// which sets mActive in both and resets the timers.
TCHFACCHLogicalChannel *GSMConfig::getTCH(
bool forGPRS, // If true, allocate the channel to gprs, else to RR use.
bool onlyCN0) // If true, allocate only channels on the lowest ARFCN.
{
LOG(DEBUG);
ScopedLock lock(mLock);
TCHFACCHLogicalChannel *chan = getChan<TCHFACCHLogicalChannel>(mTCHPool);
//if (GPRS::GPRSDebug) {
// const unsigned sz = mTCHPool.size();
// char buf[300]; int n = 0;
// for (unsigned i=0; i<sz; i++) {
// TCHFACCHLogicalChannel *chan = mTCHPool[i];
// n += sprintf(&buf[n],"ch=%d:%d,g=%d,r=%d ",chan->CN(),chan->TN(),
// chan->inUseByGPRS(),chan->recyclable());
// }
// LOG(WARNING)<<"getTCH list:"<<buf;
//}
TCHFACCHLogicalChannel *chan = getChan<TCHFACCHLogicalChannel>(mTCHPool,forGPRS);
// (pat) We have to open it or set gprs mode before returning to avoid a race.
if (chan) {
chan->open();
gReports.incr("OpenBTS.GSM.RR.ChannelAssignment");
// The channels are searched in order from low to high, so if the first channel
// found is not on CN0, we have failed.
//LOG(DEBUG)<<"getTCH returns"<<LOGVAR2("chan->CN",chan->CN());
if (onlyCN0 && chan->CN()) { return NULL; }
if (forGPRS) {
// (pat) Reserves channel for GPRS, but does not start delivering bursts yet.
chan->debugGetL1()->setGPRS(true,NULL);
return chan;
}
chan->open(); // (pat) LogicalChannel::open(); Opens mSACCH also.
gReports.incr("OpenBTS.GSM.RR.ChannelAssignment");
} else {
//LOG(DEBUG)<<"getTCH returns NULL";
}
LOG(DEBUG);
return chan;
}
@@ -204,6 +395,7 @@ template <class ChanType> size_t chanAvailable(const vector<ChanType*>& chanList
{
size_t count = 0;
for (unsigned i=0; i<chanList.size(); i++) {
if (chanList[i]->inUseByGPRS()) { continue; }
if (chanList[i]->recyclable()) count++;
}
return count;
@@ -227,7 +419,7 @@ size_t GSMConfig::TCHAvailable() const
size_t GSMConfig::totalLoad(const CCCHList& chanList) const
{
size_t total = 0;
for (int i=0; i<chanList.size(); i++) {
for (unsigned i=0; i<chanList.size(); i++) {
total += chanList[i]->load();
}
return total;
@@ -235,17 +427,41 @@ size_t GSMConfig::totalLoad(const CCCHList& chanList) const
template <class ChanType> unsigned countActive(const vector<ChanType*>& chanList)
unsigned countActive(const SDCCHList& chanList)
{
unsigned active = 0;
const unsigned sz = chanList.size();
for (unsigned i=0; i<sz; i++) {
if (!chanList[i]->recyclable()) active++;
}
return active;
}
unsigned countActive(const TCHList& chanList)
{
unsigned active = 0;
const unsigned sz = chanList.size();
// Start the search from a random point in the list.
for (unsigned i=0; i<sz; i++) {
if (chanList[i]->inUseByGPRS()) continue;
if (!chanList[i]->recyclable()) active++;
}
return active;
}
unsigned countAvailable(const TCHList& chanList)
{
unsigned available = 0;
const unsigned sz = chanList.size();
// Start the search from a random point in the list.
for (unsigned i=0; i<sz; i++) {
if (chanList[i]->inUseByGPRS()) continue;
available++;
}
return available;
}
unsigned GSMConfig::SDCCHActive() const
{
@@ -257,6 +473,13 @@ unsigned GSMConfig::TCHActive() const
return countActive(mTCHPool);
}
unsigned GSMConfig::TCHTotal() const
{
return countAvailable(mTCHPool);
}
unsigned GSMConfig::T3122() const
{
@@ -270,7 +493,7 @@ unsigned GSMConfig::growT3122()
ScopedLock lock(mLock);
unsigned retVal = mT3122;
mT3122 += (random() % mT3122) / 2;
if (mT3122>max) mT3122=max;
if (mT3122>(int)max) mT3122=max;
return retVal;
}
@@ -281,7 +504,7 @@ unsigned GSMConfig::shrinkT3122()
ScopedLock lock(mLock);
unsigned retVal = mT3122;
mT3122 -= (random() % mT3122) / 2;
if (mT3122<min) mT3122=min;
if (mT3122<(int)min) mT3122=min;
return retVal;
}
@@ -294,7 +517,7 @@ void GSMConfig::createCombination0(TransceiverManager& TRX, unsigned TN)
LOG_ASSERT(TN!=0);
LOG(NOTICE) << "Configuring dummy filling on C0T " << TN;
ARFCNManager *radio = TRX.ARFCN(0);
radio->setSlot(TN,0);
radio->setSlot(TN,0); // (pat) 0 => Transciever.h enum ChannelCombination = FILL
}
@@ -303,14 +526,13 @@ void GSMConfig::createCombinationI(TransceiverManager& TRX, unsigned CN, unsigne
LOG_ASSERT((CN!=0)||(TN!=0));
LOG(NOTICE) << "Configuring combination I on C" << CN << "T" << TN;
ARFCNManager *radio = TRX.ARFCN(CN);
radio->setSlot(TN,1);
radio->setSlot(TN,1); // (pat) 1 => Transciever.h enum ChannelCombination = I
TCHFACCHLogicalChannel* chan = new TCHFACCHLogicalChannel(CN,TN,gTCHF_T[TN]);
chan->downstream(radio);
Thread* thread = new Thread;
thread->start((void*(*)(void*))Control::DCCHDispatcher,chan);
chan->open();
gBTS.addTCH(chan);
}
@@ -319,7 +541,7 @@ void GSMConfig::createCombinationVII(TransceiverManager& TRX, unsigned CN, unsig
LOG_ASSERT((CN!=0)||(TN!=0));
LOG(NOTICE) << "Configuring combination VII on C" << CN << "T" << TN;
ARFCNManager *radio = TRX.ARFCN(CN);
radio->setSlot(TN,7);
radio->setSlot(TN,7); // (pat) 7 => Transciever.h enum ChannelCombination = VII
for (int i=0; i<8; i++) {
SDCCHLogicalChannel* chan = new SDCCHLogicalChannel(CN,TN,gSDCCH8[i]);
chan->downstream(radio);
@@ -345,4 +567,95 @@ bool GSMConfig::hold() const
#if ENABLE_PAGING_CHANNELS
// 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);
}
void GSMConfig::sendPCH(const L3RRMessage& msg,unsigned imsiMod1000)
{
unsigned paging_block_index; // which of the paging ccchs to use.
unsigned multiframe_index; // which 51-multiframe to use.
crackPagingFromImsi(imsiMod1000,paging_block_index, multiframe_index);
assert(multiframe_index < sMax_BS_PA_MFRMS);
CCCHLogicalChannel* ch = getPCH(paging_block_index);
ch->mPagingQ[multiframe_index].write(new L3Frame((const L3Message&)msg,UNIT_DATA));
}
Time GSMConfig::getPchSendTime(imsiMod1000)
{
unsigned paging_block_index; // which of the paging ccchs to use.
unsigned multiframe_index; // which 51-multiframe to use.
crackPagingFromImsi(imsiMod1000,paging_block_index, multiframe_index);
assert(multiframe_index < sMax_BS_PA_MFRMS);
CCCHLogicalChannel* ch = getPCH(paging_block_index);
return ch->getNextPchSendTime(multiframe_index);
}
#endif
// vim: ts=4 sw=4

View File

@@ -1,24 +1,18 @@
/*
* Copyright 2008-2010 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
* Copyright 2012 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -27,6 +21,7 @@
#ifndef GSMCONFIG_H
#define GSMCONFIG_H
#include "Defines.h"
#include <vector>
#include <Interthread.h>
@@ -43,9 +38,13 @@
namespace GSM {
// From GSM 05.02 6.5.
const unsigned sMax_BS_PA_MFRMS = 9;
class CCCHLogicalChannel;
class SDCCHLogicalChannel;
class CBCHLogicalChannel;
class TCHFACCHLogicalChannel;
class CCCHList : public std::vector<CCCHLogicalChannel*> {};
@@ -73,6 +72,7 @@ class GSMConfig {
CCCHList mPCHPool; ///< paging CCCH subchannels
//@}
CBCHLogicalChannel* mCBCH;
/**@name Allocatable channel pools. */
//@{
@@ -86,7 +86,7 @@ class GSMConfig {
unsigned mBCC; ///< basestation color code
//@}
GSMBand mBand; ///< BTS operating band
GSMBand mBand; ///< BTS operating band, or 0 for custom band
Clock mClock; ///< local copy of BTS master clock
@@ -96,6 +96,7 @@ class GSMConfig {
L2Frame mSI2Frame;
L2Frame mSI3Frame;
L2Frame mSI4Frame;
L2Frame mSI13Frame; // pat added for GPRS
//@}
/**@name Encoded L3 frames to be sent on the SACCH. */
@@ -104,6 +105,16 @@ class GSMConfig {
L3Frame mSI6Frame;
//@}
/**@name Copies of system information messages as they were most recently generated. */
//@{
L3SystemInformationType1* mSI1;
L3SystemInformationType2* mSI2;
L3SystemInformationType3* mSI3;
L3SystemInformationType4* mSI4;
L3SystemInformationType5* mSI5;
L3SystemInformationType6* mSI6;
//@}
int mT3122;
time_t mStartTime;
@@ -115,12 +126,18 @@ class GSMConfig {
InterthreadQueue<Control::ChannelRequestRecord> mChannelRequestQueue;
Thread mAccessGrantThread;
unsigned mChangemark;
void crackPagingFromImsi(unsigned imsiMod1000,unsigned &ccch_group,unsigned &paging_Index);;
public:
GSMConfig();
/** Initialize with parameters from gConfig. */
void init();
@@ -133,12 +150,22 @@ class GSMConfig {
const L2Frame& SI2Frame() const { return mSI2Frame; }
const L2Frame& SI3Frame() const { return mSI3Frame; }
const L2Frame& SI4Frame() const { return mSI4Frame; }
const L2Frame& SI13Frame() const { return mSI13Frame; } // pat added for GPRS
//@}
/**@name Get references to L3 frames for SACCH SI messages. */
//@{
const L3Frame& SI5Frame() const { return mSI5Frame; }
const L3Frame& SI6Frame() const { return mSI6Frame; }
//@}
/**@name Get the messages themselves. */
//@{
const L3SystemInformationType1* SI1() const { return mSI1; }
const L3SystemInformationType2* SI2() const { return mSI2; }
const L3SystemInformationType3* SI3() const { return mSI3; }
const L3SystemInformationType4* SI4() const { return mSI4; }
const L3SystemInformationType5* SI5() const { return mSI5; }
const L3SystemInformationType6* SI6() const { return mSI6; }
//@}
/** Get the current master clock value. */
Time time() const { return mClock.get(); }
@@ -151,6 +178,7 @@ class GSMConfig {
unsigned NCC() const { return mNCC; }
GSM::Clock& clock() { return mClock; }
const L3LocationAreaIdentity& LAI() const { return mLAI; }
unsigned changemark() const { return mChangemark; }
//@}
/** Return the BSIC, NCC:BCC. */
@@ -162,6 +190,12 @@ class GSMConfig {
*/
void regenerateBeacon();
/**
SI5 is generated separately because it may get random
neighbors added each time it's sent.
*/
void regenerateSI5();
/**
Hold off on channel allocations; don't answer RACH.
@param val true to hold, false to clear hold
@@ -196,8 +230,28 @@ class GSMConfig {
void addPCH(CCCHLogicalChannel* wCCCH) { mPCHPool.push_back(wCCCH); }
/** Return a minimum-load AGCH. */
// (pat) TODO: This strategy needs to change.
// There needs to be a common message queue for all CCCH timeslots from which the
// FEC can pull the next AGCH message if there is no paging message at that paging slot.
// And if someone besides pat works on this, note that gprs also wants
// to be able cancel messages after sending them in case conditions have changed,
// and also needs to know, a-priori, the exact frame number when the message
// is going to be sent, none of which works properly at the moment.
CCCHLogicalChannel* getAGCH() { return minimumLoad(mAGCHPool); }
#if ENABLE_PAGING_CHANNELS
///< (pat) Send a paging message for the specified imsi.
// This function should be used instead of getPCH(), etc. which should then be made private.
void sendPCH(const L3RRMessage& msg,unsigned imsiMod1000);
///< (pat) Return the approximate time of the next PCH message for this imsi.
// This routine should be elided after DRX mode in GPRS is fixed.
Time getPchSendTime(imsiMod1000);
///< (pat) Send a message on the avail AGCH.
void sendAGCH(const L3RRMessage& msg);
#endif
/** Return a minimum-load PCH. */
CCCHLogicalChannel* getPCH() { return minimumLoad(mPCHPool); }
@@ -224,6 +278,17 @@ class GSMConfig {
//@}
/**@ Manage the CBCH. */
//@{
/** The add method is not mutex protected and should only be used during initialization. */
void addCBCH(CBCHLogicalChannel *wCBCH)
{ assert(mCBCH==NULL); mCBCH=wCBCH; }
CBCHLogicalChannel* getCBCH() { return mCBCH; }
//@}
/**@name Manage SDCCH Pool. */
//@{
/** The add method is not mutex protected and should only be used during initialization. */
@@ -245,11 +310,12 @@ class GSMConfig {
/** The add method is not mutex protected and should only be used during initialization. */
void addTCH(TCHFACCHLogicalChannel *wTCH) { mTCHPool.push_back(wTCH); }
/** Return a pointer to a usable channel. */
TCHFACCHLogicalChannel *getTCH();
TCHFACCHLogicalChannel *getTCH(bool forGPRS=false, bool onlyCN0=false);
int getTCHGroup(int groupSize,TCHFACCHLogicalChannel **results);
/** Return true if an TCH is available, but do not allocate it. */
size_t TCHAvailable() const;
/** Return number of total TCH. */
unsigned TCHTotal() const { return mTCHPool.size(); }
unsigned TCHTotal() const;
/** Return number of active TCH. */
unsigned TCHActive() const;
/** Just a reference to the TCH pool. */
@@ -271,6 +337,9 @@ class GSMConfig {
void createCombinationI(TransceiverManager &TRX, unsigned CN, unsigned TN);
/** Combination VII is 8 SDCCHs. */
void createCombinationVII(TransceiverManager &TRX, unsigned CN, unsigned TN);
/** Combination XIII is a GPRS PDTCH: PDTCH/F+PACCH/F+PTCCH/F */
// pat todo: This does not exist yet.
void createCombinationXIII(TransceiverManager &TRX, unsigned CN, unsigned TN);
//@}
/** Return number of seconds since starting. */

File diff suppressed because it is too large Load Diff

View File

@@ -2,31 +2,25 @@
* Copyright 2008-2010 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING 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.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribuion.
*/
#ifndef GSML1FEC_H
#define GSML1FEC_H
#include "Defines.h"
#include "Threads.h"
#include <assert.h>
@@ -36,14 +30,18 @@
#include "GSMTransfer.h"
#include "GSMTDMA.h"
#include "a53.h"
#include "A51.h"
#include "GSM610Tables.h"
#include <Globals.h>
#include "../GPRS/GPRSExport.h"
class ARFCNManager;
namespace GSM {
@@ -61,9 +59,6 @@ class SACCHL1Decoder;
class SACCHL1FEC;
class TrafficTranscoder;
/*
Naming convention for bit vectors follows GSM 05.03 Section 2.2.
d[k] data
@@ -74,12 +69,19 @@ class TrafficTranscoder;
*/
enum EncryptionType {
ENCRYPT_NO,
ENCRYPT_MAYBE,
ENCRYPT_YES
};
/**
Abstract class for L1 encoders.
In most subclasses, writeHighSide() drives the processing.
(pat) base class for: XCCHL1Encoder, GeneratorL1Encoder
*/
class L1Encoder {
@@ -105,19 +107,31 @@ class L1Encoder {
/**@ Internal state. */
//@{
// (pat) The way this works is rollForward() sets mNextWriteTime to the next
// frame time specified in mMapping. Each logical channel combination has a
// custom serviceloop function running in a separate thread to multiplex the downstream data,
// and send an appropriate frame to ARFCNManager::writeHighSideTx.
// This is totally unlike decoders, for which AFCNManager:receiveBurst uses
// the encoder mapping (which it has cached) to send incoming bursts directly
// to the mapped L1Decoder::writeLowSideRx() for each frame.
unsigned mTotalBursts; ///< total bursts sent since last open()
GSM::Time mPrevWriteTime; ///< timestamp of pervious generated burst
GSM::Time mNextWriteTime; ///< timestamp of next generated burst
volatile bool mRunning; ///< true while the service loop is running
bool mActive; ///< true between open() and close()
//@}
ViterbiR2O4 mVCoder; ///< nearly all GSM channels use the same convolutional code
// (pat) Moved to classes that need the convolutional coder.
//ViterbiR2O4 mVCoder; ///< nearly all GSM channels use the same convolutional code
char mDescriptiveString[100];
public:
EncryptionType mEncrypted;
int mEncryptionAlgorithm;
/**
The basic encoder constructor.
@param wCN carrier index.
@@ -136,6 +150,10 @@ class L1Encoder {
mDownstream=wDownstream;
}
ARFCNManager *getRadio() { return mDownstream; }
// Used by XCCHEncoder
void transmit(BitVector *mI, BitVector *mE, const int *qbits);
/**@name Accessors. */
//@{
const TDMAMapping& mapping() const { return mMapping; }
@@ -155,6 +173,9 @@ class L1Encoder {
/** Open the channel for a new transaction. */
virtual void open();
/** Set mDownstream handover correlator mode. */
void handoverPending(bool flag);
/**
Returns true if the channel is in use by a transaction.
For broadcast and unicast channels this is always true.
@@ -174,6 +195,10 @@ class L1Encoder {
const char* descriptiveString() const { return mDescriptiveString; }
L1FEC* parent() { return mParent; }
GSM::Time getNextWriteTime() { resync(); return mNextWriteTime; }
protected:
/** Roll write times forward to the next positions. */
@@ -200,16 +225,18 @@ class L1Encoder {
};
/**
An abstract class for L1 decoders.
writeLowSide() drives the processing.
writeLowSideRx() drives the processing.
// (pat) base class for: RACHL1Decoder, XCCHL1Decoder
// It would be more elegant to split this into two classes: a base class
// for both GPRS and RR, and the rest of this class that is RR specific.
*/
class L1Decoder {
protected:
// (pat) Not used for GPRS
SAPMux * mUpstream;
/**@name Mutex-controlled state information. */
@@ -220,6 +247,7 @@ class L1Decoder {
Z100Timer mT3101; ///< timer for new channels
Z100Timer mT3109; ///< timer for existing channels
Z100Timer mT3111; ///< timer for reuse of a closed channel
Z100Timer mT3103; ///< timer for handover
//@}
bool mActive; ///< true between open() and close()
//@}
@@ -230,6 +258,7 @@ class L1Decoder {
volatile bool mRunning; ///< true if all required service threads are started
volatile float mFER; ///< current FER estimate
static const int mFERMemory=20; ///< FER decay time, in frames
volatile bool mHandoverPending; ///< if true, we are decoding handover bursts
//@}
/**@name Parameters fixed by the constructor, not requiring mutex protection. */
@@ -240,7 +269,13 @@ class L1Decoder {
L1FEC* mParent; ///< a containing L1 processor, if any
//@}
ViterbiR2O4 mVCoder; ///< nearly all GSM channels use the same convolutional code
// (pat) Moved to classes that use the convolutional coder.
//ViterbiR2O4 mVCoder; ///< nearly all GSM channels use the same convolutional code
EncryptionType mEncrypted;
int mEncryptionAlgorithm;
unsigned char mKc[8];
int mFN[8];
public:
@@ -254,11 +289,14 @@ class L1Decoder {
L1Decoder(unsigned wCN, unsigned wTN, const TDMAMapping& wMapping, L1FEC* wParent)
:mUpstream(NULL),
mT3101(T3101ms),mT3109(T3109ms),mT3111(T3111ms),
mT3103(gConfig.getNum("GSM.Timer.T3103")),
mActive(false),
mRunning(false),
mFER(0.0F),
mCN(wCN),mTN(wTN),
mMapping(wMapping),mParent(wParent)
mMapping(wMapping),mParent(wParent),
mEncrypted(ENCRYPT_NO),
mEncryptionAlgorithm(0)
{
// Start T3101 so that the channel will
// become recyclable soon.
@@ -291,7 +329,7 @@ class L1Decoder {
bool recyclable() const;
/** Connect the upstream SAPMux and L2. */
void upstream(SAPMux * wUpstream)
virtual void upstream(SAPMux * wUpstream)
{
assert(mUpstream==NULL); // Only call this once.
mUpstream=wUpstream;
@@ -304,20 +342,30 @@ class L1Decoder {
const TDMAMapping& mapping() const { return mMapping; }
/** Accept an RxBurst and process it into the deinterleaver. */
virtual void writeLowSide(const RxBurst&) = 0;
virtual void writeLowSideRx(const RxBurst&) = 0;
/**@name Components of the channel description. */
//@{
unsigned TN() const { return mTN; }
unsigned ARFCN() const; ///< this comes from mUpstream
TypeAndOffset typeAndOffset() const; ///< this comes from mMapping
unsigned ARFCN() const; ///< this comes from mUpstream
TypeAndOffset typeAndOffset() const; ///< this comes from mMapping
//@}
/** Control the processing of handover access busts. */
void handoverPending(bool flag)
{
if (flag) mT3103.set();
mHandoverPending=flag;
}
public:
L1FEC* parent() { return mParent; } // pat thinks it is not used virtual.
/** How much time left in T3101? */
long debug3101remaining() { return mT3101.remaining(); }
protected:
virtual L1FEC* parent() { return mParent; }
/** Return pointer to paired L1 encoder, if any. */
virtual L1Encoder* sibling();
@@ -327,9 +375,12 @@ class L1Decoder {
/** Mark the decoder as started. */
virtual void start() { mRunning=true; }
public:
void countGoodFrame();
void countBadFrame();
bool decrypt_maybe(string wIMSI, int wA5Alg);
unsigned char *kc() { return mKc; }
};
@@ -338,6 +389,96 @@ class L1Decoder {
/**
The L1FEC encapsulates an encoder and decoder.
Notes by pat 8/2011:
A complete L2 <-> L1 handler includes a set of instances of classes L1FEC, L1Encoder, L1Decoder.
These are always wrapped by an instance of LogicalChannel, which defines the
complete L3 <-> L1 handler. The L1<->L2 handling is quite different for different
logical channels, so all these classes are always over-ridden by more specific ones
for each logical channel. The descendents of L1Encoder/L2Decoder classes
are not just encoders/decoders; together with the associated LogicalChannel class
they incorporate the complete upstream and downstream channel handler.
Initialization:
All these instances are immortal (unlike GPRS PDCHL1FEC, which is allocated/deallocated
on demand.) The mEncoder and mDecoder below are set once
and never changed, to define the related set of L1FEC+L1Encoder+L2Decoder.
At startup, GSMConfig uses info from the tables in GPRSTDMA
to create a complete set of instances of all these classes for each logical channel,
in each physical channel to which they apply. (The C0T0 beach gets a different
set of classes than TCH Traffic channels, but every LogicalChannel descendent has
its own distinct set of L1FEC+L1Encoder+L1Decoder descendents.)
Note that there is an L1FEC+L1Encoder+L1Decoder per logical channel, not per
physical channel; they all share the physical channel resource, as described below.
The downstream end is connected to ARFCNManager in TRXManager.cpp.
The upstream end goes various places, connected at runtime through SAPMux,
or for some classes (example: RACH), directly to low-level managers.
See also documentation in LogicalChannel::send().
L2 -> L1 data flow is as follows:
L2 calls SAPMux::writeHighSide(L2Frame),
which calls L1FEC::writeHighSide(L2Frame),
<or> L2 calls L1FEC::writeHighSide(L2Frame) directly,
which then calls (L1Encoder)mEncoder->writeHighSide(L2Frame)
This is overridden to provide the logical channel specific handling,
which is performed by descendents of L1Encoder. The frames may be processed
at that point (for example, cause RR setup/teardown based on the frame primitive)
or be passed downstream, in which case they usually go through sendFrame() below,
which is over-ridden to provide the logical-channel specific encoding.
Eventually, downstream frames go to L1Encoder::writeHighSideTx, which
delivers them to the ARFCNManager.
They may be delivered directly or spend time in an InterThreadQueue,
which is processed by a serviceLoop, (which may reside either in the L1Encoder
or LogicalChannel descendent) to synchronize them to the BTS frame clock
(by using rollForward() to set mPrevTime, mNextTime, and then waitToSend() to block.)
L1 -> L2 data flow is as follows:
In TRXManager, the mDemuxTable, which was initialized from the GSMTDMA frame data,
is consulted to pass the radio burst to the appropriate logical channel, using
L1FEC::writeLowSideRx(RxBurst) in the appropriate L1FEC descendent.
From there, anything can happen. Four bursts need to be assembled and decoded.
For TCH, FACH and SACH, this happens in (L1Decoder descendent)::processBurst(),
which then calls countGoodFrame()+handleGoodFrame() or countBadFrame() if the
parity was wrong. handleGoodFrame() does the L1 housekeeping (start/stop timers,
remember power/timing parameters) then passes the frame up using SAPMux->writeLowSide(),
which calls some descendent L2DL.
For RACH, writeLowSideRx decodes the burst and sends a message directly
to gBTS.channelRequest(), which enqueues them for eventual processing
by AccessGrantResponder().
Routines:
The start() routine is usually called once to create a thread to start a serviceloop thread.
Radio bursts are then delivered to the class endpoints forever.
The channels are turned on/off by calling open()/close(), which sets the active flag
to determine whether they will process those bursts or drop them.
GPRS Support:
The "L2Frame" used ubiquitously in this code is a GSM-specific L2 frame.
Now we want to add GPRS support with a new frame structure.
I split the XCCHL1encoder/XCCHL1decoder classes into separate parts for handling
the logical channel flow, which remained in the original classes, and the
actual data encoding/decoding, which moved to SharedL1Encoder/SharedL2Encoder.
The new SharedL1Encoder/SharedL2Encoder are shared with GPRS.
Almost all the other functions in the L1Encoder/L2Decoder are different for GPRS
because the channel is shared by multiple MS. So GPRS has its own
set of classes: PDCHL1FEC, PDCHL1Uplink, PDCHL1Downlink.
Notice that the frame numbers used by GPRS for Radio Blocks are identical to the
data frame numbers for GSM RR TCH channels. Similarly, the GPRS timing advance channels
use the same frame numbers as GPRS RR SACCH (although we dont use those yet.)
We will allocate the GPRS channels dynamically from the TCH pool using
getTCH to allocate an existing TCH LogicalChannel class, which wont otherwise
be used for GPRS, except to return to the pool when GPRS signs off the channel.
The L1Decoder/L1Encoder classes will now be three state: inactive, active for RR,
active for GPRS. Uplink data will be diverted to GPRS code at the earliest point
possible, which is in XCCHL1Decoder::writeLowSideRx().
Another option was to completely bypass this code, modifing TRXManager,
either by changing the mDemuxTable to send radio bursts directly to the GPRS code, or
adding a new hook to simply send the entire timeslot to GPRS.
We might still want to go back and do that at some point, possibly when
we implement continuous timing advance.
*/
class L1FEC {
@@ -347,31 +488,51 @@ class L1FEC {
L1Decoder* mDecoder;
public:
// The mGprsReserved variable prevents the GSM subsystem from using the channel.
// When the GPRS PDCHL1FEC is ready to receive bursts, it sets mGPRSFEC.
bool mGprsReserved; // If set, channel reserved for GPRS.
GPRS::PDCHL1FEC *mGPRSFEC; // If set, bursts are delivered to GPRS.
// Currently, this could go in TCHFACCHL1Decoder instead.
/**
The L1FEC constructor is over-ridden for different channel types.
But the default has no encoder or decoder.
*/
L1FEC():mEncoder(NULL),mDecoder(NULL) {}
L1FEC():mEncoder(NULL),mDecoder(NULL)
, mGprsReserved(0)
, mGPRSFEC(0)
{}
/** This is no-op because these channels should not be destroyed. */
/** This is no-op because these channels should not be destroyed.
(pat) We may allocate/deallocate GPRS channels on demand,
stealing GSM channels, so above statement may become untrue.
*/
virtual ~L1FEC() {};
/** Send in an RxBurst for decoding. */
void writeLowSide(const RxBurst& burst)
{ assert(mDecoder); mDecoder->writeLowSide(burst); }
// (pat) I dont think this is ever called. Gotta love C++
void writeLowSideRx(const RxBurst& burst)
{ assert(mDecoder); mDecoder->writeLowSideRx(burst); }
/** Send in an L2Frame for encoding and transmission. */
void writeHighSide(const L2Frame& frame)
{ assert(mEncoder); mEncoder->writeHighSide(frame); }
// (pat) not used for GPRS.
virtual void writeHighSide(const L2Frame& frame)
{
assert(mEncoder); mEncoder->writeHighSide(frame);
}
/** Attach L1 to a downstream radio. */
void downstream(ARFCNManager*);
/** Attach L1 to an upstream SAPI mux and L2. */
void upstream(SAPMux* mux)
// (pat) not used for GPRS.
virtual void upstream(SAPMux* mux)
{ if (mDecoder) mDecoder->upstream(mux); }
/** set encoder and decoder handover pending mode. */
void handoverPending(bool flag);
/**@name Ganged actions. */
//@{
void open();
@@ -379,34 +540,37 @@ class L1FEC {
//@}
/**@name Pass-through actions. */
/**@name Pass-through actions that concern the physical channel. */
//@{
TypeAndOffset typeAndOffset() const
{ assert(mEncoder); return mEncoder->typeAndOffset(); }
unsigned TN() const
unsigned TN() const // Timeslot number to use.
{ assert(mEncoder); return mEncoder->TN(); }
unsigned CN() const
unsigned CN() const // Carrier index.
{ assert(mEncoder); return mEncoder->CN(); }
unsigned TSC() const
unsigned TSC() const // Trainging sequence for this channel.
{ assert(mEncoder); return mEncoder->TSC(); }
unsigned ARFCN() const
unsigned ARFCN() const // Absolute Radio Frequence Channel Number.
{ assert(mEncoder); return mEncoder->ARFCN(); }
float FER() const
float FER() const // Frame Error Rate
{ assert(mDecoder); return mDecoder->FER(); }
bool recyclable() const
bool recyclable() const // Can we reuse this channel yet?
{ assert(mDecoder); return mDecoder->recyclable(); }
bool active() const;
bool active() const; // Channel in use? See L1Encoder
// (pat) This lovely function is unsed.
// TRXManager.cpp:installDecoder uses L1Decoder::mapping() directly.
const TDMAMapping& txMapping() const
{ assert(mEncoder); return mEncoder->mapping(); }
// (pat) This function is unsed.
const TDMAMapping& rcvMapping() const
{ assert(mDecoder); return mDecoder->mapping(); }
@@ -415,6 +579,11 @@ class L1FEC {
//@}
//void setDecoder(L1Decoder*me) { mDecoder = me; }
//void setEncoder(L1Encoder*me) { mEncoder = me; }
ARFCNManager *getRadio() { return mEncoder->getRadio(); }
bool inUseByGPRS() { return mGprsReserved; }
void setGPRS(bool reserved, GPRS::PDCHL1FEC *pch) { mGprsReserved = reserved; mGPRSFEC = pch; }
L1Decoder* decoder() { return mDecoder; }
L1Encoder* encoder() { return mEncoder; }
@@ -433,7 +602,7 @@ class TestL1FEC : public L1FEC {
public:
void writeLowSide(const RxBurst&);
void writeLowSideRx(const RxBurst&);
void writeHighSide(const L2Frame&);
void downstream(ARFCNManager *wDownstream) { mDownstream=wDownstream; }
@@ -442,12 +611,14 @@ class TestL1FEC : public L1FEC {
/** L1 decoder for Random Access (RACH). */
class RACHL1Decoder : public L1Decoder {
class RACHL1Decoder : public L1Decoder
{
private:
/**@name FEC state. */
//@{
ViterbiR2O4 mVCoder; ///< nearly all GSM channels use the same convolutional code
Parity mParity; ///< block coder
BitVector mU; ///< u[], as per GSM 05.03 2.2
BitVector mD; ///< d[], as per GSM 05.03 2.2
@@ -456,6 +627,9 @@ class RACHL1Decoder : public L1Decoder {
// The RACH channel uses an internal FIFO,
// because the channel allocation process might block
// and we don't want to block the radio receive thread.
// (pat) I dont think this is used. I think TRXManager calls writeLowSideRx directly.
// The serviceLoop is still started, and watches mQ forever, hopefully
// waiting for a burst that never comes.
RxBurstFIFO mQ; ///< a FIFO to decouple the rx thread
Thread mServiceThread; ///< a thread to process the FIFO
@@ -473,7 +647,7 @@ class RACHL1Decoder : public L1Decoder {
void start();
/** Decode the burst and call the channel allocator. */
void writeLowSide(const RxBurst&);
void writeLowSideRx(const RxBurst&);
/** A loop to watch the FIFO. */
void serviceLoop();
@@ -486,14 +660,105 @@ void *RACHL1DecoderServiceLoopAdapter(RACHL1Decoder*);
// This is just an encoder, nothing else, shared by RR and GPRS.
// This is the encoder specified in GSM05.03 sec 4.1, used for SACCH and GPRS CS-1.
// Why isnt this derived directly from L1Encoder, you ask?
// First it was because GPRS has multiple encoders for different encoding schemes
// and they all use a single L1Encoder attached to the radio.
// Second, because the GSM L1Encoder is not just an encoder, it is the complete stack
// down to the radio, whereas this class is just an encoder only.
// First case above is now inapplicable because the additional GPRS encoders are now
// derived from this one.
class SharedL1Encoder
{
protected:
ViterbiR2O4 mVCoder; ///< nearly all GSM channels use the same convolutional code
Parity mBlockCoder;
BitVector mC; ///< c[], as per GSM 05.03 2.2
BitVector mU; ///< u[], as per GSM 05.03 2.2
//BitVector mDP; ///< d[]:p[] (data & parity)
BitVector mP; ///< p[], as per GSM 05.03 2.2
public:
BitVector mD; ///< d[], as per GSM 05.03 2.2 Incoming Data.
BitVector mI[4]; ///< i[][], as per GSM 05.03 2.2 Outgoing Data.
BitVector mE[4];
/**
Encode u[] to c[].
Includes LSB-MSB reversal within each octet.
*/
void encode41();
/**
Interleave c[] to i[].
GSM 05.03 4.1.4.
It is not virtual.
*/
void interleave41();
public:
SharedL1Encoder();
//void encodeFrame41(const L2Frame &frame, int offset);
void encodeFrame41(const BitVector &frame, int offset, bool copy=true);
void initInterleave(int);
};
// Shared by RR and GPRS
class SharedL1Decoder
{
protected:
/**@name FEC state. */
//@{
ViterbiR2O4 mVCoder; ///< nearly all GSM channels use the same convolutional code
Parity mBlockCoder;
public:
SoftVector mC; ///< c[], as per GSM 05.03 2.2
BitVector mU; ///< u[], as per GSM 05.03 2.2
BitVector mP; ///< p[], as per GSM 05.03 2.2
BitVector mDP; ///< d[]:p[] (data & parity)
public:
BitVector mD; ///< d[], as per GSM 05.03 2.2
SoftVector mE[4];
SoftVector mI[4]; ///< i[][], as per GSM 05.03 2.2
/**@name Handover Access Burst FEC state. */
//@{
Parity mHParity; ///< block coder for handover access bursts
BitVector mHU; ///< u[] for handover access, as per GSM 05.03 4.6
BitVector mHD; ///< d[] for handover access, as per GSM 05.03 4.6
//@}
//@}
GSM::Time mReadTime; ///< timestamp of the first burst
public:
SharedL1Decoder();
void deinterleave();
bool decode();
SoftVector *result() { return mI; }
};
/** Abstract L1 decoder for most control channels -- GSM 05.03 4.1 */
class XCCHL1Decoder : public L1Decoder {
class XCCHL1Decoder :
public SharedL1Decoder,
public L1Decoder
{
protected:
// Moved to SharedL1Decoder
#if 0
/**@name FEC state. */
//@{
Parity mBlockCoder;
/**@name Normal Burst FEC state. */
//@{
Parity mBlockCoder; ///< block coder for normal bursts
SoftVector mI[4]; ///< i[][], as per GSM 05.03 2.2
SoftVector mC; ///< c[], as per GSM 05.03 2.2
BitVector mU; ///< u[], as per GSM 05.03 2.2
@@ -501,15 +766,24 @@ class XCCHL1Decoder : public L1Decoder {
BitVector mDP; ///< d[]:p[] (data & parity)
BitVector mD; ///< d[], as per GSM 05.03 2.2
//@}
GSM::Time mReadTime; ///< timestamp of the first burst
unsigned mRSSIHistory[4];
/**@name Handover Access Burst FEC state. */
//@{
Parity mHParity; ///< block coder for handover access bursts
BitVector mHU; ///< u[] for handover access, as per GSM 05.03 4.6
BitVector mHD; ///< d[] for handover access, as per GSM 05.03 4.6
//@}
//@}
#endif
public:
XCCHL1Decoder(unsigned wCN, unsigned wTN, const TDMAMapping& wMapping,
L1FEC *wParent);
void saveMi();
void restoreMi();
void decrypt();
protected:
/** Offset to the start of the L2 header. */
@@ -519,7 +793,7 @@ class XCCHL1Decoder : public L1Decoder {
virtual ChannelType channelType() const = 0;
/** Accept a timeslot for processing and drive data up the chain. */
virtual void writeLowSide(const RxBurst&);
virtual void writeLowSideRx(const RxBurst&);
/**
Accept a new timeslot for processing and save it in i[].
@@ -529,6 +803,8 @@ class XCCHL1Decoder : public L1Decoder {
*/
virtual bool processBurst(const RxBurst&);
// Moved to SharedL1Encoder.
#if 0
/**
Deinterleave the i[] to c[].
This virtual method works for all block-interleaved channels (xCCHs).
@@ -542,6 +818,7 @@ class XCCHL1Decoder : public L1Decoder {
@return True if frame passed parity check.
*/
bool decode();
#endif
/** Finish off a properly-received L2Frame in mU and send it up to L2. */
virtual void handleGoodFrame();
@@ -567,8 +844,6 @@ class SDCCHL1Decoder : public XCCHL1Decoder {
};
/**
L1 decoder for the SACCH.
Like any other control channel, but with hooks for power/timing control.
@@ -578,9 +853,9 @@ class SACCHL1Decoder : public XCCHL1Decoder {
private:
SACCHL1FEC *mSACCHParent;
unsigned mRSSICounter;
volatile float mRSSI[4]; ///< RSSI history , dB wrt full scale
volatile float mTimingError[4]; ///< Timing error histoty in symbol
volatile float mRSSI; ///< most recent RSSI, dB wrt full scale
volatile float mTimingError; ///< Timing error history in symbols
volatile double mTimestamp; ///< system time of most recent received burst
volatile int mActualMSPower; ///< actual MS tx power in dBm
volatile int mActualMSTiming; ///< actual MS tx timing advance in symbols
@@ -593,10 +868,12 @@ class SACCHL1Decoder : public XCCHL1Decoder {
SACCHL1FEC *wParent)
:XCCHL1Decoder(wCN,wTN,wMapping,(L1FEC*)wParent),
mSACCHParent(wParent),
mRSSICounter(0)
{
for (int i=0; i<4; i++) mRSSI[i]=0.0F;
}
mRSSI(0.0F),
mTimingError(0.0F),
mTimestamp(0.0),
mActualMSPower(0),
mActualMSTiming(0)
{ }
ChannelType channelType() const { return SACCHType; }
@@ -612,18 +889,24 @@ class SACCHL1Decoder : public XCCHL1Decoder {
bool processBurst(const RxBurst&);
/** Set pyshical parameters for initialization. */
void setPhy(float wRSSI, float wTimingError);
void setPhy(float wRSSI, float wTimingError, double wTimestamp);
void setPhy(const SACCHL1Decoder& other);
/** RSSI of most recent received burst, in dB wrt full scale. */
float RSSI() const;
float RSSI() const { return mRSSI; }
/** Artificially push down RSSI to induce the handset to push more power. */
void RSSIBumpDown(float dB) { mRSSI -= dB; }
/**
Timing error of most recent received burst, symbol units.
Positive is late; negative is early.
*/
float timingError() const;
float timingError() const { return mTimingError; }
/** Timestamp of most recent received burst. */
double timestamp() const { return mTimestamp; }
protected:
@@ -645,10 +928,15 @@ class SACCHL1Decoder : public XCCHL1Decoder {
/** L1 encoder used for many control channels -- mostly from GSM 05.03 4.1 */
class XCCHL1Encoder : public L1Encoder {
class XCCHL1Encoder :
public SharedL1Encoder,
public L1Encoder
{
protected:
// Moved to SharedL1Encoder
#if 0
/**@name FEC signal processing state. */
//@{
Parity mBlockCoder; ///< block coder for this channel
@@ -658,6 +946,7 @@ class XCCHL1Encoder : public L1Encoder {
BitVector mD; ///< d[], as per GSM 05.03 2.2
BitVector mP; ///< p[], as per GSM 05.03 2.2
//@}
#endif
public:
@@ -670,6 +959,7 @@ class XCCHL1Encoder : public L1Encoder {
protected:
/** Process pending incoming messages. */
// (pat) Messages may be control primitives. If it is data, it is passed to sendFrame()
virtual void writeHighSide(const L2Frame&);
/** Offset from the start of mU to the start of the L2 frame. */
@@ -677,7 +967,9 @@ class XCCHL1Encoder : public L1Encoder {
/** Send a single L2 frame. */
virtual void sendFrame(const L2Frame&);
// Moved to SharedL1Encoder
//virtual void transmit(BitVector *mI);
#if 0
/**
Encode u[] to c[].
Includes LSB-MSB reversal within each octet.
@@ -697,6 +989,7 @@ class XCCHL1Encoder : public L1Encoder {
GSM 05.03 4.1.5, 05.02 5.2.3.
*/
virtual void transmit();
#endif
};
@@ -710,6 +1003,9 @@ private:
bool mPreviousFACCH; ///< A copy of the previous stealing flag state.
size_t mOffset; ///< Current deinterleaving offset.
BitVector mE[8];
// (pat) Yes, the mI here duplicates but overrides the same
// vector down in XCCHL1Encoder.
BitVector mI[8]; ///< deinterleaving history, 8 blocks instead of 4
BitVector mTCHU; ///< u[], but for traffic
BitVector mTCHD; ///< d[], but for traffic
@@ -743,8 +1039,12 @@ public:
protected:
// GSM 05.03, 3.1.3
void interleave31(int blockOffset);
#if 0
/** Interleave c[] to i[]. GSM 05.03 4.1.4. */
virtual void interleave(int blockOffset);
virtual void interleave31(int blockOffset);
#endif
/** Encode a FACCH and enqueue it for transmission. */
void sendFrame(const L2Frame&);
@@ -773,6 +1073,7 @@ class TCHFACCHL1Decoder : public XCCHL1Decoder {
protected:
SoftVector mE[8]; ///< deinterleaving history, 8 blocks instead of 4
SoftVector mI[8]; ///< deinterleaving history, 8 blocks instead of 4
BitVector mTCHU; ///< u[] (uncoded) in the spec
BitVector mTCHD; ///< d[] (data) in the spec
@@ -780,8 +1081,8 @@ class TCHFACCHL1Decoder : public XCCHL1Decoder {
BitVector mClass1A_d; ///< the class 1A part of d[]
SoftVector mClass2_c; ///< the class 2 part of c[]
VocoderFrame mVFrame; ///< unpacking buffer for vocoder frame
unsigned char mPrevGoodFrame[33]; ///< previous good frame.
VocoderFrame mVFrame; ///< unpacking buffer for current vocoder frame
VocoderFrame mPrevGoodFrame; ///< previous good frame
Parity mTCHParity;
@@ -798,17 +1099,22 @@ class TCHFACCHL1Decoder : public XCCHL1Decoder {
/** TCH/FACCH has a special-case writeLowSide. */
void writeLowSide(const RxBurst& inBurst);
void writeLowSideRx(const RxBurst& inBurst);
/**
Unlike other DCCHs, TCH/FACCH process burst calls
deinterleave, decode, handleGoodFrame.
*/
bool processBurst( const RxBurst& );
void saveMi();
void restoreMi();
void decrypt(int B);
/** Deinterleave i[] to c[]. */
void deinterleave(int blockOffset );
// (pat) Routine does not exist.
void replaceFACCH( int blockOffset );
/**
@@ -837,7 +1143,9 @@ class TCHFACCHL1Decoder : public XCCHL1Decoder {
This is base class for output-only encoders.
These all have very thin L2/L3 and are driven by a clock instead of a FIFO.
*/
class GeneratorL1Encoder : public L1Encoder {
class GeneratorL1Encoder :
public L1Encoder
{
private:
@@ -880,7 +1188,7 @@ void *GeneratorL1EncoderServiceLoopAdapter(GeneratorL1Encoder*);
class SCHL1Encoder : public GeneratorL1Encoder {
private:
ViterbiR2O4 mVCoder; ///< nearly all GSM channels use the same convolutional code
Parity mBlockCoder; ///< block parity coder
BitVector mU; ///< u[], as per GSM 05.03 2.2
BitVector mE; ///< e[], as per GSM 05.03 2.2
@@ -975,7 +1283,6 @@ class BCCHL1Encoder : public NDCCHL1Encoder {
};
/**
L1 decoder for the SACCH.
Like any other control channel, but with hooks for power/timing control.
@@ -1171,10 +1478,12 @@ class SACCHL1FEC : public L1FEC {
//@{
float RSSI() const { return mSACCHDecoder->RSSI(); }
float timingError() const { return mSACCHDecoder->timingError(); }
double timestamp() const { return mSACCHDecoder->timestamp(); }
int actualMSPower() const { return mSACCHDecoder->actualMSPower(); }
int actualMSTiming() const { return mSACCHDecoder->actualMSTiming(); }
void setPhy(const SACCHL1FEC&);
virtual void setPhy(float RSSI, float timingError);
virtual void setPhy(float RSSI, float timingError, double wTimestamp);
void RSSIBumpDown(int dB) { mSACCHDecoder->RSSIBumpDown(dB); }
//@}
};

View File

@@ -1,24 +1,16 @@
/*
* Copyright 2008, 2009 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -43,6 +35,7 @@ implementation, although no code is copied directly.
#include "GSML2LAPDm.h"
#include "GSMSAPMux.h"
#include <Logger.h>
#include <GSML3RRMessages.h>
using namespace std;
using namespace GSM;
@@ -72,7 +65,7 @@ void CCCHL2::writeHighSide(const GSM::L3Frame& l3)
assert(mDownstream);
assert(l3.primitive()==UNIT_DATA);
L2Header header(L2Length(l3.L2Length()));
mDownstream->writeHighSide(L2Frame(header,l3));
mDownstream->writeHighSide(L2Frame(header,l3,true));
}
@@ -94,6 +87,7 @@ L2LAPDm::L2LAPDm(unsigned wC, unsigned wSAPI)
mIdleFrame.fillField(8*0,(mC<<1)|1,8); // address
mIdleFrame.fillField(8*1,3,8); // control
mIdleFrame.fillField(8*2,1,8); // length
if (gConfig.getBool("GSM.Cipher.ScrambleFiller")) mIdleFrame.randomizeFiller(8*4);
}
@@ -102,7 +96,9 @@ void L2LAPDm::writeL1(const L2Frame& frame)
OBJLOG(DEBUG) <<"L2LAPDm::writeL1 " << frame;
//assert(mDownstream);
if (!mDownstream) return;
ScopedLock lock(mLock);
// It is tempting not to lock this, but if we don't,
// the ::open operation can result in contention in L1.
ScopedLock lock(mL1Lock);
mDownstream->writeHighSide(frame);
}
@@ -288,13 +284,16 @@ void L2LAPDm::open()
OBJLOG(DEBUG);
{
ScopedLock lock(mLock);
OBJLOG(DEBUG);
if (!mRunning) {
OBJLOG(DEBUG);
// We can't call this from the constructor,
// since N201 may not be defined yet.
mMaxIPayloadBits = 8*N201(L2Control::IFormat);
mRunning = true;
mUpstreamThread.start((void *(*)(void*))LAPDmServiceLoopAdapter,this);
}
OBJLOG(DEBUG);
mL3Out.clear();
mL1In.clear();
clearCounters();
@@ -302,7 +301,9 @@ void L2LAPDm::open()
mAckSignal.signal();
}
OBJLOG(DEBUG);
if (mSAPI==0) sendIdle();
OBJLOG(DEBUG);
}
@@ -484,6 +485,9 @@ void L2LAPDm::receiveFrame(const GSM::L2Frame& frame)
case L2Control::UFormat: receiveUFrame(frame); break;
}
break;
case HANDOVER_ACCESS:
mL3Out.write(new L3Frame(HANDOVER_ACCESS));
break;
default:
OBJLOG(ERR) << "unhandled primitive in L1->L2 " << frame;
assert(0);
@@ -577,8 +581,7 @@ void L2LAPDm::receiveUFrameSABM(const L2Frame& frame)
}
// Re-establishment procedure, GSM 04.06 5.6.3.
// This basically resets the ack engine.
// We should not actually see this, as of rev 2.4.
OBJLOG(WARNING) << "reestablishment not really supported";
// The most common reason for this is failed handover.
sendUFrameUA(frame.PF());
clearCounters();
break;
@@ -908,12 +911,21 @@ void L2LAPDm::sendUFrameUI(const L3Frame& l3)
L2Control control(L2Control::UFormat,1,0x00);
L2Length length(l3.L2Length());
L2Header header(address,control,length);
writeL1NoAck(L2Frame(header,l3));
L2Frame l2f = L2Frame(header, l3);
// FIXME -
// The correct solution is to build an L2 frame in RadioResource.cpp and control the bits explicitly up there.
// But I don't know if the LogcialChannel class has a method for sending frames directly into L2.
if (l3.PD() == L3RadioResourcePD && l3.MTI() == L3RRMessage::PhysicalInformation) {
l2f.CR(true);
l2f.PF(false);
}
writeL1NoAck(l2f);
}
void L2LAPDm::sendMultiframeData(const L3Frame& l3)
{
// See GSM 04.06 5.8.5
@@ -995,6 +1007,25 @@ bool L2LAPDm::stuckChannel(const L2Frame& frame)
void CBCHL2::writeHighSide(const GSM::L3Frame& l3)
{
OBJLOG(DEBUG) <<"CBCHL2 incoming L3 frame: " << l3;
assert(mDownstream);
assert(l3.primitive()==UNIT_DATA);
assert(l3.size()==88*8);
L2Frame outFrame(DATA);
// Chop the L3 frame into 4 L2 frames.
for (unsigned i=0; i<4; i++) {
outFrame.fillField(0,0x02,4);
outFrame.fillField(4,i,4);
const BitVector thisSeg = l3.segment(i*22*8,22*8);
thisSeg.copyToSegment(outFrame,8);
OBJLOG(DEBUG) << "CBCHL2 outgoing L2 frame: " << outFrame;
mDownstream->writeHighSide(outFrame);
}
}
// vim: ts=4 sw=4

View File

@@ -2,24 +2,16 @@
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2011 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -135,13 +127,38 @@ class CCCHL2 : public L2DL {
void writeLowSide(const GSM::L2Frame&) { assert(0); }
L3Frame* readHighSide(unsigned /*timeout = 3600000*/) { assert(0); return NULL; }
L3Frame* readHighSide(unsigned timeout=3600000) { assert(0); return NULL; }
void writeHighSide(const GSM::L3Frame&);
};
/**
A "thin" L2 for CBCH.
This is a downlink-only channel and does not use LAPDm.
See GSM 04.12 3.3.1.
*/
class CBCHL2 : public L2DL {
public:
unsigned N201(GSM::L2Control::ControlFormat format) const { assert(0); }
unsigned N200() const { return 0; }
void open() {}
void writeLowSide(const GSM::L2Frame&) { assert(0); }
L3Frame* readHighSide(unsigned timeout=3600000) { assert(0); return NULL; }
void writeHighSide(const GSM::L3Frame&);
};
@@ -392,6 +409,7 @@ class L2LAPDm : public L2DL {
- This need not be called when the channel is closed,
as L1 will generate its own filler pattern that is more
appropriate in this condition.
- This does not need to be called for the SACCH or FACCH.
*/
virtual void sendIdle() { writeL1(mIdleFrame); }

View File

@@ -1,25 +1,17 @@
/**@file @brief Call Control messages, GSM 04.08 9.3 */
/**@file
@brief Call Control messages, GSM 04.08 9.3
*/
/*
* Copyright 2008, 2009 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -71,30 +63,40 @@ void L3BearerCapability::text(ostream& os) const
}
void L3BCDDigits::parse(const L3Frame& src, size_t &rp, size_t numOctets)
void L3BCDDigits::parse(const L3Frame& src, size_t &rp, size_t numOctets, bool international)
{
unsigned i=0;
size_t readOctets = 0;
if (international) mDigits[i++] = '+';
while (readOctets < numOctets) {
unsigned d2 = src.readField(rp,4);
unsigned d1 = src.readField(rp,4);
readOctets++;
mDigits[i++]=d1+'0';
if (d2!=0x0f) mDigits[i++]=d2+'0';
mDigits[i++] = d1 == 10 ? '*' : d1 == 11 ? '#' : d1+'0';
if (d2!=0x0f) mDigits[i++] = d2 == 10 ? '*' : d2 == 11 ? '#' : d2+'0';
if (i>maxDigits) L3_READ_ERROR;
}
mDigits[i++]='\0';
}
int encode(char c)
{
return c == '*' ? 10 : c == '#' ? 11 : c-'0';
}
void L3BCDDigits::write(L3Frame& dest, size_t &wp) const
{
unsigned index = 0;
unsigned numDigits = strlen(mDigits);
if (index < numDigits && mDigits[index] == '+') {
index++;
}
while (index < numDigits) {
if ((index+1) < numDigits) dest.writeField(wp,mDigits[index+1]-'0',4);
if ((index+1) < numDigits) dest.writeField(wp,encode(mDigits[index+1]),4);
else dest.writeField(wp,0x0f,4);
dest.writeField(wp,mDigits[index]-'0',4);
dest.writeField(wp,encode(mDigits[index]),4);
index += 2;
}
}
@@ -103,6 +105,7 @@ void L3BCDDigits::write(L3Frame& dest, size_t &wp) const
size_t L3BCDDigits::lengthV() const
{
unsigned sz = strlen(mDigits);
if (*mDigits == '+') sz--;
return (sz/2) + (sz%2);
}
@@ -131,7 +134,7 @@ void L3CalledPartyBCDNumber::parseV( const L3Frame &src, size_t &rp, size_t expe
if (src.readField(rp, 1) != 1) L3_READ_ERROR;
mType = (TypeOfNumber)src.readField(rp, 3);
mPlan = (NumberingPlan)src.readField(rp, 4);
mDigits.parse(src,rp,expectedLength-1);
mDigits.parse(src,rp,expectedLength-1, mType == InternationalNumber);
}
@@ -154,7 +157,7 @@ void L3CallingPartyBCDNumber::writeV( L3Frame &dest, size_t &wp ) const
{
// If Octet3a is extended, then write 0 else 1.
dest.writeField(wp, (!mHaveOctet3a & 0x01), 1);
dest.writeField(wp, mType, 3);
dest.writeField(wp, *digits() == '+' ? InternationalNumber : mType, 3);
dest.writeField(wp, mPlan, 4);
if(mHaveOctet3a){

View File

@@ -2,24 +2,14 @@
/*
* Copyright 2008, 2009 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -71,7 +61,7 @@ class L3BCDDigits {
L3BCDDigits(const char* wDigits) { strncpy(mDigits,wDigits,sizeof(mDigits)-1); mDigits[sizeof(mDigits)-1]='\0'; }
void parse(const L3Frame& src, size_t &rp, size_t numOctets);
void parse(const L3Frame& src, size_t &rp, size_t numOctets, bool international = false);
void write(L3Frame& dest, size_t &wp) const;
/** Return number of octets needed to encode the digits. */
@@ -200,6 +190,9 @@ public:
private:
// FIXME -- This should include any supplied diagnostics.
// See ticket GSM 04.08 10.5.4.11 and ticket #1139.
Location mLocation;
unsigned mCause;

View File

@@ -1,27 +1,19 @@
/** @file Call Control messags, GSM 04.08 9.3. */
/*
* Copyright 2008, 2009, 2011 Free Software Foundation, Inc.
* Copyright 2008, 2009 Free Software Foundation, Inc.
* Copyright 2011 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -57,10 +49,8 @@ ostream& GSM::operator<<(ostream& os, L3CCMessage::MessageType val)
os << "Release Complete"; break;
case L3CCMessage::Setup:
os << "Setup"; break;
case L3CCMessage::EmergencySetup:
os << "Emergency Setup"; break;
case L3CCMessage::CCStatus:
os <<"Status"; break;
os << "Status"; break;
case L3CCMessage::CallConfirmed:
os <<"Call Confirmed"; break;
case L3CCMessage::CallProceeding:
@@ -92,7 +82,6 @@ L3CCMessage * GSM::L3CCFactory(L3CCMessage::MessageType MTI)
case L3CCMessage::Connect: return new L3Connect();
case L3CCMessage::Alerting: return new L3Alerting();
case L3CCMessage::Setup: return new L3Setup();
case L3CCMessage::EmergencySetup: return new L3EmergencySetup();
case L3CCMessage::Disconnect: return new L3Disconnect();
case L3CCMessage::CallProceeding: return new L3CallProceeding();
case L3CCMessage::Release: return new L3Release();

View File

@@ -4,24 +4,16 @@
* Copyright 2008, 2009 Free Software Foundation, Inc.
* Copyright 2011 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -65,7 +57,6 @@ class L3CCMessage : public L3Message {
CallProceeding=0x02,
Connect=0x07,
Setup=0x05,
EmergencySetup=0x0e,
ConnectAcknowledge=0x0f,
Progress=0x03,
//@}
@@ -179,6 +170,7 @@ public:
mCause(wCause),
mCallState(wCallState)
{}
const L3Cause& cause() const { return mCause; }
const L3CallState callState() const { return mCallState; }
@@ -295,29 +287,6 @@ public:
};
/**
GSM 04.08 9.3.8
*/
class L3EmergencySetup : public L3CCMessage
{
// We fill in IEs one at a time as we need them.
public:
L3EmergencySetup(unsigned wTI=7)
:L3CCMessage(wTI)
{ }
int MTI() const { return EmergencySetup; }
void parseBody( const L3Frame &src, size_t &rp ) {}
size_t l2BodyLength() const { return 0; }
};
/** GSM 04.08 9.3.3 */
class L3CallProceeding : public L3CCMessage {

View File

@@ -6,24 +6,16 @@
* Copyright 2008, 2010 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -342,9 +334,9 @@ void L3MobileStationClassmark3::text(ostream& os) const
{
os << "multiband=" << mMultiband;
os << " A5/4=" << mA5_4;
os << " A5/5=" << mA5_4;
os << " A5/6=" << mA5_4;
os << " A5/7=" << mA5_4;
os << " A5/5=" << mA5_5;
os << " A5/6=" << mA5_6;
os << " A5/7=" << mA5_7;
}

View File

@@ -5,24 +5,16 @@
* Copyright 2008-2010 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/

375
GSM/GSML3GPRSElements.cpp Normal file
View File

@@ -0,0 +1,375 @@
/**@file @brief L3 Radio Resource messages related to GPRS */
/*
* Copyright 2008, 2010 Free Software Foundation, Inc.
* Copyright 2011 Kestrel Signal Processing, Inc.
*
* 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.
*/
#include <typeinfo>
#include <iostream>
#include "GSML3RRMessages.h"
#include "../GPRS/GPRSExport.h"
#include <Logger.h>
namespace GSM {
// GSM 04.60 sec 12.24
void L3GPRSCellOptions::writeBits(L3Frame& dest, size_t &wp) const
{
GPRS::GPRSCellOptions_t& gco = GPRS::GPRSGetCellOptions();
dest.writeField(wp,gco.mNMO,2);
dest.writeField(wp,gco.mT3168Code,3);
dest.writeField(wp,gco.mT3192Code,3);
dest.writeField(wp,gco.mDRX_TIMER_MAX,3);
dest.writeField(wp,gco.mACCESS_BURST_TYPE,1);
dest.writeField(wp,gco.mCONTROL_ACK_TYPE,1);
dest.writeField(wp,gco.mBS_CV_MAX,4);
dest.writeField(wp,0,1); // optional PAN_ fields omitted.
LOG(INFO)<< "beacon"<<LOGVAR2("NW_EXT_UTBF",gco.mNW_EXT_UTBF);
if (!gco.mNW_EXT_UTBF) {
dest.writeField(wp,0,1); // optional extension information omitted
} else {
dest.writeField(wp,1,1); // extension information included.
unsigned extlen = 6; // 6 bits of extension information.
dest.writeField(wp,extlen,6); // length of extension.
// R99 extensions:
dest.writeField(wp,0,1); // No EGPRS.
dest.writeField(wp,0,1); // No PFC_FEATURE_MODE
dest.writeField(wp,0,1); // No DTM_SUPPORT
dest.writeField(wp,0,1); // No BSS_PAGING_COORDINATION
// Rel-4 extensions:
// I tried setting CCN to 1 to get the MS to indicate GERAN feature pack I support.
// CCN is network assisted cell change and is also part of GERAN feature pack I.
dest.writeField(wp,0,1); // CCN_ACTIVE. CCN described 44.060 5.5.1.1a
dest.writeField(wp,gco.mNW_EXT_UTBF,1); // Finally.
// Rel-6 extensions:
// We dont want any of these, but here they are as documentation.
//dest.writeField(wp,0,1); // No MULTIPLE_TBF_CAPABILITY
//dest.writeField(wp,0,1); // No EXT_UTBF_NODATA
//dest.writeField(wp,0,1); // No DTM_ENHANCEMENTS_CAPABILITY
//dest.writeField(wp,0,1); // No MBMS procedures
// End of Rel extensions, we are allowed to truncate here.
dest.writeField(wp,0,1); // Required spare bit - this is very confusing in the spec.
}
}
size_t L3GPRSCellOptions::lengthBits() const
{
GPRS::GPRSCellOptions_t& gco = GPRS::GPRSGetCellOptions();
size_t result = 2+3+3+3+1+1+4+1+1;
if (gco.mNW_EXT_UTBF) {
result += 6 + 6 + 1; // 6 bit len + 6 bits of extension + 1 spare bit.
}
return result;
}
void L3GPRSCellOptions::text(ostream& os) const
{
GPRS::GPRSCellOptions_t& gco = GPRS::GPRSGetCellOptions();
os << "NMO=" << gco.mNMO;
os << " T3168Code=" << gco.mT3168Code;
os << " T3192Code=" << gco.mT3192Code;
os << " DRX_TIMER_MAX=" << gco.mDRX_TIMER_MAX;
os << " ACCESS_BURST_TYPE=" << gco.mACCESS_BURST_TYPE;
os << " CONTROL_ACK_TYPE=" << gco.mCONTROL_ACK_TYPE;
os << " BS_CV_MAX=" << gco.mBS_CV_MAX;
os << LOGVAR2("NW_EXT_UTBF",gco.mNW_EXT_UTBF);
}
const char *L3IAPacketAssignment::IAPacketAssignmentTypeText(enum IAPacketAssignmentType type) const
{
switch (type) {
case PacketUplinkAssignUninitialized: return ""; // No rest octets neeeded for this.
case PacketUplinkAssignFixed: return "Fixed Packet Uplink Assignment";
case PacketUplinkAssignDynamic: return "Dynamic Packet Uplink Assignment";
case PacketUplinkAssignSingleBlock: return "Single Block Packet Uplink Assignment";
case PacketDownlinkAssign: return "Packet Downlink Assignment";
default:
LOG(ERR) << "unrecognized packet assignment type code " << (int)type;
return "??Unknown Assignment Type??";
}
}
void L3IAPacketAssignment::setPacketUplinkAssignSingleBlock(unsigned TBFStartingTime)
{
mPacketAssignmentType = PacketUplinkAssignSingleBlock;
mTBFStartingTimePresent = true;
mTBFStartingTime = TBFStartingTime;
mChannelCodingCommand = 0; // use CS-1; redundant
}
void L3IAPacketAssignment::setPacketUplinkAssignDynamic(unsigned TFI, unsigned CSNum, unsigned USF)
{
mPacketAssignmentType = PacketUplinkAssignDynamic;
mTFIPresent = true;
mTFIAssignment = TFI;
mChannelCodingCommand = CSNum; // CS-1, etc.
mUSFGranularity = 0; // redundant.
mUSF = USF;
}
void L3IAPacketAssignment::setPacketDownlinkAssign(
unsigned wTLLI, unsigned wTFI,unsigned wCSNum,
unsigned wRLCMode,unsigned wTAValid)
{
mPacketAssignmentType = PacketDownlinkAssign;
mTLLI = wTLLI;
mTFIPresent = true;
mTFIAssignment = wTFI;
mChannelCodingCommand = wCSNum; // CS-1, etc.
mRLCMode = wRLCMode;
mTAValid = wTAValid; // We provided a valid TimingAdvance.
}
void L3IAPacketAssignment::setPacketPollTime(unsigned wTBFStartingTime)
{
mPolling = true;
mTBFStartingTimePresent = true;
mTBFStartingTime = wTBFStartingTime;
}
void L3IAPacketAssignment::setPacketUplinkAssignFixed()
{
mPacketAssignmentType = PacketUplinkAssignFixed;
// unimplemented
assert(0);
}
// We broadcast alpha in the SI13 message, but not gamma.
// This gives us a chance to over-ride the alpha,gamma for an individual MS,
// or based on RSSI from the RACH.
// Dont know if we will use this, but here it is anyway.
// If this is not called, the default value of gamma == 0 means MS broadcasts at full power,
// moderated only by the alpha broadcast on SI13.
void L3IAPacketAssignment::setPacketPowerOptions(unsigned wAlpha, unsigned wGamma)
{
mAlpha = wAlpha; mGamma = wGamma; mAlphaPresent = true;
}
// TBF Starting Time GSM 04.08 10.5.2.38
static void writeStartTime(MsgCommon &dest, unsigned startframe)
{
std::ostream*os = dest.getStream(); // non-NULL for text() function.
// The names T1, T2, T3 are defined in table 10.5.79
unsigned T1 = (startframe/1326)%32;
unsigned T3 = startframe%51;
unsigned T2 = startframe%26;
// Recompute original startframe:
// Note that T3-T2 may be negative:
int recomputed = 51 * (((int)T3-(int)T2) % 26) + T3 + 51 * 26 * T1;
unsigned startframemod = (startframe % 42432);
// If we are writing text(), output both the original startframe and
// the computed T1,T2,T3.
if (os) {
// The recomputed time may be a much smaller number than startframe.
*os << " TBFStartFrame=" <<startframe << "=(" << "T=" <<recomputed;
}
// Note: The fields are written here Most-Significant-Bit first in each byte,
// then the bytes are reversed in the encoder before being sent to the radio.
// 7 6 5 4 3 2 1 0
// [ T1[4:0] ][ T3[5:3] ] Octet 1
// [ T3[2:0] ][ T2[4:0] ] Octet 2
dest.writeField(T1,5,"T1p");
dest.writeField(T3,6,"T3"); // Yes T3 comes before T2.
dest.writeField(T2,5,"T2");
// This just doesnt work, despite the documentation.
if (os && recomputed != (int)startframemod) {
*os << " TBF Start Time miscalculation: "
<<LOGVAR(startframemod) <<"!=" <<LOGVAR(recomputed);
}
if (os) { *os << ")"; }
}
// (pat) The uplink assignment is always initiated by the MS using a RACH,
// so the MS is identified by the request reference, and this message
// does not contain a TLLI.
void L3IAPacketAssignment::writePacketUplinkAssignment(MsgCommon &dest) const
{
// The IA Rest Octets start with some bits to indicate a Packet Uplink Assignment:
// GSM04.08 sec 10.5.2.16
dest.writeH();
dest.writeH();
dest.write0();
dest.write0();
if (mPacketAssignmentType == PacketUplinkAssignFixed ||
mPacketAssignmentType == PacketUplinkAssignDynamic) {
dest.write1();
dest.WRITE_FIELD(mTFIAssignment, 5);
dest.WRITE_FIELD(mPolling, 1);
switch (mPacketAssignmentType) {
case PacketUplinkAssignDynamic:
dest.write0();
dest.WRITE_FIELD(mUSF, 3);
dest.WRITE_FIELD(mUSFGranularity, 1);
dest.write0(); // No downlink power parameters present.
// mPowerOption.writePower(dest,0);
break;
case PacketUplinkAssignFixed:
dest.write1();
dest.WRITE_FIELD(mAllocationBitmapLength, 5);
if (mAllocationBitmapLength) {
dest.WRITE_FIELD(mAllocationBitmap, mAllocationBitmapLength);
}
dest.write0(); // No downlink power parameters present.
// mPowerOption.writePower(dest,0);
break;
default: assert(0);
}
dest.WRITE_FIELD(mChannelCodingCommand, 2);
dest.WRITE_FIELD(mTLLIBlockChannelCoding, 1);
if (dest.write01(mAlphaPresent)) { dest.WRITE_FIELD(mAlpha,4); }
dest.WRITE_FIELD(mGamma,5);
if (dest.write01(mTimingAdvanceIndexPresent)) {
dest.WRITE_FIELD(mTimingAdvanceIndex,4);
}
if (dest.write01(mTBFStartingTimePresent)) {
writeStartTime(dest,mTBFStartingTime);
}
} else { // single block assignment.
dest.write0(); // uplink assignment type designator
if (dest.write01(mAlphaPresent)) { dest.WRITE_FIELD(mAlpha,4); }
dest.WRITE_FIELD(mGamma,5);
dest.write0(); dest.write1(); // As per 10.5.2.16 Note 1.
assert(mTBFStartingTimePresent); // required for single block uplink assignment.
writeStartTime(dest,mTBFStartingTime);
dest.writeL(); // No downlink power parameters present.
//mPowerOption.writePower(dest,1);
}
}
// (pat) The downlink assignment may be (normally is) initiated by the network,
// in which case the "request reference" in the Immediate Assignment message
// is set to an impossible value, and the MS is identified by the TLLI.
void L3IAPacketAssignment::writePacketDownlinkAssignment(MsgCommon &dest) const
{
// The IA Rest Octets start with some bits to indicate a Packet Downlink Assignment:
// GSM04.08 sec 10.5.2.16
dest.writeH();
dest.writeH();
dest.write0();
dest.write1();
dest.writeField(mTLLI,32,"TLLI",tohex);
if (dest.write01(mTFIPresent)) {
dest.WRITE_FIELD(mTFIAssignment,5);
dest.WRITE_FIELD(mRLCMode,1);
dest.WRITE_OPT_FIELD01(mAlpha,4,mAlphaPresent);
dest.WRITE_FIELD(mGamma,5);
dest.WRITE_FIELD(mPolling, 1);
dest.WRITE_FIELD(mTAValid, 1);
}
dest.WRITE_OPT_FIELD01(mTimingAdvanceIndex,4,mTimingAdvanceIndexPresent);
if (dest.write01(mTBFStartingTimePresent)) {
writeStartTime(dest,mTBFStartingTime);
}
dest.write0(); // No downlink power parameters present.
dest.writeL(); // No Egprs.
}
void L3IAPacketAssignment::writeIAPacketAssignment(MsgCommon &dest) const
{
// (pat) These messages are the rest octets in an Immediate Assignment Message.
switch (mPacketAssignmentType) {
case PacketUplinkAssignUninitialized:
return; // No rest octets neeeded for this.
case PacketUplinkAssignFixed:
case PacketUplinkAssignDynamic:
case PacketUplinkAssignSingleBlock:
return writePacketUplinkAssignment(dest);
case PacketDownlinkAssign:
return writePacketDownlinkAssignment(dest);
}
}
void L3IAPacketAssignment::writeBits(L3Frame &frame, size_t &wp) const
{
MsgCommonWrite tmp(frame,wp);
writeIAPacketAssignment(tmp);
wp = tmp.wp;
}
// Return the length of this puppy.
size_t L3IAPacketAssignment::lengthBits() const
{
MsgCommonLength dest;
writeIAPacketAssignment(dest);
return dest.wp;
}
// Print a human readable version of this puppy.
void L3IAPacketAssignment::text(std::ostream& os) const
{
if (mPacketAssignmentType != PacketUplinkAssignUninitialized) {
os << " " << IAPacketAssignmentTypeText(mPacketAssignmentType);
MsgCommonText dest(os);
writeIAPacketAssignment(dest);
}
}
#if 0 // Currently unused
void L3GPRSPowerControlParameters::writeBits(L3Frame& dest, size_t &wp) const
{
dest.writeField(wp,mAlpha,4);
// We dont use any of these gamma fields at the moment:
dest.writeField(wp,0,1); // GAMMA_TM0
dest.writeField(wp,0,1); // GAMMA_TM1
dest.writeField(wp,0,1); // GAMMA_TM2
dest.writeField(wp,0,1); // GAMMA_TM3
dest.writeField(wp,0,1); // GAMMA_TM4
dest.writeField(wp,0,1); // GAMMA_TM5
dest.writeField(wp,0,1); // GAMMA_TM6
dest.writeField(wp,0,1); // GAMMA_TM7
}
void L3GPRSPowerControlParameters::text(ostream& os) const
{
os << "Alpha=" << mAlpha;
}
#endif
L3GPRSSI13PowerControlParameters::L3GPRSSI13PowerControlParameters()
: mAlpha(GPRS::GetPowerAlpha()),
mTAvgW(gConfig.getNum("GPRS.MS.Power.T_AVG_W")),
mTAvgT(gConfig.getNum("GPRS.MS.Power.T_AVG_T")),
mPCMeasChan(0),
mNAvgI(15) // We dont use this so dont bother putting in sql.
{}
void L3GPRSSI13PowerControlParameters::writeBits(L3Frame& dest, size_t &wp) const
{
// TODO: use WRITE_ITEM from MsgBase.h
dest.writeField(wp,mAlpha,4);
dest.writeField(wp,mTAvgW,5);
dest.writeField(wp,mTAvgT,5);
dest.writeField(wp,mPCMeasChan,1);
dest.writeField(wp,mNAvgI,4);
}
void L3GPRSSI13PowerControlParameters::text(ostream& os) const
{
os << "(" <<LOGVAR(mAlpha) <<LOGVAR(mTAvgW) <<LOGVAR(mTAvgT)
<<LOGVAR(mPCMeasChan) <<LOGVAR(mNAvgI) << ")";
}
};

180
GSM/GSML3GPRSElements.h Normal file
View File

@@ -0,0 +1,180 @@
/**@file @brief L3 Radio Resource messages related to GPRS */
/*
* Copyright 2008, 2010 Free Software Foundation, Inc.
* Copyright 2011 Kestrel Signal Processing, Inc.
*
* 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.
*/
#ifndef GSML3GPRSELEMENTS_H
#define GSML3GPRSELEMENTS_H
#include "GSML3Message.h"
#include "../GPRS/MsgBase.h"
#include "../GPRS/GPRSExport.h"
#include "ScalarTypes.h"
namespace GSM {
/** Defined in GSM 04.60 12.24 but used in GSM 04.08 10.5.2.37b - SI13 Rest Octets. */
class L3GPRSCellOptions : public GenericMessageElement
{
public:
L3GPRSCellOptions() { }
size_t lengthBits() const;
void writeBits(L3Frame& dest, size_t &wp) const;
void text(std::ostream& os) const;
//void parseV( const L3Frame&, size_t&, size_t) { abort(); }
//void parseV(const L3Frame&, size_t&) { abort(); }
};
// GSM 04.08 10.5.2.16
// (pat) This message is sent to MS inside the rest octets of an Immediate Assignment message
// on CCCH in response to a CHANNEL REQUEST message sent by the MS on RACH.
// The Packet Uplink and Packet Downlink assignment messages are so similar
// they are combined in one structure.
// Note that there are also a Packet Uplink/Downlink Assignment messages (GSM04.60) that do
// the same thing as these messages, but with completely different format,
// and sent on PACCH not CCCH.
// TODO: Padding to end of message should be as for RR messages, not PDCH messages.
// This should be done by whomever sends this message.
struct L3IAPacketAssignment : GenericMessageElement
{
// (note: the MS may choose to send a Packet Uplink Request instead.
// There are three types of packet uplink assignment, and one type of downlink assignment:
enum IAPacketAssignmentType {
PacketUplinkAssignUninitialized,
PacketUplinkAssignFixed,
PacketUplinkAssignDynamic,
PacketUplinkAssignSingleBlock,
PacketDownlinkAssign
};
const char *IAPacketAssignmentTypeText(enum IAPacketAssignmentType type) const;
enum IAPacketAssignmentType mPacketAssignmentType;
Bool_z mTFIPresent;
Field_z<5> mTFIAssignment;
Field_z<1> mPolling; // Set if MS is being polled for Packet Control Acknowledgement.
// This part for Uplink Dynamic Allocation Mode [for packet uplink transfer]:
Field_z<3> mUSF;
Field_z<1> mUSFGranularity;
// This part for Uplink Fixed Allocation Mode [for packet uplink transfer]:
Field_z<5> mAllocationBitmapLength;
Field_z<32> mAllocationBitmap; // variable sized, up to 32 bits
// alpha, gamma for MS power control. See GSM05.08
Field_z<4> mAlpha; Bool_z mAlphaPresent; // optional param
Field_z<5> mGamma;
Field_z<4> mTimingAdvanceIndex; Bool_z mTimingAdvanceIndexPresent; // optional param
// From GSM 04.08 10.5.2.16, and I quote:
// The TBF starting time is coded using the same coding as the V format
// of the type 3 information element Starting Time (10.5.2.38).
Field_z<16> mTBFStartingTime; Bool_z mTBFStartingTimePresent; // optional param
Field_z<2> mChannelCodingCommand; // CS-1, CS-2, CS-3 or CS-4.
Field_z<1> mTLLIBlockChannelCoding;
// (pat) We wont use the downlink power control parameters (P0, etc), so dont even bother.
// L3AssignmentPowerOption mPowerOption;
// The following variables used only for Packet Downlink Assignment
Field_z<32> mTLLI;
Field_z<1> mRLCMode;
Field_z<1> mTAValid; // Is the timingadvance in the main Immediate Assignment Message valid?
void setPacketUplinkAssignSingleBlock(unsigned TBFStartingTime);
void setPacketUplinkAssignDynamic(unsigned TFI, unsigned CSNum, unsigned USF);
void setPacketDownlinkAssign(
unsigned wTLLI, unsigned wTFI,unsigned wCSNum, unsigned wRLCMode,unsigned wTAValid);
void setPacketUplinkAssignFixed();
void setPacketPowerOptions(unsigned wAlpha, unsigned wGamma);
void setPacketPollTime(unsigned TBFStartingTime);
void writePacketUplinkAssignment(MsgCommon &dest) const;
void writePacketDownlinkAssignment(MsgCommon &dest) const;
void writeIAPacketAssignment(MsgCommon &dest) const;
void writeBits(L3Frame &dest, size_t &wp) const;
size_t lengthBits() const;
void text(std::ostream& os) const;
L3IAPacketAssignment() { mPacketAssignmentType = PacketUplinkAssignUninitialized; /*redundant*/ }
};
#if 0 // This is currently unused, so lets indicate so.
/** GSM 04.60 12.13 */
// NOTE: These are the power control parameters for assignment in GSM 4.60,
// not the power control parameters for the SI13 rest octets
// This is NOT a L3ProtocolElement; it is not in TLV format or byte aligned.
class L3GPRSPowerControlParameters : public GenericMessageElement
{
private:
unsigned mAlpha; ///< GSM 04.60 Table 12.9.2
// GSM04.60 12.13
// (pat) There are 8 gamma values, one for each channel.
// sec 12.13 says the presence/absense of gamma may be used to denote
// timeslot for "an uplink TBF", presumably in the absense of a TIMESLOT ALLOCATION IE,
// but I dont see which uplink TBF assignment would use that and the spec does not say.
// I dont see why you need gamma in the SI13 message at all; Gamma is assigned
// in the uplink/downlink assignment messages as a non-optional element.
// I am going to leave them out entirely for now.
// unsigned mGamma[8];
// bool mGammaPresent[8];
public:
// Init alpha to the defalt value.
L3GPRSPowerControlParameters() : mAlpha(GPRS::GetPowerAlpha()) {}
size_t lengthBits() const { return 4+8; }
void writeBits(L3Frame& dest, size_t &wp) const;
void text(std::ostream& os) const;
//void parseV( const L3Frame&, size_t&, size_t) { abort(); }
//void parseV(const L3Frame&, size_t&) { abort(); }
};
#endif
/** GSM 04.08 10.5.2.37b Power Control Parameters for SI13 Rest Octets */
// Info has moved to 44.060 12.13.
// NOTE: This is not the same as the Global Power Control Parameters
// in GSM 44.060 12.9a, which include a Pb element.
class L3GPRSSI13PowerControlParameters : public GenericMessageElement
{
// See GSM 5.08 10.2.1
// (pat) The MS can regulate its own output power based on measurements it makes.
// See comments at GetPowerAlpha(). The alpha below is used for initial
// communication and may be over-ridden later when the MS starts talking to us.
// The other parameters are "forgetting factors" determining the window period for
// the MS measurements. I dont think the values (other than alpha itself)
// are critical because they are clamped to sane values in the formulas in GSM05.08.
unsigned mAlpha; ///< Range 0..10 See GSM 04.60 Table 12.9.2
unsigned mTAvgW; // The MS measurement 'forgetting factor' in Packet Idle Mode.
unsigned mTAvgT; // The MS measurement 'forgetting factor' in Packet Transfer Mode.
unsigned mPCMeasChan; // Which channel Ms monitors: 0 => use BCCH, 1 => PDCH1
unsigned mNAvgI; // 'Forgetting factor' for MS reporting to BTS.
public:
L3GPRSSI13PowerControlParameters();
size_t lengthBits() const { return 4+5+5+1+4; }
void writeBits(L3Frame& dest, size_t &wp) const;
void text(std::ostream& os) const;
};
}; // namespace
#endif

View File

@@ -2,27 +2,19 @@
@brief Elements for Mobility Management messages, GSM 04.08 9.2.
*/
/*
* Copyright 2008, 2010 Free Software Foundation, Inc.
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -48,7 +40,6 @@ ostream& GSM::operator<<(ostream& os, L3CMServiceType::TypeCode code)
{
switch (code) {
case L3CMServiceType::MobileOriginatedCall: os << "MOC"; break;
case L3CMServiceType::EmergencyCall: os << "Emergency"; break;
case L3CMServiceType::ShortMessage: os << "SMS"; break;
case L3CMServiceType::SupplementaryService: os << "SS"; break;
case L3CMServiceType::VoiceCallGroup: os << "VGCS"; break;
@@ -57,6 +48,7 @@ ostream& GSM::operator<<(ostream& os, L3CMServiceType::TypeCode code)
case L3CMServiceType::MobileTerminatedCall: os << "MTC"; break;
case L3CMServiceType::MobileTerminatedShortMessage: os << "MTSMS"; break;
case L3CMServiceType::TestCall: os << "Test"; break;
case L3CMServiceType::FuzzCall: os << "Fuzz"; break;
default: os << "?" << (int)code << "?";
}
return os;

View File

@@ -4,24 +4,16 @@
* Copyright 2008-2010 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -43,7 +35,6 @@ class L3CMServiceType : public L3ProtocolElement {
enum TypeCode {
UndefinedType=0,
MobileOriginatedCall=1,
EmergencyCall=2,
ShortMessage=4, ///< specifically, MO-SMS
SupplementaryService=8,
VoiceCallGroup=9,
@@ -52,6 +43,8 @@ class L3CMServiceType : public L3ProtocolElement {
MobileTerminatedCall=100, ///< non-standard code
MobileTerminatedShortMessage=101, ///< non-standard code
TestCall=102, ///< non-standard code
HandoverCall=103, ///< non-standard code
FuzzCall=104, ///< non-standard code
};
private:
@@ -126,7 +119,7 @@ public:
/** Set the network name, taking the default from gConfig. */
L3NetworkName(const char* wName,
GSMAlphabet alphabet=ALPHABET_7BIT,
int wCI=gConfig.defines("GSM.ShowCountry"))
int wCI=gConfig.getBool("GSM.ShowCountry"))
:L3ProtocolElement(), mAlphabet(alphabet), mCI(wCI)
{ strncpy(mName,wName,maxLen); mName[maxLen] = '\0'; }

View File

@@ -6,24 +6,16 @@
* Copyright 2008-2010 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -124,7 +116,8 @@ void L3MMMessage::text(ostream& os) const
void L3LocationUpdatingRequest::parseBody( const L3Frame &src, size_t &rp )
{
// skip updating type
rp += 4;
// (pat) Save this for debugging purposes.
mUpdateType = src.readField(rp,4);
// skip ciphering ket sequence number
rp += 4;
mLAI.parseV(src,rp);
@@ -136,7 +129,8 @@ void L3LocationUpdatingRequest::parseBody( const L3Frame &src, size_t &rp )
void L3LocationUpdatingRequest::text(ostream& os) const
{
L3MMMessage::text(os);
os << "LAI=("<<mLAI<<")";
os << "UpdateType=("<<mUpdateType<<")";
os << " LAI=("<<mLAI<<")";
os << " MobileIdentity=("<<mMobileIdentity<<")";
os << " classmark=(" << mClassmark << ")";
}

View File

@@ -3,24 +3,16 @@
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -110,6 +102,7 @@ L3MMMessage* parseL3MM(const L3Frame& source);
/** GSM 04.08 9.2.15 */
class L3LocationUpdatingRequest : public L3MMMessage
{
unsigned mUpdateType; // (pat) Added for debugging.
L3MobileStationClassmark1 mClassmark;
L3MobileIdentity mMobileIdentity; // (LV) 1+len
L3LocationAreaIdentity mLAI;

View File

@@ -1,25 +1,14 @@
/*
* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -52,6 +41,7 @@ void L3Message::parse(const L3Frame& source)
void L3Message::write(L3Frame& dest) const
{
size_t l3len = bitsNeeded();
//printf("bitsneeded=%d\n",l3len);
if (dest.size()!=l3len) dest.resize(l3len);
size_t wp = 0;
// write the standard L3 header
@@ -133,10 +123,6 @@ ostream& GSM::operator<<(ostream& os, const L3Message& msg)
GSM::L3Message* GSM::parseL3(const GSM::L3Frame& source)
{
if (source.size()==0) return NULL;
@@ -258,6 +244,12 @@ ostream& GSM::operator<<(ostream& os, const L3ProtocolElement& elem)
return os;
}
ostream& GSM::operator<<(ostream& os, const GenericMessageElement& msg)
{
msg.text(os);
return os;
}

View File

@@ -2,24 +2,14 @@
* Copyright 2008, 2010 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -69,13 +59,14 @@ class L3Message {
/**
Body length not including header but including rest octets.
In subclasses with no rest octets, this returns l2BodyLength.
(pat) in BYTES!!!
*/
virtual size_t fullBodyLength() const =0;
/** Return the expected message length in bytes, including L3 header, but not including rest octets. */
size_t L2Length() const { return l2BodyLength()+2; }
/** Length including header and rest octets. */
/** Length ((pat) in BYTES!!) including header and rest octets. */
size_t FullLength() const { return fullBodyLength()+2; }
/** Return number of BITS needed to hold message and header. */
@@ -303,6 +294,20 @@ class L3ProtocolElement {
std::ostream& operator<<(std::ostream& os, const L3ProtocolElement& elem);
// Pat added: A Non-Aligned Message Element that is not an L3ProtocolElement because
// it is not in TLV format, and is not byte or half-byte aligned,
// but is rather just a stream of bits, often used in the Message RestOctets.
class GenericMessageElement {
public:
// We dont use these virtual functions except for text().
// They are basically here as documentation.
virtual size_t lengthBits() const = 0;
virtual void writeBits(L3Frame& dest, size_t &wp) const = 0;
virtual void text(std::ostream& os) const = 0;
};
std::ostream& operator<<(std::ostream& os, const GenericMessageElement& elem);
}; // GSM

View File

@@ -1,35 +1,25 @@
/**@file
@brief Radio Resource messages, GSM 04.08 9.1.
*/
/**@file @brief Radio Resource messages, GSM 04.08 9.1. */
/*
* Copyright 2008, 2009 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
* Copyright 2010, 2013 Kestrel Signal Processing, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
#include <iterator> // for L3APDUData::text
#include "GSML3RRElements.h"
#include "Defines.h"
#include "GSMConfig.h"
#include <Logger.h>
@@ -105,6 +95,20 @@ void L3CellSelectionParameters::text(ostream& os) const
unsigned L3ControlChannelDescription::getBS_PA_MFRMS()
{
unsigned bs_pa_mfrms = mBS_PA_MFRMS + 2;
if (bs_pa_mfrms != RN_BOUND(bs_pa_mfrms,2,sMax_BS_PA_MFRMS)) {
static bool printed_msg = false;
if (!printed_msg) {
LOG(ERR) << "Invalid BS_PA_MFRMS value, must be 2.."<<sMax_BS_PA_MFRMS;
printed_msg = true;
}
bs_pa_mfrms = 2; // If invalid, it is ok as long as we use the same value all the time.
}
return bs_pa_mfrms;
}
void L3ControlChannelDescription::writeV(L3Frame& dest, size_t &wp) const
{
@@ -180,7 +184,7 @@ void L3FrequencyList::writeV(L3Frame& dest, size_t &wp) const
// bit map
unsigned delta = spread();
unsigned numBits = 8*lengthV() - 17;
if (numBits<delta) { LOG(ALERT) << "L3FrequencyList cannot encode full ARFCN set"; }
if (numBits<delta) { LOG(ALERT) << "L3FrequencyList cannot encode full ARFCN set, base=" << baseARFCN << " delta=" << delta; }
for (unsigned i=0; i<numBits; i++) {
unsigned thisARFCN = baseARFCN + 1 + i;
if (contains(thisARFCN)) dest.writeField(wp,1,1);
@@ -316,6 +320,7 @@ void L3ChannelDescription::writeV( L3Frame &dest, size_t &wp ) const
//
// HACK -- Hard code for non-hopping.
// (pat) Same format used for Packet Channel Description 10.5.2.25a
assert(mHFlag==0);
dest.writeField(wp,mTypeAndOffset,5);
dest.writeField(wp,mTN,3);
@@ -345,7 +350,6 @@ void L3ChannelDescription::parseV(const L3Frame& src, size_t &rp)
void L3ChannelDescription::text(std::ostream& os) const
{
os << "typeAndOffset=" << mTypeAndOffset;
os << " TN=" << mTN;
os << " TSC=" << mTSC;
@@ -353,16 +357,16 @@ void L3ChannelDescription::text(std::ostream& os) const
}
void L3RequestReference::writeV( L3Frame &dest, size_t &wp ) const
{
// Request Reference Format.
// 7 6 5 4 3 2 1 0
// [ RequestReference [7:0] ] Octet 2
// [ T1[4:0] ][ T3[5:3] ] Octet 3
// [ T3[2:0] ][ T2[4:0] ] Octet 4
// Note: fields are written MSB first, then bytes are reversed later in the encoder.
// Request Reference Format.
// 7 6 5 4 3 2 1 0
// [ RequestReference [7:0] ] Octet 2
// [ T1[4:0] ][ T3[5:3] ] Octet 3
// [ T3[2:0] ][ T2[4:0] ] Octet 4
dest.writeField(wp, mRA, 8);
dest.writeField(wp, mT1p, 5);
@@ -373,7 +377,10 @@ void L3RequestReference::writeV( L3Frame &dest, size_t &wp ) const
void L3RequestReference::text(ostream& os) const
{
os << "RA=" << mRA;
os << hex << "RA=0x" << mRA << dec;
// pat added: This is the frame number recomputed from T1p, T2, T3:
unsigned recomputed = 51 * ((mT3-mT2) % 26) + mT3 + 51 * 26 * mT1p;
os << " T=" << recomputed;
os << " T1'=" << mT1p;
os << " T2=" << mT2;
os << " T3=" << mT3;
@@ -600,21 +607,21 @@ void L3MeasurementResults::text(ostream& os) const
}
unsigned L3MeasurementResults::RXLEV_NCELL(unsigned * target) const
unsigned L3MeasurementResults::RXLEV_NCELLs(unsigned * target) const
{
for (unsigned i=0; i<mNO_NCELL; i++) target[i] = mRXLEV_NCELL[i];
return mNO_NCELL;
}
unsigned L3MeasurementResults::BCCH_FREQ_NCELL(unsigned * target) const
unsigned L3MeasurementResults::BCCH_FREQ_NCELLs(unsigned * target) const
{
for (unsigned i=0; i<mNO_NCELL; i++) target[i] = mBCCH_FREQ_NCELL[i];
return mNO_NCELL;
}
unsigned L3MeasurementResults::BSIC_NCELL(unsigned * target) const
unsigned L3MeasurementResults::BSIC_NCELLs(unsigned * target) const
{
for (unsigned i=0; i<mNO_NCELL; i++) target[i] = mBSIC_NCELL[i];
return mNO_NCELL;
@@ -642,74 +649,247 @@ float L3MeasurementResults::decodeQualToBER(unsigned qual) const
L3SI3RestOctets::L3SI3RestOctets()
:L3RestOctets(),
mHaveSI3RestOctets(false),
mHaveSelectionParameters(false),
mCBQ(0),mCELL_RESELECT_OFFSET(0),
mTEMPORARY_OFFSET(0),
mPENALTY_TIME(0)
mPENALTY_TIME(0),
mRA_COLOUR(0),
mHaveGPRS(false)
{
// (pat) 11-26-2011 If you enable this in the OpenBTS sql, the microtech
// modem stops registering.
// See GSM 04.08 10.5.2.34 and 05.08 9 Table 1.
if (!gConfig.defines("GSM.SI3RO")) return;
// 12-12: Pat reversed the logic of this so the default is to have the rest octets
// if any of the other SI3R0 things are defined, unless you specifically
// define GSM.SI3RO as 0:
if (gConfig.defines("GSM.SI3RO")) {
mHaveSI3RestOctets = gConfig.getNum("GSM.SI3RO");
if (!mHaveSI3RestOctets) return;
}
// Optional Cell Selection Parameters.
// CELL_BAR_QUALIFY. 1 bit. Default value is 0.
if (gConfig.defines("GSM.SI3RO.CBQ")) {
mCBQ = gConfig.getNum("GSM.SI3RO.CBQ");
mHaveSI3RestOctets = true;
mHaveSelectionParameters = true;
}
// CELL_RESELECT_OFFSET. 6 bits. Default value is 0.
// C2 offset in 2 dB steps
if (gConfig.defines("GSM.SI3RO.CRO")) {
mCELL_RESELECT_OFFSET = gConfig.getNum("GSM.SI3RO.CRO");
mHaveSI3RestOctets = true;
mHaveSelectionParameters = true;
}
// Another offset to C2 in 10 dB steps, applied during penalty time.
// 3 bits. // Default is 0 dB but "7" means "infinity".
if (gConfig.defines("GSM.SI3RO.TEMPORARY_OFFSET")) {
mTEMPORARY_OFFSET = gConfig.getNum("GSM.SI3RO.TEMPORARY_OFFSET");
mHaveSI3RestOctets = true;
mHaveSelectionParameters = true;
}
// The time for which the temporary offset is applied, 20*(n+1).
if (gConfig.defines("GSM.SI3RO.PENALTY_TIME")) {
mPENALTY_TIME = gConfig.getNum("GSM.SI3RO.PENALTY_TIME");
mHaveSI3RestOctets = true;
mHaveSelectionParameters = true;
}
mHaveGPRS = GPRS::GPRSConfig::IsEnabled();
if (mHaveGPRS) {
mHaveSI3RestOctets = true;
mRA_COLOUR = gConfig.getNum("GPRS.RA_COLOUR");
}
}
size_t L3SI3RestOctets::lengthV() const
{
size_t sumBits = 0;
if (!mHaveSI3RestOctets) { return 0; }
if (mHaveSelectionParameters) sumBits += 1 + 1+6+3+5;
else sumBits += 1;
sumBits += 1 // L for Optional Power Offset
+ 1 // L for System Information 2ter Indicator
+ 1 // L for Early Classmark Sending Control
+ 1; // L for Scheduling if and where
if (mHaveGPRS) sumBits += 1 // H for GPRS Indicator
+ 4;// Size of GPRS Indicator field.
else sumBits += 1;
size_t octets = sumBits/8;
if (sumBits%8) octets += 1;
return octets;
}
// GSM04.08 sec10.5.2.34
void L3SI3RestOctets::writeV(L3Frame& dest, size_t &wp) const
{
if (!mHaveSI3RestOctets) { return; }
size_t wpstart = wp;
if (mHaveSelectionParameters) {
dest.writeH(wp);
dest.writeField(wp,mCBQ,1);
dest.writeField(wp,mCELL_RESELECT_OFFSET,6);
dest.writeField(wp,mTEMPORARY_OFFSET,3);
dest.writeField(wp,mPENALTY_TIME,5);
} else {
dest.writeL(wp);
}
dest.writeL(wp); // L for Optional Power Offset
dest.writeL(wp); // L for System Information 2ter Indicator
dest.writeL(wp); // L for Early Classmark Sending Control
dest.writeL(wp); // L for Scheduling if and where (means no System Information Type 9.)
if (mHaveGPRS) {
dest.writeH(wp); // H for GPRS Indicator
// (pat) The GPRS Indicator.
dest.writeField(wp,mRA_COLOUR,3);
dest.writeField(wp,0,1); // SI13 POSITION: 0 => BCCH Norm
} else {
dest.writeL(wp);
}
while (wp & 7) { dest.writeL(wp); } // spare padding to byte boundary.
assert(wp-wpstart == lengthV() * 8);
}
void L3SI3RestOctets::text(ostream& os) const
{
if (!mHaveSI3RestOctets) { return; }
if (mHaveSelectionParameters) {
os << "CBQ=" << mCBQ;
os << " CELL_RESELECT_OFFSET=" << mCELL_RESELECT_OFFSET;
os << " TEMPORARY_OFFSET=" << mTEMPORARY_OFFSET;
os << " PANALTY_TIME=" << mPENALTY_TIME;
os << " PENALTY_TIME=" << mPENALTY_TIME;
}
if (mHaveGPRS) {
os << " RA_COLOUR=" << mRA_COLOUR;
}
}
void L3HandoverReference::writeV(L3Frame& frame, size_t& wp) const
{
frame.writeField(wp,mValue,8);
}
void L3HandoverReference::text(ostream& os) const
{
os << "value=" << mValue;
}
size_t L3CipheringModeSetting::lengthV() const
{
return 0;
}
void L3CipheringModeSetting::writeV(L3Frame& frame, size_t& wp) const
{
frame.writeField(wp, mCiphering? mAlgorithm-1: 0, 3);
frame.writeField(wp, mCiphering, 1);
}
void L3CipheringModeSetting::text(ostream& os) const
{
os << "ciphering=" << mCiphering;
os << " algorithm=A5/" << mAlgorithm;
}
size_t L3CipheringModeResponse::lengthV() const
{
return 0;
}
void L3CipheringModeResponse::writeV(L3Frame& frame, size_t& wp) const
{
frame.writeField(wp, 0, 3);
frame.writeField(wp, mIncludeIMEISV, 1);
}
void L3CipheringModeResponse::text(ostream& os) const
{
os << "includeIMEISV=" << mIncludeIMEISV;
}
void L3SynchronizationIndication::writeV(L3Frame& frame, size_t& wp) const
{
frame.writeField(wp,0xD,4);
frame.writeField(wp,mNCI,1);
frame.writeField(wp,mROT,1);
frame.writeField(wp,mSI,2);
}
void L3SynchronizationIndication::text(ostream& os) const
{
os << "NCI=" << (int)mNCI << " ROT=" << (int)mROT << " SI=" << mSI;
}
void L3CellDescription::writeV(L3Frame& frame, size_t &wp) const
{
frame.writeField(wp, mARFCN>>8, 2);
frame.writeField(wp, mNCC, 3);
frame.writeField(wp, mBCC, 3);
frame.writeField(wp, mARFCN & 0x0ff, 8);
}
void L3CellDescription::text(std::ostream& os) const
{
os << " ARFCN=" << mARFCN;
os << " NCC=" << mNCC;
os << " BCC=" << mBCC;
}
void L3SI13RestOctets::writeV(L3Frame& dest, size_t &wp) const
{
size_t wpstart = wp;
dest.writeH(wp); // Indicates Rest Octets are present.
// FIXME -- Need to implement BCCH_CHANGE_MARK
// If implemented, BCCH_CHANGE_MARK would be a counter
// that is incremented when the BCCH content changes.
dest.writeField(wp,gBTS.changemark()%8,3); // BCCH_CHANGE_MARK
dest.writeField(wp,0,4); // SI13_CHANGE_FIELD
dest.writeField(wp,0,1); // no changemark or mobile allocation
// (pat) The GPRS "mobile allocation" is optional and does
// not indicate that GPRS service is present or absent.
dest.writeField(wp,0,1); // no PBCCH (pat says: This is correct.)
dest.writeField(wp,mRAC,8);
dest.writeField(wp,mSPGC_CCCH_SUP,1);
dest.writeField(wp,mPRIORITY_ACCESS_THR,3);
dest.writeField(wp,mNETWORK_CONTROL_ORDER,2);
mCellOptions.writeBits(dest,wp);
mPowerControlParameters.writeBits(dest,wp);
while (wp & 7) { dest.writeL(wp); } // spare padding to byte bondary.
assert(wp-wpstart == lengthV() * 8);
}
void L3SI13RestOctets::text(ostream& os) const
{
os << "RAC=" << mRAC;
os << " SPGC_CCCH_SUP=" << mSPGC_CCCH_SUP;
os << " PRIORITY_ACCESS_THR=" << mPRIORITY_ACCESS_THR;
os << " NETWORK_CONTROL_ORDER=" << mNETWORK_CONTROL_ORDER;
os << " cellOptions=(" << mCellOptions << ")";
os << " powerControlParameters=(" << mPowerControlParameters << ")";
}
// vim: ts=4 sw=4

View File

@@ -2,25 +2,18 @@
/*
* Copyright 2008, 2009 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
* Copyright 2011, 2012 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -30,6 +23,7 @@
#include <vector>
#include "GSML3Message.h"
#include "GSML3GPRSElements.h"
#include <Globals.h>
@@ -55,7 +49,7 @@ class L3CellOptionsBCCH : public L3ProtocolElement {
mPWRC=0;
mDTX=2;
// Configuarable values.
mRADIO_LINK_TIMEOUT= gConfig.getNum("GSM.RADIO-LINK-TIMEOUT");
mRADIO_LINK_TIMEOUT= gConfig.getNum("GSM.CellOptions.RADIO-LINK-TIMEOUT");
}
size_t lengthV() const { return 1; }
@@ -87,7 +81,7 @@ class L3CellOptionsSACCH : public L3ProtocolElement {
mPWRC=0;
mDTX=2;
// Configuarable values.
mRADIO_LINK_TIMEOUT=gConfig.getNum("GSM.RADIO-LINK-TIMEOUT");
mRADIO_LINK_TIMEOUT=gConfig.getNum("GSM.CellOptions.RADIO-LINK-TIMEOUT");
}
size_t lengthV() const { return 1; }
@@ -144,10 +138,16 @@ class L3ControlChannelDescription : public L3ProtocolElement {
private:
// (pat) 5-27-2012: I put in 'real' paging channels and used them for GPRS,
// but someone still needs to modify the GSM stack to use them and test them there.
// Then we could change the parameters below to provide more paging channels.
// See class CCCHCombinedChannel.
unsigned mATT; ///< 1 -> IMSI attach/detach
unsigned mBS_AG_BLKS_RES; ///< access grant channel reservation
unsigned mCCCH_CONF; ///< channel combination for CCCH
unsigned mBS_PA_MFRMS; ///< paging channel configuration
// Note: This var is 0..7 representing BS_PA_MFRMS values 2..9.
unsigned mT3212; ///< periodic updating timeout
public:
@@ -159,11 +159,14 @@ class L3ControlChannelDescription : public L3ProtocolElement {
mBS_AG_BLKS_RES=2; // reserve 2 CCCHs for access grant
mBS_PA_MFRMS=0; // minimum PCH spacing
// Configurable values.
mATT=(unsigned)gConfig.defines("Control.LUR.AttachDetach");
mATT=(unsigned)gConfig.getBool("Control.LUR.AttachDetach");
mCCCH_CONF=gConfig.getNum("GSM.CCCH.CCCH-CONF");
mT3212=gConfig.getNum("GSM.Timer.T3212")/6;
}
// BS_PA_MFRMS is the number of 51-multiframes used for paging in the range 2..9.
unsigned getBS_PA_MFRMS();
size_t lengthV() const { return 3; }
void writeV(L3Frame& dest, size_t &wp) const;
void parseV(const L3Frame&, size_t&) { assert(0); }
@@ -257,8 +260,14 @@ class L3NeighborCellsDescription : public L3FrequencyList {
public:
L3NeighborCellsDescription()
:L3FrequencyList(gConfig.getVector("GSM.CellSelection.Neighbors"))
L3NeighborCellsDescription() {}
//L3NeighborCellsDescription()
// :L3FrequencyList(gConfig.getVector("GSM.CellSelection.Neighbors"))
//{}
L3NeighborCellsDescription(const std::vector<unsigned>& neighbors)
:L3FrequencyList(neighbors)
{}
void writeV(L3Frame& dest, size_t &wp) const;
@@ -322,7 +331,7 @@ class L3RACHControlParameters : public L3ProtocolElement {
// Configurable values.
mMaxRetrans = gConfig.getNum("GSM.RACH.MaxRetrans");
mTxInteger = gConfig.getNum("GSM.RACH.TxInteger");
mAC = gConfig.getNum("GSM.RACH.AC");
mAC = 0x0400; //NO EMERGENCY SERVICE - kurtis
}
size_t lengthV() const { return 3; }
@@ -365,6 +374,7 @@ public:
/** DedicatedModeOrTBF, GSM 04.08 10.5.2.25b */
class L3DedicatedModeOrTBF : public L3ProtocolElement {
// (pat) This is poorly named: mDownlink must be TRUE for a TBF, even if it is an uplink tbf.
unsigned mDownlink; ///< Indicates the IA reset octets contain additional information.
unsigned mTMA; ///< This is part of a 2-message assignment.
unsigned mDMOrTBF; ///< Dedicated link (circuit-switched) or temporary block flow (GPRS/pakcet).
@@ -372,9 +382,9 @@ class L3DedicatedModeOrTBF : public L3ProtocolElement {
public:
L3DedicatedModeOrTBF()
L3DedicatedModeOrTBF(bool forTBF, bool wDownlink)
:L3ProtocolElement(),
mDownlink(0), mTMA(0), mDMOrTBF(0)
mDownlink(wDownlink), mTMA(0), mDMOrTBF(forTBF)
{}
size_t lengthV() const { return 1; }
@@ -387,7 +397,12 @@ public:
/** ChannelDescription, GSM 04.08 10.5.2.5 */
/** ChannelDescription, GSM 04.18 10.5.2.5
(pat) The Packet Channel Description, GSM 04.18 10.5.2.25a, is the
same as the Channel Description except with mTypeAndOffset always 1,
and for the addition of indirect frequency hopping encoding,
which is irrelevant for us at the moment.
*/
class L3ChannelDescription : public L3ProtocolElement {
@@ -416,7 +431,8 @@ public:
/** Non-hopping initializer. */
L3ChannelDescription(TypeAndOffset wTypeAndOffset, unsigned wTN,
unsigned wTSC, unsigned wARFCN)
:mTypeAndOffset(wTypeAndOffset),mTN(wTN),
:L3ProtocolElement(),
mTypeAndOffset(wTypeAndOffset),mTN(wTN),
mTSC(wTSC),
mHFlag(0),
mARFCN(wARFCN),
@@ -436,8 +452,24 @@ public:
void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
void text(std::ostream&) const;
TypeAndOffset typeAndOffset() const { return mTypeAndOffset; }
unsigned TN() const { return mTN; }
unsigned TSC() const{ return mTSC; }
unsigned ARFCN() const { return mARFCN; }
};
/** GSM 040.08 10.5.2.5a */
class L3ChannelDescription2 : public L3ChannelDescription {
public:
L3ChannelDescription2(TypeAndOffset wTypeAndOffset, unsigned wTN,
unsigned wTSC, unsigned wARFCN)
:L3ChannelDescription(wTypeAndOffset,wTN,wTSC,wARFCN)
{ }
L3ChannelDescription2() { }
};
@@ -734,6 +766,10 @@ class L3MeasurementResults : public L3ProtocolElement {
L3MeasurementResults()
:L3ProtocolElement(),
mMEAS_VALID(false),
mRXLEV_FULL_SERVING_CELL(0),
mRXLEV_SUB_SERVING_CELL(0),
mRXQUAL_FULL_SERVING_CELL(0),
mRXQUAL_SUB_SERVING_CELL(0),
mNO_NCELL(0)
{ }
@@ -756,11 +792,11 @@ class L3MeasurementResults : public L3ProtocolElement {
unsigned NO_NCELL() const { return mNO_NCELL; }
unsigned RXLEV_NCELL(unsigned i) const { assert(i<mNO_NCELL); return mRXLEV_NCELL[i]; }
unsigned RXLEV_NCELL(unsigned *) const;
unsigned RXLEV_NCELLs(unsigned *) const;
unsigned BCCH_FREQ_NCELL(unsigned i) const { assert(i<mNO_NCELL); return mBCCH_FREQ_NCELL[i]; }
unsigned BCCH_FREQ_NCELL(unsigned *) const;
unsigned BCCH_FREQ_NCELLs(unsigned *) const;
unsigned BSIC_NCELL(unsigned i) const { assert(i<mNO_NCELL); return mBSIC_NCELL[i]; }
unsigned BSIC_NCELL(unsigned *) const;
unsigned BSIC_NCELLs(unsigned *) const;
//@}
/**@ Real-unit conversions. */
@@ -787,6 +823,139 @@ class L3MeasurementResults : public L3ProtocolElement {
};
/** GSM 04.08 10.5.2.2 */
class L3CellDescription : public L3ProtocolElement {
protected:
unsigned mARFCN;
unsigned mNCC;
unsigned mBCC;
public:
L3CellDescription( unsigned wARFCN, unsigned wNCC, unsigned wBCC)
:L3ProtocolElement(),
mARFCN(wARFCN),
mNCC(wNCC),mBCC(wBCC)
{ }
L3CellDescription() { }
size_t lengthV() const { return 2; }
void writeV(L3Frame&, size_t&) const;
void parseV(const L3Frame&, size_t&) { assert(0); }
void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
void text(std::ostream&) const;
};
/** GSM 04.08 10.5.2.15 */
class L3HandoverReference : public L3ProtocolElement
{
protected:
unsigned mValue;
public:
L3HandoverReference(unsigned wValue)
:L3ProtocolElement(),
mValue(wValue)
{}
L3HandoverReference() { }
size_t lengthV() const { return 1; }
void writeV(L3Frame &, size_t &wp ) const;
void parseV( const L3Frame&, size_t&, size_t) { abort(); }
void parseV(const L3Frame&, size_t&) { abort(); }
void text(std::ostream&) const;
unsigned value() const { return mValue; }
};
/** GSM 04.08 10.5.2.9 */
class L3CipheringModeSetting : public L3ProtocolElement
{
protected:
bool mCiphering;
int mAlgorithm; // algorithm is A5/mAlgorithm
public:
L3CipheringModeSetting(bool wCiphering, int wAlgorithm)
:mCiphering(wCiphering), mAlgorithm(wAlgorithm)
{
// assert(wAlgorithm >= 1 && wAlgorithm <= 7);
}
size_t lengthV() const;
void writeV(L3Frame&, size_t& wp) const;
void parseV( const L3Frame&, size_t&, size_t) { abort(); }
void parseV(const L3Frame&, size_t&) { abort(); }
void text(std::ostream&) const;
};
/** GSM 04.08 10.5.2.10 */
class L3CipheringModeResponse : public L3ProtocolElement
{
protected:
bool mIncludeIMEISV;
public:
L3CipheringModeResponse(bool wIncludeIMEISV)
:mIncludeIMEISV(wIncludeIMEISV)
{ }
size_t lengthV() const;
void writeV(L3Frame&, size_t& wp) const;
void parseV( const L3Frame&, size_t&, size_t) { abort(); }
void parseV(const L3Frame&, size_t&) { abort(); }
void text(std::ostream&) const;
};
/** GSM 04.08 10.5.2.39 */
class L3SynchronizationIndication : public L3ProtocolElement
{
protected:
bool mNCI;
bool mROT;
int mSI;
public:
L3SynchronizationIndication(bool wNCI, bool wROT, int wSI = 0)
:L3ProtocolElement(),
mNCI(wNCI),
mROT(wROT),
mSI(wSI & 3)
{}
L3SynchronizationIndication() { }
size_t lengthV() const { return 1; }
void writeV(L3Frame &, size_t &wp ) const;
void parseV( const L3Frame&, size_t&, size_t) { abort(); }
void parseV(const L3Frame&, size_t&) { abort(); }
void text(std::ostream&) const;
unsigned NCI() const { return mNCI; }
unsigned ROT() const { return mROT; }
};
/** GSM 04.08 10.5.2.28a */
class L3PowerCommandAndAccessType : public L3PowerCommand { };
/** A special subclass for rest octets, just in case we need it later. */
@@ -800,12 +969,15 @@ class L3SI3RestOctets : public L3RestOctets {
private:
// We do not yet support the full parameter set.
bool mHaveSI3RestOctets;
bool mHaveSelectionParameters;
bool mCBQ;
unsigned mCELL_RESELECT_OFFSET;
unsigned mTEMPORARY_OFFSET;
unsigned mPENALTY_TIME;
unsigned mCELL_RESELECT_OFFSET; // 6 bits
unsigned mTEMPORARY_OFFSET; // 3 bits
unsigned mPENALTY_TIME; // 5 bits
unsigned mRA_COLOUR; // (pat) In GPRS_Indicator, 3 bits
bool mHaveGPRS; // (pat)
public:
@@ -820,6 +992,127 @@ class L3SI3RestOctets : public L3RestOctets {
};
#if 0
/** GSM 04.60 12.24 */
// (pat) Someone kindly added this before I got here.
// This info is included in the SI13 rest octets.
class L3GPRSCellOptions : public L3ProtocolElement {
private:
unsigned mNMO; // Network Mode of Operation See GSM 03.60 6.3.3.1
unsigned mT3168; // range 0..7
unsigned mT3192; // range 0..7
unsigned mDRX_TIMER_MAX;
unsigned mACCESS_BURST_TYPE;
unsigned mCONTROL_ACK_TYPE;
unsigned mBS_VC_MAX;
public:
L3GPRSCellOptions()
:L3ProtocolElement(),
mNMO(2), // (pat) 2 == Network Mode of Operation III, which means
// GPRS attached MS uses Packet Paging channel
// if allocated (which it wont be), otherwise CCCH.
mT3168(gConfig.getNum("GPRS.CellOptions.T3168Code")),
mT3192(gConfig.getNum("GPRS.CellOptions.T3192Code")),
mDRX_TIMER_MAX(gConfig.getNum("GPRS.CellOptions.DRX_TIMER_MAX")),
mACCESS_BURST_TYPE(0), // (pat) 0 == use 8 bit format of Packet Channel Request Message.
mCONTROL_ACK_TYPE(1), // (pat) 1 == default format for Packet Control Acknowledgement
// is RLC/MAC block, ie, not special.
mBS_VC_MAX(gConfig.getNum("GPRS.CellOptions.BS_VC_MAX"))
{ }
size_t lengthV() const { return 2+3+3+3+1+1+4+1+1; }
void writeV(L3Frame& dest, size_t &wp) const;
void parseV( const L3Frame&, size_t&, size_t) { abort(); }
void parseV(const L3Frame&, size_t&) { abort(); }
void text(std::ostream& os) const;
};
#endif
#if 0
/** GSM 04.60 12.13 */
class L3GPRSPowerControlParameters : public L3ProtocolElement {
private:
unsigned mALPHA; ///< GSM 04.60 Table 12.9.2
public:
L3GPRSPowerControlParameters()
:L3ProtocolElement(),
mALPHA(gConfig.getNum("GPRS.PowerControl.ALPHA"))
{ }
size_t lengthV() const { return 4+8; }
void writeV(L3Frame& dest, size_t &wp) const;
void parseV( const L3Frame&, size_t&, size_t) { abort(); }
void parseV(const L3Frame&, size_t&) { abort(); }
void text(std::ostream& os) const;
};
#endif
/** GSM 04.08 10.5.2.37b */
class L3SI13RestOctets : public L3RestOctets {
private:
unsigned mRAC; ///< routing area code GSM03.03
bool mSPGC_CCCH_SUP; ///< indicates support of SPLIT_PG_CYCLE on CCCH
unsigned mPRIORITY_ACCESS_THR;
unsigned mNETWORK_CONTROL_ORDER; ///< network reselection behavior
const L3GPRSCellOptions mCellOptions;
const L3GPRSSI13PowerControlParameters mPowerControlParameters;
public:
L3SI13RestOctets()
:L3RestOctets(),
mRAC(gConfig.getNum("GPRS.RAC")), // (pat) aka Routing Area Code.
mSPGC_CCCH_SUP(false),
// See GSM04.08 table 10.5.76: Value 6 means any priority packet access allowed.
mPRIORITY_ACCESS_THR(gConfig.getNum("GPRS.PRIORITY-ACCESS-THR")),
// (pat) GSM05.08 sec 10.1.4: This controls whether the MS
// does cell reselection or the network, and appears to apply
// only to GPRS mode. Value NC2 = 2 means the network
// performs cell reselection, but it has a side-effect that
// the MS continually sends Measurement reports, and these
// clog up the RACH channel so badly that the MS cannot send
// enough uplink messages to make the SGSN happy.
// The reporting interval values are as follows,
// defined in GSM04.60 11.2.23 table 11.2.23.2
// NC_REPORTING_PERIOD_I - used in packet idle mode.
// NC_REPORTING_PERIOD_T - used in packet transfer mode.
// They can be in PSI5, SI2quarter (but I dont see them there),
// or by a PACKET MEASUREMENT ORDER msg.
// I am going to set this to 0 for now instead of 2.
// Update: Lets set it back to see if the MS keeps sending measurement reports when it is non-responsive.
// Update: If the MS is requested to make measurement reports it
// reduces the multislot capability. Measurements described 45.008
mNETWORK_CONTROL_ORDER(gConfig.getNum("GPRS.NC.NetworkControlOrder")),
mPowerControlParameters() // redundant explicit call
{ }
size_t lengthBits() const
{ return 1+3+4+1+1+8+1+3+2+mCellOptions.lengthBits()+mPowerControlParameters.lengthBits(); }
size_t lengthV() const
{ return (lengthBits() + 7) / 8; }
void writeV(L3Frame& dest, size_t &wp) const;
void parseV( const L3Frame&, size_t&, size_t) { abort(); }
void parseV(const L3Frame&, size_t&) { abort(); }
void text(std::ostream& os) const;
};
} // GSM

View File

@@ -2,27 +2,19 @@
@brief GSM Radio Resorce messages, from GSM 04.08 9.1.
*/
/*
* Copyright 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
* Copyright 2011 Kestrel Signal Processing, Inc.
* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
* Copyright 2011, 2012 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -56,9 +48,6 @@ void L3Message::parseBody(const L3Frame&, size_t&)
}
ostream& GSM::operator<<(ostream& os, L3RRMessage::MessageType val)
{
switch (val) {
@@ -126,6 +115,18 @@ ostream& GSM::operator<<(ostream& os, L3RRMessage::MessageType val)
os << "RR Status"; break;
case L3RRMessage::ApplicationInformation:
os << "Application Information"; break;
case L3RRMessage::HandoverCommand:
os << "Handover Command"; break;
case L3RRMessage::HandoverComplete:
os << "Handover Complete"; break;
case L3RRMessage::HandoverFailure:
os << "Handover Failure"; break;
case L3RRMessage::CipheringModeCommand:
os << "Ciphering Mode Command"; break;
case L3RRMessage::CipheringModeComplete:
os << "Ciphering Mode Complete"; break;
case L3RRMessage::PhysicalInformation:
os << "Physical Information"; break;
default: os << hex << "0x" << (int)val << dec;
}
return os;
@@ -152,6 +153,9 @@ L3RRMessage* GSM::L3RRFactory(L3RRMessage::MessageType MTI)
case L3RRMessage::ClassmarkEnquiry: return new L3ClassmarkEnquiry();
case L3RRMessage::MeasurementReport: return new L3MeasurementReport();
case L3RRMessage::ApplicationInformation: return new L3ApplicationInformation();
case L3RRMessage::HandoverComplete: return new L3HandoverComplete();
case L3RRMessage::HandoverFailure: return new L3HandoverFailure();
case L3RRMessage::CipheringModeComplete: return new L3CipheringModeComplete();
// Partial support just to get along with some phones.
case L3RRMessage::GPRSSuspensionRequest: return new L3GPRSSuspensionRequest();
default:
@@ -215,7 +219,8 @@ void L3PagingRequestType1::writeBody(L3Frame& dest, size_t &wp) const
assert(sz<=2);
// Remember to reverse orders of 1/2-octet fields.
// Because GSM transmits LSB-first within each byte.
// channel needed codes
// (pat) No, it is because the fields are written MSB first here,
// and then later byte-reversed in the encoder before being sent to radio LSB first.
dest.writeField(wp,channelNeededCode(mChannelsNeeded[1]),2);
dest.writeField(wp,channelNeededCode(mChannelsNeeded[0]),2);
// "normal paging", GSM 04.08 Table 10.5.63
@@ -320,6 +325,7 @@ void L3SystemInformationType3::writeBody(L3Frame& dest, size_t &wp) const
- RACH Control Parameters 10.5.2.29 M V 3
- Rest Octets 10.5.2.34 O CSN.1
*/
size_t wpstart = wp;
LOG(DEBUG) << dest;
mCI.writeV(dest,wp);
LOG(DEBUG) << dest;
@@ -333,8 +339,9 @@ void L3SystemInformationType3::writeBody(L3Frame& dest, size_t &wp) const
LOG(DEBUG) << dest;
mRACHControlParameters.writeV(dest,wp);
LOG(DEBUG) << dest;
if (mHaveRestOctets) mRestOctets.writeV(dest,wp);
/*if (mHaveRestOctets)*/ mRestOctets.writeV(dest,wp);
LOG(DEBUG) << dest;
assert(wp-wpstart == fullBodyLength() * 8);
}
@@ -347,25 +354,75 @@ void L3SystemInformationType3::text(ostream& os) const
os << " cellOptions=(" << mCellOptions << ")";
os << " cellSelectionParameters=(" << mCellSelectionParameters << ")";
os << " RACHControlParameters=(" << mRACHControlParameters << ")";
if (mHaveRestOctets) os << " SI3RO=(" << mRestOctets << ")";
/*if (mHaveRestOctets)*/ os << " SI3RO=(" << mRestOctets << ")";
}
L3SIType4RestOctets::L3SIType4RestOctets()
{
#if GPRS_PAT|GPRS_TESTSI4
mRA_COLOUR = gConfig.getNum("GPRS.RA_COLOUR");
#endif
}
// GSM04.08 sec 10.5.2.35
void L3SIType4RestOctets::writeV(L3Frame &dest, size_t &wp) const
{
#if GPRS_PAT|GPRS_TESTSI4
dest.writeL(wp); // SI4 Rest Octets_O -> Optional selection parameters
dest.writeL(wp); // SI4 Rest Octets_O -> Optional Power offset
if (GPRS::GPRSConfig::IsEnabled()) {
dest.writeH(wp); // SI4 Rest Octets_O -> GPRS Indicator (present)
dest.writeField(wp,mRA_COLOUR,3);
dest.write0(wp); // SI13 message is sent on BCCH Norm schedule.
} else {
dest.writeL(wp); // SI4 Rest Octets_O -> GPRS Indicator (absent)
}
dest.writeL(wp); // Indicates 'Break Indicator' branch of message.
dest.writeL(wp); // Break Indicator == L means no extra info sent in SI Type 7 and 8.
#endif
}
size_t L3SIType4RestOctets::lengthBits() const
{
#if GPRS_PAT|GPRS_TESTSI4
return 1 + 1 + (GPRS::GPRSConfig::IsEnabled() ? 5 : 1) + 1 + 1;
#else
return 0;
#endif
}
void L3SIType4RestOctets::writeText(std::ostream& os) const
{
#if GPRS_PAT|GPRS_TESTSI4
if (GPRS::GPRSConfig::IsEnabled()) {
os << "GPRS enabled; RA_COLOUR=(" << mRA_COLOUR << ")";
}
#endif
}
L3SystemInformationType4::L3SystemInformationType4()
:L3RRMessageNRO()
:L3RRMessageRO(),
mHaveCBCH(gConfig.getStr("Control.SMSCB.Table").length() != 0),
mCBCHChannelDescription(SDCCH_4_2,0,gConfig.getNum("GSM.Identity.BSIC.BCC"),gConfig.getNum("GSM.Radio.C0"))
{ }
size_t L3SystemInformationType4::l2BodyLength() const
{
size_t len = mLAI.lengthV();
len += mCellSelectionParameters.lengthV();
len += mRACHControlParameters.lengthV();
if (mHaveCBCH) len += mCBCHChannelDescription.lengthTV();
return len;
}
size_t L3SystemInformationType4::restOctetsLength() const
{
return mType4RestOctets.lengthV();
}
void L3SystemInformationType4::writeBody(L3Frame& dest, size_t &wp) const
{
@@ -375,9 +432,16 @@ void L3SystemInformationType4::writeBody(L3Frame& dest, size_t &wp) const
- Cell Selection Parameters 10.5.2.4 M V 2
- RACH Control Parameters 10.5.2.29 M V 3
*/
size_t wpstart = wp;
mLAI.writeV(dest,wp);
mCellSelectionParameters.writeV(dest,wp);
mRACHControlParameters.writeV(dest,wp);
if (mHaveCBCH) {
mCBCHChannelDescription.writeTV(0x64,dest,wp);
}
mType4RestOctets.writeV(dest,wp);
while (wp & 7) { dest.writeL(wp); } // Zero to byte boundary.
assert(wp-wpstart == fullBodyLength() * 8);
}
@@ -387,11 +451,14 @@ void L3SystemInformationType4::text(ostream& os) const
os << "LAI=(" << mLAI << ")";
os << " cellSelectionParameters=(" << mCellSelectionParameters << ")";
os << " RACHControlParameters=(" << mRACHControlParameters << ")";
if (mHaveCBCH) {
os << "CBCHChannelDescription=(" << mCBCHChannelDescription << ")";
}
mType4RestOctets.writeText(os);
}
void L3SystemInformationType5::writeBody(L3Frame& dest, size_t &wp) const
{
/*
@@ -399,6 +466,12 @@ void L3SystemInformationType5::writeBody(L3Frame& dest, size_t &wp) const
- BCCH Frequency List 10.5.2.22 M V 16
*/
mBCCHFrequencyList.writeV(dest,wp);
wp -= 111;
int p = gConfig.getFloat("GSM.Cipher.RandomNeighbor") * (float)0xFFFFFF;
for (unsigned i = 1; i <= 111; i++) {
int b = ((random() & 0xFFFFFF) < p) | dest.peekField(wp, 1);
dest.writeField(wp, b, 1);
}
}
@@ -436,26 +509,31 @@ void L3SystemInformationType6::text(ostream& os) const
os << " NCCPermitted=(" << mNCCPermitted << ")";
}
void L3ImmediateAssignment::writeBody( L3Frame &dest, size_t &wp ) const
{
/*
- Page Mode 10.5.2.26 M V 1/2
- Dedicated mode or TBF 10.5.2.25b M V 1/2
- Channel Description 10.5.2.5 C V 3
- Request Reference 10.5.2.30 M V 3
- Timing Advance 10.5.2.40 M V 1
(ignoring optional elements)
*/
size_t wpstart = wp;
/*
- Page Mode 10.5.2.26 M V 1/2
- Dedicated mode or TBF 10.5.2.25b M V 1/2
- Channel Description 10.5.2.5 C V 3
- Request Reference 10.5.2.30 M V 3
- Timing Advance 10.5.2.40 M V 1
(ignoring optional elements)
*/
// reverse order of 1/2-octet fields
// (pat) Because we are writing MSB first here.
mDedicatedModeOrTBF.writeV(dest, wp);
mPageMode.writeV(dest, wp);
mChannelDescription.writeV(dest, wp);
mChannelDescription.writeV(dest, wp); // From L3ChannelDescription
mRequestReference.writeV(dest, wp);
mTimingAdvance.writeV(dest, wp);
// No mobile allocation in non-hopping systems.
// A zero-length LV. Just write L=0.
// A zero-length LV. Just write L=0. (pat) LV, etc. defined in GSM04.07 sec 11.2.1.1
dest.writeField(wp,0,8);
//assert(wp-wpstart == l2BodyLength() * 8);
// Note: optional starting Time not implemented.
mIARestOctets.writeBits(dest,wp);
assert(wp-wpstart == fullBodyLength() * 8);
}
@@ -466,6 +544,7 @@ void L3ImmediateAssignment::text(ostream& os) const
os << " ChannelDescription=("<<mChannelDescription<<")";
os << " RequestReference=("<<mRequestReference<<")";
os << " TimingAdvance="<<mTimingAdvance;
mIARestOctets.text(os);
}
@@ -652,6 +731,7 @@ void L3ApplicationInformation::writeBody( L3Frame &dest, size_t &wp ) const
- APDU Data 10.5.2.50 M LV N
*/
// reverse order of 1/2-octet fields
// (pat) Because we are writing MSB first here.
static size_t start = wp;
LOG(DEBUG) << "L3ApplicationInformation: written " << wp - start << " bits";
mFlags.writeV(dest, wp);
@@ -674,6 +754,7 @@ void L3ApplicationInformation::text(ostream& os) const
void L3ApplicationInformation::parseBody(const L3Frame& src, size_t &rp)
{
// reverse order of 1/2-octet fields
// (pat) Because we are writing MSB first here.
mFlags.parseV(src, rp);
mID.parseV(src, rp);
mData.parseLV(src, rp);
@@ -685,10 +766,34 @@ size_t L3ApplicationInformation::l2BodyLength() const
}
// 3GPP 44.018 9.1.13b
// (pat 3-2012) Added parsing.
void L3GPRSSuspensionRequest::parseBody(const L3Frame &src, size_t& rp)
{
// We don't really parse this yet.
return;
// The TLLI is what we most need out of this message to identify the MS.
// Note that TLLI is not just a simple number; encoding defined in 23.003.
// We dont worry about it here; the SGSN handles that.
mTLLI = src.readField(rp,4*8);
// 3GPP 24.008 10.5.5.15 Routing Area Identification.
// Similar to L3LocationAreaIdentity but includes RAC too.
// We dont really care about it now, and when we do, all we will care
// is if it matches our own or not.
// Just squirrel away the 6 bytes as a ByteVector.
// This is an immediate object whose memory will be deleted automatically.
mRaId = ByteVector(src.segment(rp,6*8));
rp += 6*8; // And skip over it.
mSuspensionCause = src.readField(rp,1*8); // 10.5.2.47
// Optional service support, IEI=0x01.
// It is for MBMS and we dont really care about it, but get it anyway.
if (rp>=src.size()+2*8 && 0x01 == src.peekField(rp,8)) {
rp+=8; // Skip over the IEI type
mServiceSupport = src.readField(rp,8);
}
}
void L3GPRSSuspensionRequest::text(ostream& os) const
{
L3RRMessage::text(os);
os <<LOGVAR(mTLLI)<<LOGVAR(mRaId)<<LOGVAR(mSuspensionCause)<<LOGVAR(mServiceSupport);
}
@@ -713,4 +818,106 @@ void L3ClassmarkChange::text(ostream& os) const
os << " +classmark=(" << mAdditionalClassmark << ")";
}
size_t L3HandoverCommand::l2BodyLength() const
{
size_t sum =
mCellDescription.lengthV() +
mChannelDescriptionAfter.lengthV() +
mHandoverReference.lengthV() +
mPowerCommandAccessType.lengthV() +
mSynchronizationIndication.lengthV();
return sum;
}
void L3HandoverCommand::writeBody(L3Frame& frame, size_t& wp) const
{
mCellDescription.writeV(frame,wp);
mChannelDescriptionAfter.writeV(frame,wp);
mHandoverReference.writeV(frame,wp);
mPowerCommandAccessType.writeV(frame,wp);
mSynchronizationIndication.writeV(frame,wp);
}
void L3HandoverCommand::text(ostream& os) const
{
L3RRMessage::text(os);
os << "cell=(" << mCellDescription << ")";
os << " channelr=(" << mChannelDescriptionAfter << ")";
os << " ref=" << mHandoverReference;
os << " powerAndAccess=(" << mPowerCommandAccessType << ")";
os << " synchronization=(" << mSynchronizationIndication << ")";
}
void L3HandoverComplete::parseBody(const L3Frame& frame, size_t& rp)
{
mCause.parseV(frame,rp);
}
void L3HandoverComplete::text(ostream& os) const
{
L3RRMessage::text(os);
os << "cause=" << mCause;
}
void L3HandoverFailure::parseBody(const L3Frame& frame, size_t& rp)
{
mCause.parseV(frame,rp);
}
void L3HandoverFailure::text(ostream& os) const
{
L3RRMessage::text(os);
os << "cause=" << mCause;
}
int L3CipheringModeCommand::MTI() const
{
return CipheringModeCommand;
}
void L3CipheringModeCommand::writeBody(L3Frame& frame, size_t& wp) const
{
// reverse order of 1/2-octet fields
mCipheringResponse.writeV(frame,wp);
mCipheringModeSetting.writeV(frame,wp);
}
void L3CipheringModeCommand::text(ostream& os) const
{
L3RRMessage::text(os);
os << "ciphering mode setting=(" << mCipheringModeSetting << ")";
os << " ciphering response=(" << mCipheringResponse << ")";
}
int L3CipheringModeComplete::MTI() const
{
return CipheringModeComplete;
}
void L3CipheringModeComplete::parseBody(const L3Frame& frame, size_t& rp)
{
// mobile equipment identity optional
}
void L3CipheringModeComplete::text(ostream& os) const
{
L3RRMessage::text(os);
}
void L3PhysicalInformation::writeBody(L3Frame& frame, size_t& wp) const
{
mTA.writeV(frame,wp);
}
void L3PhysicalInformation::text(ostream& os) const
{
L3RRMessage::text(os);
os << "TA=" << mTA;
}
// vim: ts=4 sw=4

View File

@@ -4,24 +4,14 @@
* Copyright 2008, 2010 Free Software Foundation, Inc.
* Copyright 2011 Kestrel Signal Processing, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -35,6 +25,7 @@
#include "GSML3Message.h"
#include "GSML3CommonElements.h"
#include "GSML3RRElements.h"
#include <ByteVector.h>
namespace GSM {
@@ -42,6 +33,20 @@ namespace GSM {
/**
This a virtual class for L3 messages in the Radio Resource protocol.
These messages are defined in GSM 04.08 9.1.
(pat) The GSM 04.08 and 04.18 specs list all these messages together, but say
nothing about their transport mechanisms, which are wildly different and described elsewhere.
For example, GPRS Mobility Management messages are handled inside the SGSN,
which wraps them in an LLC protocol and sends them to the RLC/MAC layer
(via BSSG and NS protocols, in which these messages reside temporarily)
which wraps them in an RLC Header, then wraps them with a MAC header,
before delivering to the radio transmit, which munges them even further.
And by the way, if the MS is in DTM (Dual Transfer Mode) the MAC layer
may (or should?) unwrap the L3 Message from its LLC wrapper and send it on a
dedicated RR message channel instead of sending it via GPRS PDCH.
Note that the message numbers are reused several times in the tables
for different purposes, for example, MessageTypes for Mobility Management reuse
numbers in Message Types for Radio Rsource Management.
*/
class L3RRMessage : public L3Message {
@@ -64,7 +69,7 @@ class L3RRMessage : public L3Message {
SystemInformationType7=0x1f,
SystemInformationType8=0x18,
SystemInformationType9=0x04,
SystemInformationType13=0x00,
SystemInformationType13=0x00, // (pat) yes, this is correct.
SystemInformationType16=0x3d,
SystemInformationType17=0x3e,
//@}
@@ -89,10 +94,14 @@ class L3RRMessage : public L3Message {
///@name Handover
//@{
HandoverCommand=0x2b,
HandoverComplete=0x2c,
HandoverFailure=0x28,
PhysicalInformation=0x2d,
//@}
///@name ciphering
//@{
CipheringModeCommand=0x35,
CipheringModeComplete=0x32,
//@}
///@name miscellaneous
//@{
@@ -108,12 +117,14 @@ class L3RRMessage : public L3Message {
//@{
SynchronizationChannelInformation=0x100,
ChannelRequest=0x101,
HandoverAccess=0x102,
//@}
///@name application information - used for RRLP
//@{
ApplicationInformation=0x38,
//@}
};
static const char *name(MessageType mt);
L3RRMessage():L3Message() { }
@@ -129,6 +140,9 @@ std::ostream& operator<<(std::ostream& os, L3RRMessage::MessageType);
/** Subclass for L3 RR Messages with no rest octets. */
// (pat) L3RRMessagesRO subclass must define:
// l2BodyLength - length of body only, and there are no rest octets.
// writeBody() - writes the body.
class L3RRMessageNRO : public L3RRMessage {
public:
@@ -140,6 +154,10 @@ class L3RRMessageNRO : public L3RRMessage {
};
/** Subclass for L3 RR messages with rest octets */
// (pat) L3RRMessagesRO subclass must define:
// l2BodyLength - length of body only, in bytes
// restOctetsLength - length of rest octets only, in bytes.
// writeBody() - writes the body AND the rest octets.
class L3RRMessageRO : public L3RRMessage {
public:
@@ -293,7 +311,13 @@ class L3SystemInformationType2 : public L3RRMessageNRO {
public:
L3SystemInformationType2():L3RRMessageNRO() {}
//L3SystemInformationType2():L3RRMessageNRO() {}
L3SystemInformationType2(const std::vector<unsigned>& wARFCNs)
:L3RRMessageNRO(),
mBCCHFrequencyList(wARFCNs)
{ }
void BCCHFrequencyList(const L3NeighborCellsDescription& wBCCHFrequencyList)
{ mBCCHFrequencyList = wBCCHFrequencyList; }
@@ -335,14 +359,16 @@ class L3SystemInformationType3 : public L3RRMessageRO {
L3CellSelectionParameters mCellSelectionParameters;
L3RACHControlParameters mRACHControlParameters;
bool mHaveRestOctets;
// (pat) GSM04.08 table 9.32 says RestOctets are mandatory, so why are they optional here?
// I moved this control into the rest octets and changed the logic.
//bool mHaveRestOctets;
// (pat) The rest of the Type3 setup information is in L3SI3RestOctets:
L3SI3RestOctets mRestOctets;
public:
L3SystemInformationType3()
:L3RRMessageRO(),
mHaveRestOctets(gConfig.defines("GSM.SI3RO"))
:L3RRMessageRO()
{ }
void CI(const L3CellIdentity& wCI) { mCI = wCI; }
@@ -372,6 +398,15 @@ class L3SystemInformationType3 : public L3RRMessageRO {
struct L3SIType4RestOctets
{
unsigned mRA_COLOUR;
L3SIType4RestOctets();
void writeV(L3Frame &dest, size_t &wp) const;
void writeText(std::ostream& os) const;
size_t lengthBits() const;
size_t lengthV() const { return (lengthBits()+7)/8; }
};
/**
@@ -379,14 +414,19 @@ class L3SystemInformationType3 : public L3RRMessageRO {
- Location Area Identification 10.5.1.3 M V 5
- Cell Selection Parameters 10.5.2.4 M V 2
- RACH Control Parameters 10.5.2.29 M V 3
pats note: We included the GPRS Indicator in the rest octets for SI3, so I am assuming
we do not also have to included it in SI4.
*/
class L3SystemInformationType4 : public L3RRMessageNRO {
class L3SystemInformationType4 : public L3RRMessageRO {
private:
L3LocationAreaIdentity mLAI;
L3CellSelectionParameters mCellSelectionParameters;
L3RACHControlParameters mRACHControlParameters;
bool mHaveCBCH;
L3ChannelDescription mCBCHChannelDescription;
L3SIType4RestOctets mType4RestOctets;
public:
@@ -403,7 +443,7 @@ class L3SystemInformationType4 : public L3RRMessageNRO {
int MTI() const { return (int)SystemInformationType4; }
size_t l2BodyLength() const;
size_t restOctetsLength() const;
void writeBody(L3Frame &dest, size_t &wp) const;
void text(std::ostream&) const;
};
@@ -423,7 +463,12 @@ class L3SystemInformationType5 : public L3RRMessageNRO {
public:
L3SystemInformationType5():L3RRMessageNRO() { }
//L3SystemInformationType5():L3RRMessageNRO() { }
L3SystemInformationType5(const std::vector<unsigned>& wARFCNs)
:L3RRMessageNRO(),
mBCCHFrequencyList(wARFCNs)
{ }
void BCCHFrequencyList(const L3NeighborCellsDescription& wBCCHFrequencyList)
{ mBCCHFrequencyList = wBCCHFrequencyList; }
@@ -477,38 +522,114 @@ class L3SystemInformationType6 : public L3RRMessageNRO {
};
// GSM 04.08 10.5.2.16
struct L3IARestOctets : public GenericMessageElement
{
// Someday this may include frequence parameters, but now all it can be is Packet Assignment.
struct L3IAPacketAssignment mPacketAssignment;
size_t lengthBits() const {
return mPacketAssignment.lengthBits();
}
void writeBits(L3Frame &dest, size_t &wp) const {
mPacketAssignment.writeBits(dest, wp);
while (wp & 7) { dest.writeL(wp); } // fill out to byte boundary.
}
void text(std::ostream& os) const {
mPacketAssignment.text(os);
}
};
/** Immediate Assignment, GSM 04.08 9.1.18 */
class L3ImmediateAssignment : public L3RRMessageNRO {
// (pat) The elements below correspond directly to the parts of the Immediate Assignment
// message content as defined in 9.1.18, table 9.18.
// (pat) some deobfuscation.
// // Example from Control::AccessGrantResponder()
// L3ImmediateAssignment assign( // Initialization of assign message
// L3RequestReference(
// unsigned RA, // => L3RequestReference::mRA
// GSM::Time &when // => L3RequestReference::mT1p,mT2,mT3
// ), // {/*empty body*/}
// LogicalChannel *LCH->channelDescription(),
// // returns L3ChannelDescription(
// // LCH->mL1.typeAndOffset(), // => L3ChannelDescription::mTypeAndOffset;
// // LCH->mL1.TN(), // => L3ChannelDescription::mTN
// // LCH->mL1.TSC(), // => L3ChannelDescription::mTSC
// // LCH->mL1.ARFCN()) // => L3ChannelDescription::mARFCN;
// // { L3ChannelDescription::mHFlag = 0, ::mMAIO = 0, ::mHSN = 0 }
// L3TimingAdvance(
// int initialTA // => L3TimingAdvance::mTimingAdvance
// // L3TimingAdvance : L3ProtocolElement() [virtual class, no constructor]
// )
// );
class L3ImmediateAssignment : public L3RRMessageRO
{
private:
L3PageMode mPageMode;
L3DedicatedModeOrTBF mDedicatedModeOrTBF;
L3RequestReference mRequestReference;
// (pat) Note that either "Channel Description" or "Packet Channel Description"
// appears in the message. They are identical except for some new options
// added to Packet Channel Description.
L3ChannelDescription mChannelDescription;
L3TimingAdvance mTimingAdvance;
// Used for Packet uplink/downlink assignment messages, which, when transmitted
// on CCCH, appear in the rest octets of the Immediate Assignment message.
struct L3IARestOctets mIARestOctets;
public:
size_t restOctetsLength() const { return (mIARestOctets.lengthBits()+7)/8; }
L3ImmediateAssignment(
const L3RequestReference& wRequestReference,
const L3ChannelDescription& wChannelDescription,
const L3TimingAdvance& wTimingAdvance = L3TimingAdvance(0))
:L3RRMessageNRO(),
const L3TimingAdvance& wTimingAdvance = L3TimingAdvance(0),
const bool forTBF = false, bool wDownlink = false)
:L3RRMessageRO(),
mPageMode(0),
mDedicatedModeOrTBF(forTBF,wDownlink),
mRequestReference(wRequestReference),
mChannelDescription(wChannelDescription),
mTimingAdvance(wTimingAdvance)
{}
int MTI() const { return (int)ImmediateAssignment; }
size_t l2BodyLength() const { return 9; }
size_t l2BodyLength() const {
// 1/2: page mode
// 1/2: Dedicated mode or TBF
// 3: channel description or packet channel description
// 3: request reference
// 1: timing advance
// 1-9: Mobile Allocation (not implemented, so just 1 byte)
// 0: starting time, not implemented
// = 9 total bytes.
return 9;
}
// (pat) Return the PacketAssignment part of the message for the client to fill in.
// I did it this way to cause the least change to the preexisting L3ImmediateAssignment class.
struct L3IAPacketAssignment *packetAssign() { return &mIARestOctets.mPacketAssignment; }
// (pat) writeBody called via:
// CCCHLogicalChannel:send(L3RRMessage msg)
// calls L3FrameFIFO mq.L3FrameFIFO::write(new L3Frame(L3Message msg,UNIT_DATA));
// L3Frame::L3Frame(L3Message&,Primitive) : BitVector(msg.bitsNeeded)
// mPrimitive(wPrimitive),
// mL2Length(wPrimitive) { L3Message msg.write(); }
// L3Message::write() calls writeBody()
void writeBody(L3Frame &dest, size_t &wp) const;
void text(std::ostream&) const;
};
@@ -549,12 +670,17 @@ class L3ChannelRelease : public L3RRMessageNRO {
private:
L3RRCause mRRCause;
// 3GPP 44.018 10.5.2.14c GPRS Resumption.
// It is one bit to specify to the MS whether GPRS services should resume.
// Kinda important.
bool mGprsResumptionPresent;
bool mGprsResumptionBit;
public:
/** The default cause is 0x0, "normal event". */
L3ChannelRelease(const L3RRCause& cause = L3RRCause(0x0))
:L3RRMessageNRO(),mRRCause(cause)
:L3RRMessageNRO(),mRRCause(cause),mGprsResumptionPresent(0)
{}
int MTI() const { return (int) ChannelRelease; }
@@ -819,16 +945,37 @@ class L3ApplicationInformation : public L3RRMessageNRO {
};
/** GSM 04.08 9.1.13b */
class L3GPRSSuspensionRequest : public L3RRMessageNRO {
/** GSM 04.08 (or 04.18) 9.1.13b */
// 44.018 3.4.25 GPRS Suspension procedure.
// 44.018 3.4.13 RR Connection releasee procedure - GPRS resumption if includes:
// 10.5.2.14c GPRS Resumption IEI
class L3GPRSSuspensionRequest : public L3RRMessageNRO
{ public:
// The TLLI is what we most need out of this message to identify the MS.
// Note that TLLI is not just a simple number; encoding defined in 23.003.
// We dont worry about it here; the SGSN handles that.
uint32_t mTLLI;
// 3GPP 24.008 10.5.5.15 Routing Area Identification.
// Similar to L3LocationAreaIdentity but includes RAC too.
// We dont really care about it now, and when we do, all we will care
// is if it matches our own or not, so just squirrel away the 6 bytes as a ByteVector.
// This is an immediate object whose memory will be deleted automatically.
ByteVector mRaId;
// Suspension cause 44.018 10.5.2.47.
// Can be 0: mobile originated call, 1: Location area update, 2: SMS, or others
uint8_t mSuspensionCause;
// Optional service support, IEI=0x01.
// It is for MBMS and we dont really care about it, but get it anyway.
uint8_t mServiceSupport;
public:
// Must init only the optional elements:
L3GPRSSuspensionRequest() : mServiceSupport(0) {}
int MTI() const { return (int) GPRSSuspensionRequest; }
size_t l2BodyLength() const { return 11; }
size_t l2BodyLength() const { return 11; } // This is uplink only so not relevant.
void parseBody(const L3Frame&, size_t&);
void text(std::ostream&) const;
};
@@ -865,9 +1012,209 @@ class L3ClassmarkChange : public L3RRMessageNRO {
};
/** GSM 04.08 9.1.43a */
// (pat) Someone kindly added this before I got here...
// SI13 includes GPRS Cell Options in its rest octets,
// so we broadcast it on BCCH if GPRS is supported.
class L3SystemInformationType13 : public L3RRMessageRO {
protected:
L3SI13RestOctets mRestOctets;
public:
L3SystemInformationType13()
:L3RRMessageRO()
{ }
int MTI() const { return (int)SystemInformationType13; }
size_t l2BodyLength() const { return 0; }
size_t restOctetsLength() const { return mRestOctets.lengthV(); }
void writeBody(L3Frame &dest, size_t &wp) const
{
size_t wpstart = wp;
mRestOctets.writeV(dest,wp);
assert(wp-wpstart == fullBodyLength() * 8);
}
void text(std::ostream& os) const
{ L3RRMessage::text(os); os << mRestOctets; }
};
class L3HandoverCommand : public L3RRMessageNRO {
protected:
L3CellDescription mCellDescription;
L3ChannelDescription2 mChannelDescriptionAfter;
L3HandoverReference mHandoverReference;
L3PowerCommandAndAccessType mPowerCommandAccessType;
L3SynchronizationIndication mSynchronizationIndication;
public:
L3HandoverCommand(const L3CellDescription& wCellDescription,
const L3ChannelDescription2 wChannelDescriptionAfter,
const L3HandoverReference& wHandoverReference,
const L3PowerCommandAndAccessType& wPowerCommandAccessType,
const L3SynchronizationIndication& wSynchronizationIndication)
:L3RRMessageNRO(),
mCellDescription(wCellDescription),
mChannelDescriptionAfter(wChannelDescriptionAfter),
mHandoverReference(wHandoverReference),
mPowerCommandAccessType(wPowerCommandAccessType),
mSynchronizationIndication(wSynchronizationIndication)
{ }
int MTI() const { return (int) HandoverCommand; }
size_t l2BodyLength() const;
void writeBody(L3Frame&, size_t&) const;
void text(std::ostream&) const;
};
/** GSM 04.08 9.1.16 */
class L3HandoverComplete : public L3RRMessageNRO {
protected:
L3RRCause mCause;
public:
int MTI() const { return (int) HandoverComplete; }
size_t l2BodyLength() const { return mCause.lengthV(); }
void parseBody(const L3Frame&, size_t&);
void text(std::ostream&) const;
const L3RRCause& cause() const { return mCause; }
};
/** GSM 04.08 9.1.17 */
class L3HandoverFailure : public L3RRMessageNRO {
protected:
L3RRCause mCause;
public:
int MTI() const { return (int) HandoverFailure; }
size_t l2BodyLength() const { return mCause.lengthV(); }
void parseBody(const L3Frame&, size_t&);
void text(std::ostream&) const;
const L3RRCause& cause() const { return mCause; }
};
/** GSM 04.08 9.1.9 */
class L3CipheringModeCommand : public L3RRMessageNRO {
protected:
L3CipheringModeSetting mCipheringModeSetting;
L3CipheringModeResponse mCipheringResponse;
public:
L3CipheringModeCommand(L3CipheringModeSetting wCipheringModeSetting, L3CipheringModeResponse wCipheringResponse)
: mCipheringModeSetting(wCipheringModeSetting),
mCipheringResponse(wCipheringResponse)
{ }
int MTI() const;
size_t l2BodyLength() const { return 1; }
void writeBody(L3Frame&, size_t&) const;
void text(std::ostream&) const;
};
/** GSM 04.08 9.1.10 */
class L3CipheringModeComplete : public L3RRMessageNRO {
protected:
public:
int MTI() const;
size_t l2BodyLength() const { return 0; }
void parseBody(const L3Frame&, size_t&);
void text(std::ostream&) const;
};
/** GSM 04.08 9.1.28 */
class L3PhysicalInformation : public L3RRMessageNRO {
protected:
L3TimingAdvance mTA;
public:
L3PhysicalInformation(const L3TimingAdvance& wTA)
:L3RRMessageNRO(),
mTA(wTA)
{ }
int MTI() const { return (int) PhysicalInformation; }
size_t l2BodyLength() const { return mTA.lengthV(); }
void writeBody(L3Frame&, size_t&) const;
void text(std::ostream&) const;
};
#if 0
/**
GSM 04.08 9.1.14
This messages has no parse or write methods, but is used to
transfer information from L1 to the control layer.
*/
class L3HandoverAccess : public L3RRMessageNRO {
protected:
unsigned mReference;
float mTimingError;
float mRSSI;
public:
L3HandoverAccess(unsigned wReference, unsigned wTimingError, float wRSSI)
:L3RRMessageNRO(),
mReference(wReference),mTimingError(wTimingError),mRSSI(wRSSI)
{ }
int MTI() const { return (int) HandoverAccess; }
size_t l2BodyLength() const { return 1; }
unsigned reference() const { return mReference; }
float timingError() const { return mTimingError; }
float RSSI() const { return mRSSI; }
};
#endif
} // GSM
#endif
// vim: ts=4 sw=4

View File

@@ -1,28 +1,20 @@
/**@file Logical Channel. */
/*
* Copyright 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
* Copyright 2011 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -31,15 +23,16 @@
#include "GSML3RRElements.h"
#include "GSML3Message.h"
#include "GSML3RRMessages.h"
#include "GSMSMSCBL3Messages.h"
#include "GSMLogicalChannel.h"
#include "GSMConfig.h"
#include <TransactionTable.h>
#include <SMSControl.h>
#include <ControlCommon.h>
#include "GPRSExport.h"
#include <Logger.h>
#undef WARNING
using namespace std;
using namespace GSM;
@@ -49,10 +42,14 @@ using namespace GSM;
void LogicalChannel::open()
{
LOG(INFO);
LOG(DEBUG);
if (mSACCH) mSACCH->open();
if (mL1) mL1->open();
LOG(DEBUG);
if (mL1) mL1->open(); // (pat) L1FEC::open()
LOG(DEBUG);
for (int s=0; s<4; s++) {
if (mL2[s]) mL2[s]->open();
LOG(DEBUG) << "SAPI=" << s << " open complete";
}
// Empty any stray transactions in the FIFO from the SIP layer.
while (true) {
@@ -61,9 +58,11 @@ void LogicalChannel::open()
LOG(WARNING) << "flushing stray transaction " << *trans;
// FIXME -- Shouldn't we be deleting these?
}
LOG(DEBUG);
}
// (pat) This is connecting layer2, not layer1.
void LogicalChannel::connect()
{
mMux.downstream(mL1);
@@ -75,9 +74,11 @@ void LogicalChannel::connect()
}
// (pat) This is only called during initialization, using the createCombination*() functions.
// The L1FEC->downstream hooks the radio to this logical channel, permanently.
void LogicalChannel::downstream(ARFCNManager* radio)
{
assert(mL1);
assert(mL1); // This is L1FEC
mL1->downstream(radio);
if (mSACCH) mSACCH->downstream(radio);
}
@@ -115,23 +116,68 @@ void CCCHLogicalChannel::open()
}
void CCCHLogicalChannel::serviceLoop()
// (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 = mQ.read();
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;
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";
}
}
@@ -144,6 +190,77 @@ void *GSM::CCCHLogicalChannelServiceLoopAdapter(CCCHLogicalChannel* chan)
return NULL;
}
#if ENABLE_PAGING_CHANNELS
// (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;
}
#endif
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;
}
L3ChannelDescription LogicalChannel::channelDescription() const
@@ -177,7 +294,7 @@ SDCCHLogicalChannel::SDCCHLogicalChannel(
SAP3L2->master(SAP0L2);
mL2[0] = SAP0L2;
mL2[3] = SAP3L2;
mSACCH = new SACCHLogicalChannel(wCN,wTN,wMapping.SACCH());
mSACCH = new SACCHLogicalChannel(wCN,wTN,wMapping.SACCH(),this);
connect();
}
@@ -188,8 +305,10 @@ SDCCHLogicalChannel::SDCCHLogicalChannel(
SACCHLogicalChannel::SACCHLogicalChannel(
unsigned wCN,
unsigned wTN,
const MappingPair& wMapping)
: mRunning(false)
const MappingPair& wMapping,
const LogicalChannel *wHost)
: mRunning(false),
mHost(wHost)
{
mSACCHL1 = new SACCHL1FEC(wCN,wTN,wMapping);
mL1 = mSACCHL1;
@@ -232,15 +351,17 @@ L3Message* processSACCHMessage(L3Frame *l3frame)
}
void SACCHLogicalChannel::serviceLoop()
{
// run the loop
unsigned count = 0;
while (true) {
// Throttle back if not active.
if (!active()) {
OBJLOG(DEBUG) << "SACCH sleeping";
//OBJLOG(DEBUG) << "SACCH sleeping";
sleepFrames(51);
continue;
}
@@ -249,8 +370,12 @@ void SACCHLogicalChannel::serviceLoop()
// otherwise sleep and continue;
// Send alternating SI5/SI6.
// These L3Frames were created with the UNIT_DATA primivitive.
OBJLOG(DEBUG) << "sending SI5/6 on SACCH";
if (count%2) LogicalChannel::send(gBTS.SI5Frame());
if (count%2) {
gBTS.regenerateSI5();
LogicalChannel::send(gBTS.SI5Frame());
}
else LogicalChannel::send(gBTS.SI6Frame());
count++;
@@ -274,6 +399,8 @@ void SACCHLogicalChannel::serviceLoop()
// Add the measurement results to the table
// Note that the typeAndOffset of a SACCH match the host channel.
gPhysStatus.setPhysical(this, mMeasurementResults);
// Check for handover requirement.
Control::HandoverDetermination(mMeasurementResults,this);
} else {
OBJLOG(NOTICE) << "SACCH SAP0 sent unaticipated message " << rrMessage;
}
@@ -320,6 +447,10 @@ void SACCHLogicalChannel::serviceLoop()
}
}
// Did we get anything from the phone?
// If not, we may have lost contact. Bump the RSSI to induce more power
if (nothing) RSSIBumpDown(gConfig.getNum("Control.SACCHTimeout.BumpDown"));
// Nothing happened?
if (nothing) break;
}
@@ -336,18 +467,22 @@ void *GSM::SACCHLogicalChannelServiceLoopAdapter(SACCHLogicalChannel* chan)
// These have to go into the .cpp file to prevent an illegal forward reference.
void LogicalChannel::setPhy(float wRSSI, float wTimingError)
{ assert(mSACCH); mSACCH->setPhy(wRSSI,wTimingError); }
void LogicalChannel::setPhy(float wRSSI, float wTimingError, double wTimestamp)
{ assert(mSACCH); mSACCH->setPhy(wRSSI,wTimingError,wTimestamp); }
void LogicalChannel::setPhy(const LogicalChannel& other)
{ assert(mSACCH); mSACCH->setPhy(*other.SACCH()); }
float LogicalChannel::RSSI() const
{ assert(mSACCH); return mSACCH->RSSI(); }
float LogicalChannel::timingError() const
{ assert(mSACCH); return mSACCH->timingError(); }
double LogicalChannel::timestamp() const
{ assert(mSACCH); return mSACCH->timestamp(); }
int LogicalChannel::actualMSPower() const
{ assert(mSACCH); return mSACCH->actualMSPower(); }
int LogicalChannel::actualMSTiming() const
{ assert(mSACCH); return mSACCH->actualMSTiming(); }
const L3MeasurementResults& LogicalChannel::measurementResults() const
{ assert(mSACCH); return mSACCH->measurementResults(); }
@@ -362,13 +497,30 @@ TCHFACCHLogicalChannel::TCHFACCHLogicalChannel(
// SAP1 and SAP2 are not used.
mL2[0] = new FACCHL2(1,0);
mL2[3] = new FACCHL2(1,3);
mSACCH = new SACCHLogicalChannel(wCN,wTN,wMapping.SACCH());
mSACCH = new SACCHLogicalChannel(wCN,wTN,wMapping.SACCH(),this);
connect();
}
CBCHLogicalChannel::CBCHLogicalChannel(const CompleteMapping& wMapping)
{
mL1 = new CBCHL1FEC(wMapping.LCH());
mL2[0] = new CBCHL2;
mSACCH = new SACCHLogicalChannel(0,0,wMapping.SACCH(),this);
connect();
}
void CBCHLogicalChannel::send(const L3SMSCBMessage& msg)
{
L3Frame frame(UNIT_DATA,88*8);
msg.write(frame);
LogicalChannel::send(frame);
}
bool LogicalChannel::waitForPrimitive(Primitive primitive, unsigned timeout_ms)
@@ -398,6 +550,20 @@ void LogicalChannel::waitForPrimitive(Primitive primitive)
}
}
L3Frame* LogicalChannel::waitForEstablishOrHandover()
{
while (true) {
L3Frame *req = recv();
if (req==NULL) continue;
if (req->primitive()==ESTABLISH) return req;
if (req->primitive()==HANDOVER_ACCESS) return req;
LOG(INFO) << "LogicalChannel: Ignored primitive:"<<req->primitive();
delete req;
}
return NULL; // to keep the compiler happy
}
ostream& GSM::operator<<(ostream& os, const LogicalChannel& chan)
{

View File

@@ -4,24 +4,16 @@
* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -61,6 +53,7 @@ typedef InterthreadQueue<Control::TransactionEntry> TransactionFIFO;
class SACCHLogicalChannel;
class L3Message;
class L3RRMessage;
class L3SMSCBMessage;
/**
@@ -70,6 +63,8 @@ class L3RRMessage;
The concept of the logical channel and the channel types are defined in GSM 04.03.
This is virtual class; specific channel types are subclasses.
*/
// (pat) It would be nice to break this into two classes: one that has the base functionality
// that GPRS will not use, and one with all the RR specific channel stuff.
class LogicalChannel {
protected:
@@ -118,12 +113,17 @@ public:
/**@name Pass-throughs. */
//@{
// Pat 5-27-2012: Let the LogicalChannel know the next scheduled write time.
GSM::Time getNextWriteTime() { return mL1->encoder()->getNextWriteTime(); }
/** Set L1 physical parameters from a RACH or pre-exsting channel. */
virtual void setPhy(float wRSSI, float wTimingError);
virtual void setPhy(float wRSSI, float wTimingError, double wTimestamp);
/* Set L1 physical parameters from an existing logical channel. */
virtual void setPhy(const LogicalChannel&);
virtual const L3MeasurementResults& measurementResults() const;
/**@name L3 interfaces */
//@{
@@ -146,6 +146,48 @@ public:
*/
virtual void send(const L3Frame& frame, unsigned SAPI=0)
{
// (pat) Note that writeHighSide is overloaded per class hierarchy, and is also used
// for entirely unrelated classes, which are distinguishable (by humans,
// not by the compiler, which considers them unrelated functions)
// by arguments of L3Frame or L2Frame.
//
// For traffic channels:
// This function calls virtual L2DL::writeHighSide(L3Frame) which I think maps
// to L2LAPDm::writeHighSide() which interprets the primitive, and then
// sends traffic data through sendUFrameUI(L3Frame) which creates an L2Frame
// and sends it through several irrelevant functions to L2LAPDm::writeL1
// which calls (SAPMux)mDownstream->SAPMux::writeHighSide(L2Frame),
// which does nothing but call mL1->writeHighSide(L2Frame), which is a pass-through
// except that the SapMux uses mDownStream which is copied from mL1, so there is a
// chance to redirect it. But wouldn't that be an error?
// Anyway, L1Encoder::writeHighSide is usually overridden.
// For TCH, it goes to XCCHL1Encoder::writeHighSide() which processes
// the L2Frame primitive, then sends traffic data to TCHFACCHL1Encoder::sendFrame(),
// which just enqueues the frame - it does not block.
// A thread runs GSM::TCHFACCHL1EncoderRoutine() which
// calls TCHFACCHL1Encoder::dispatch() which is synchronized with the gBTS clock,
// unsynchronized with the queue, because it must send data no matter what.
// Eventually it encodes the data and
// calls (ARFCNManager*)mDownStream->writeHighSideTx(), which writes to the socket.
//
// For CCCH channels:
// CCCHLogicalChannel::send(L3RRMessage) wraps the message in an L3Frame
// and enqueues the message on CCCHLogicalChannel::mQ.
// CCCHLogicalChannel::serviceLoop() pulls it out and sends it to
// LogicalChannel::send(L3Frame) [this function], which is virtual, but I dont think it
// is over-ridden, so message goes to L2DL::writeHighSide(L3Frame) which
// is over-ridden to CCCHL2::writeHighSide(L3Frame) which creates an L2Frame
// and calls (SAPMux)mDownstream->writeHighSide(L2Frame), which just
// calls (L1FEC)mDownStream->writeHighSide(L2Frame), which
// (because CCCHL1FEC is nearly empty) just
// calls (L1Encoder)mEncoder->writeHighSide(L2Frame), which maps
// to CCCHL1Encoder which maps to XCCHL1Encoder::writeHighSide(L2Frame),
// which processes the L2Frame primitive, and sends traffic data to
// XCCHL1Encoder::sendFrame(L2Frame), which encodes the frame and then calls
// XCCHL1Encoder::transmit(implicit mI arg with encoded burst) that
// finally blocks until L1Encoder::mPrevWriteTime occurs, then sets the
// burst time to L1Encoder::mNextWriteTime and
// calls (ARFCNManager*)mDownStream->writeHighSideTx() which writes to the socket.
assert(mL2[SAPI]);
LOG(DEBUG) << "SAP"<< SAPI << " " << frame;
mL2[SAPI]->writeHighSide(frame);
@@ -180,6 +222,9 @@ public:
*/
void waitForPrimitive(GSM::Primitive primitive);
/** Block until a HANDOVER_ACCESS or ESTABLISH arrives. */
L3Frame* waitForEstablishOrHandover();
/**
Block on a channel until a given primitive arrives.
Any payload is discarded. Block indefinitely, no timeout.
@@ -197,18 +242,20 @@ public:
//@{
/** Write a received radio burst into the "low" side of the channel. */
virtual void writeLowSide(const RxBurst& burst) { assert(mL1); mL1->writeLowSide(burst); }
virtual void writeLowSide(const RxBurst& burst) { assert(mL1); mL1->writeLowSideRx(burst); }
/** Return true if the channel is safely abandoned (closed or orphaned). */
bool recyclable() const { assert(mL1); return mL1->recyclable(); }
virtual bool recyclable() const { assert(mL1); return mL1->recyclable(); }
/** Return true if the channel is active. */
bool active() const { assert(mL1); return mL1->active(); }
virtual bool active() const { assert(mL1); return mL1->active(); }
/** The TDMA parameters for the transmit side. */
// (pat) This lovely function is unused. Use L1Encoder::mapping()
const TDMAMapping& txMapping() const { assert(mL1); return mL1->txMapping(); }
/** The TDMAParameters for the receive side. */
// (pat) This lovely function is unused. Use L1Decoder::mapping()
const TDMAMapping& rcvMapping() const { assert(mL1); return mL1->rcvMapping(); }
/** GSM 04.08 10.5.2.5 type and offset code. */
@@ -229,10 +276,14 @@ public:
virtual float RSSI() const;
/** Uplink timing error. */
virtual float timingError() const;
/** System timestamp of RSSI and TA */
virtual double timestamp() const;
/** Actual MS uplink power. */
virtual int actualMSPower() const;
/** Actual MS uplink timing advance. */
virtual int actualMSTiming() const;
/** Control whether to accept a handover. */
void handoverPending(bool flag) { assert(mL1); mL1->handoverPending(flag); }
//@}
//@} // L1
@@ -277,6 +328,10 @@ public:
*/
virtual void connect();
public:
bool inUseByGPRS() { return mL1->inUseByGPRS(); }
bool decryptUplink_maybe(string wIMSI, int wA5Alg) { return mL1->decoder()->decrypt_maybe(wIMSI, wA5Alg); }
};
@@ -357,13 +412,15 @@ class SACCHLogicalChannel : public LogicalChannel {
/** MeasurementResults from the MS. They are caught in serviceLoop, accessed
for recording along with GPS and other data in MobilityManagement.cpp */
L3MeasurementResults mMeasurementResults;
const LogicalChannel *mHost;
public:
SACCHLogicalChannel(
unsigned wCN,
unsigned wTN,
const MappingPair& wMapping);
const MappingPair& wMapping,
const LogicalChannel* wHost);
ChannelType type() const { return SACCHType; }
@@ -375,10 +432,14 @@ class SACCHLogicalChannel : public LogicalChannel {
//@{
float RSSI() const { return mSACCHL1->RSSI(); }
float timingError() const { return mSACCHL1->timingError(); }
double timestamp() const { return mSACCHL1->timestamp(); }
int actualMSPower() const { return mSACCHL1->actualMSPower(); }
int actualMSTiming() const { return mSACCHL1->actualMSTiming(); }
void setPhy(float RSSI, float timingError) { mSACCHL1->setPhy(RSSI,timingError); }
void setPhy(float RSSI, float timingError, double wTimestamp)
{ mSACCHL1->setPhy(RSSI,timingError,wTimestamp); }
void setPhy(const SACCHLogicalChannel& other) { mSACCHL1->setPhy(*other.mSACCHL1); }
void RSSIBumpDown(int dB) { assert(mL1); mSACCHL1->RSSIBumpDown(dB); }
//@}
/**@name Channel and neighbour cells stats as reported from MS */
@@ -386,6 +447,12 @@ class SACCHLogicalChannel : public LogicalChannel {
const L3MeasurementResults& measurementResults() const { return mMeasurementResults; }
//@}
/** Get active state from the host DCCH. */
bool active() const { assert(mHost); return mHost->active(); }
/** Get recyclable state from the host DCCH. */
bool recyclable() const { assert(mHost); return mHost->recyclable(); }
protected:
/** Read and process a measurement report, called from the service loop. */
@@ -400,9 +467,6 @@ class SACCHLogicalChannel : public LogicalChannel {
void *SACCHLogicalChannelServiceLoopAdapter(SACCHLogicalChannel*);
/**
Common control channel.
The "uplink" component of the CCCH is the RACH.
@@ -410,10 +474,14 @@ void *SACCHLogicalChannelServiceLoopAdapter(SACCHLogicalChannel*);
bi-directional control channel. Common control channels are physically
sub-divided into the common control channel (CCCH), the packet common control
channel (PCCCH), and the Compact packet common control channel (CPCCCH)."
(pat) To implement DRX and paging I added the CCCHCombinedChannel to which CCCH messages
should now be sent, and this class is now just a private attachment point whose primary
purpose is to house the serviceloop for a single CCCH.
*/
class CCCHLogicalChannel : public NDCCHLogicalChannel {
protected:
friend class GSMConfig;
/*
Because the CCCH is written by multiple threads,
@@ -423,7 +491,14 @@ class CCCHLogicalChannel : public NDCCHLogicalChannel {
Thread mServiceThread; ///< a thread for the service loop
L3FrameFIFO mQ; ///< because the CCCH is written by multiple threads
#if ENABLE_PAGING_CHANNELS
L3FrameFIFO mPagingQ[sMax_BS_PA_MFRMS]; ///< A queue for each paging channel on this timeslot.
#endif
bool mRunning; ///< a flag to indication that the service loop is running
bool mWaitingToSend; // If this is set, there is another CCCH message
// waiting in the encoder serviceloop.
// This variable is not mutex locked and could
// be incorrect, but it is not critical.
public:
@@ -432,7 +507,11 @@ class CCCHLogicalChannel : public NDCCHLogicalChannel {
void open();
void send(const L3RRMessage& msg)
{ mQ.write(new L3Frame((const L3Message&)msg,UNIT_DATA)); }
{
// DEBUG:
//LOG(WARNING) << "CCCHLogicalChannel2::write q";
mQ.write(new L3Frame((const L3Message&)msg,UNIT_DATA));
}
void send(const L3Message&) { assert(0); }
@@ -442,6 +521,27 @@ class CCCHLogicalChannel : public NDCCHLogicalChannel {
/** Return the number of messages waiting for transmission. */
unsigned load() const { return mQ.size(); }
// (pat) GPRS needs to know exactly when the CCCH message will be sent downstream,
// because it needs to allocate an upstream radio block after that time,
// and preferably as quickly as possible after that time.
// For now, I'm going to punt on this and return the worst case.
// TODO: This is the wrong way to do this.
// First, this calculation should not be here; it will be hard for anyone maintaining
// the code and making changes that would affect this calculation to find it here.
// Second, it depends on what kind of C0T0 beacon we have.
// We should wait until it is time to send the message, then create it.
// To do this, either the CCCHLogicalChannel::serviceLoop should be rewritten,
// or we should hook XCCHL1Encoder::sendFrame(L2Frame) to modify the message
// if it is a packet message. Or more drastically, make the CCCHLogicalChannel::mQ
// queue hold internal messages not L3Frames, for example, for RACH a struct
// with the arrival time, RACH message, signal strength and timing advance,
// and delay generating the RRMessage until it is ready to send.
//
// But for now, just punt and send a frame time far enough in the future that it
// is guaranteed to work:
// Note: Time wraps at gHyperFrame.
Time getNextMsgSendTime();
ChannelType type() const { return CCCHType; }
friend void *CCCHLogicalChannelServiceLoopAdapter(CCCHLogicalChannel*);
@@ -492,6 +592,33 @@ class TCHFACCHLogicalChannel : public LogicalChannel {
/**
Cell broadcast control channel (CBCH).
See GSM 04.12 3.3.1.
*/
class CBCHLogicalChannel : public NDCCHLogicalChannel {
protected:
/*
The CBCH should be written be a single thread.
The input interface is *not* multi-thread safe.
*/
public:
CBCHLogicalChannel(const CompleteMapping& wMapping);
void send(const L3SMSCBMessage& msg);
void send(const L3Message&) { assert(0); }
ChannelType type() const { return CBCHType; }
};
/**@name Test channels, not actually used in GSM. */

View File

@@ -1,24 +1,14 @@
/*
* Copyright 2008, 2009 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/

View File

@@ -1,24 +1,14 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -42,6 +32,7 @@ class L2DL;
A "service access point" in GSM/ISDN is analogous to port number in IP.
GSM allows up to 4 SAPs, although only two are presently used.
See GSM 04.05 5.2 for an introduction.
(pat) SAPs exist at every level in the OSI model. This should probably be called L2SAPMux.
*/
class SAPMux {

115
GSM/GSMSMSCBL3Messages.cpp Normal file
View File

@@ -0,0 +1,115 @@
/*
* Copyright 2010 Kestrel Signal Processing, Inc.
*
* 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.
*/
#include "GSMSMSCBL3Messages.h"
#include <iomanip>
using namespace GSM;
using namespace std;
void L3SMSCBSerialNumber::writeV(L3Frame& l3, size_t& wp) const
{
l3.writeField(wp,mGS,2);
l3.writeField(wp,mMessageCode,10);
l3.writeField(wp,mUpdateNumber,4);
}
void L3SMSCBSerialNumber::text(ostream& os) const
{
os << "GS=" << mGS;
os << " MessageCode=" << mMessageCode;
os << " UpdateNumber=" << mUpdateNumber;
}
void L3SMSCBMessageIdentifier::writeV(L3Frame& l3, size_t& wp) const
{
l3.writeField(wp,mValue,16);
}
void L3SMSCBMessageIdentifier::text(ostream& os) const
{
os << hex << "0x" << mValue << dec;
}
void L3SMSCBDataCodingScheme::writeV(L3Frame& l3, size_t& wp) const
{
l3.writeField(wp,mValue,8);
}
void L3SMSCBDataCodingScheme::text(ostream& os) const
{
os << hex << "0x" << mValue << dec;
}
void L3SMSCBPageParameter::writeV(L3Frame& l3, size_t& wp) const
{
l3.writeField(wp,mNumber,4);
l3.writeField(wp,mTotal,4);
}
void L3SMSCBPageParameter::text(ostream& os) const
{
os << mNumber << "/" << mTotal;
}
void L3SMSCBContent::writeV(L3Frame& l3, size_t& wp) const
{
for (unsigned i=0; i<82; i++) l3.writeField(wp,mData[i],8);
}
void L3SMSCBContent::text(ostream& os) const
{
os << hex;
for (unsigned i=0; i<82; i++) os << setw(2) << (int)mData[i];
os << dec;
}
ostream& GSM::operator<<(ostream& os, const L3SMSCBMessage& msg)
{
msg.text(os);
return os;
}
void L3SMSCBMessage::write(L3Frame& frame) const
{
size_t wp=0;
mSerialNumber.writeV(frame,wp);
mMessageIdentifier.writeV(frame,wp);
mDataCodingScheme.writeV(frame,wp);
mPageParameter.writeV(frame,wp);
mContent.writeV(frame,wp);
}
void L3SMSCBMessage::text(ostream& os) const
{
os << "serialNumber=(" << mSerialNumber << ")";
os << " messageID=" << mMessageIdentifier;
os << " DCS=" << mDataCodingScheme;
os << " page=" << mPageParameter;
os << " content=(" << mContent << ")";
}
// vim: ts=4 sw=4

182
GSM/GSMSMSCBL3Messages.h Normal file
View File

@@ -0,0 +1,182 @@
/*
* Copyright 2010 Kestrel Signal Processing, Inc.
*
* 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.
*/
#ifndef GSML3SMSCBMESSAGES_H
#define GSML3SMSCBMESSAGES_H
#include "GSML3Message.h"
#include <iostream>
namespace GSM {
/* Elements of SMSCB messages, from GSM 03.41 9.3. */
/** GSM 03.41 9.3.2.1 */
class L3SMSCBSerialNumber : public L3ProtocolElement {
private:
unsigned mGS; ///< geographic scope
unsigned mMessageCode; ///< code classifying message content
unsigned mUpdateNumber; ///< so MS knows to reload this message
public:
L3SMSCBSerialNumber(unsigned wGS, unsigned wMessageCode, unsigned wUpdateNumber):
mGS(wGS),
mMessageCode(wMessageCode), mUpdateNumber(wUpdateNumber)
{ }
void parseV(const L3Frame&, size_t&, size_t) { assert(0); }
void parseV(const L3Frame&, size_t&) { assert(0); }
void writeV(L3Frame&, size_t&) const;
size_t lengthV() const { return 2; }
void text(std::ostream& os) const;
};
/** GSM 03.41 9.3.2.2 */
class L3SMSCBMessageIdentifier : public L3ProtocolElement {
private:
unsigned mValue;
public:
L3SMSCBMessageIdentifier(unsigned wValue):
mValue(wValue)
{ }
void parseV(const L3Frame&, size_t&, size_t) { assert(0); }
void parseV(const L3Frame&, size_t&) { assert(0); }
void writeV(L3Frame&, size_t&) const;
size_t lengthV() const { return 2; }
void text(std::ostream& os) const;
};
/** GSM 03.41 9.3.2.3 */
class L3SMSCBDataCodingScheme : public L3ProtocolElement {
private:
unsigned mValue;
public:
L3SMSCBDataCodingScheme(unsigned wValue):
mValue(wValue)
{ }
void parseV(const L3Frame&, size_t&, size_t) { assert(0); }
void parseV(const L3Frame&, size_t&) { assert(0); }
void writeV(L3Frame&, size_t&) const;
size_t lengthV() const { return 1; }
void text(std::ostream& os) const;
};
/** GSM 03.41 9.3.2.4 */
class L3SMSCBPageParameter : public L3ProtocolElement {
private:
unsigned mNumber;
unsigned mTotal;
public:
L3SMSCBPageParameter(unsigned wNumber, unsigned wTotal):
mNumber(wNumber),mTotal(wTotal)
{ }
void parseV(const L3Frame&, size_t&, size_t) { assert(0); }
void parseV(const L3Frame&, size_t&) { assert(0); }
void writeV(L3Frame&, size_t&) const;
size_t lengthV() const { return 1; }
void text(std::ostream& os) const;
};
/** GSM 03.41 9.3.2.5 */
class L3SMSCBContent : public L3ProtocolElement {
private:
char mData[82]; ///< raw data
public:
L3SMSCBContent(const char *wData)
{ bcopy(wData,mData,82); }
void parseV(const L3Frame&, size_t&, size_t) { assert(0); }
void parseV(const L3Frame&, size_t&) { assert(0); }
void writeV(L3Frame&, size_t&) const;
size_t lengthV() const { return 82; }
void text(std::ostream& os) const;
};
/**
L3 definition of the SMSCB message.
This message group does not follow the normal structure of
most Um L3 messages and is not an L3Message subclass.
See GSM 03.41 9.3.1.
*/
class L3SMSCBMessage {
private:
L3SMSCBSerialNumber mSerialNumber;
L3SMSCBMessageIdentifier mMessageIdentifier;
L3SMSCBDataCodingScheme mDataCodingScheme;
L3SMSCBPageParameter mPageParameter;
L3SMSCBContent mContent;
public:
L3SMSCBMessage(
L3SMSCBSerialNumber wSerialNumber,
L3SMSCBMessageIdentifier wMessageIdentifier,
L3SMSCBDataCodingScheme wDataCodingScheme,
L3SMSCBPageParameter wPageParameter,
L3SMSCBContent wContent
):
mSerialNumber(wSerialNumber),
mMessageIdentifier(wMessageIdentifier),
mDataCodingScheme(wDataCodingScheme),
mPageParameter(wPageParameter),
mContent(wContent)
{ }
void write(L3Frame&) const;
void text(std::ostream&) const;
};
std::ostream& operator<<(std::ostream&, const L3SMSCBMessage&);
}
#endif
// vim: ts=4 sw=4

View File

@@ -1,25 +1,15 @@
/*
* Copyright 2008, 2009 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING 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.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
*/
@@ -31,8 +21,10 @@
UDPSocket GSMTAPSocket;
void gWriteGSMTAP(unsigned ARFCN, unsigned TS, unsigned FN,
GSM::TypeAndOffset to, bool is_saach, bool ul_dln,
const BitVector& frame)
GSM::TypeAndOffset to, bool is_saach,
bool ul_dln, // (pat) This flag means uplink
const BitVector& frame,
unsigned wType) // Defaults to GSMTAP_TYPE_UM
{
char buffer[MAX_UDP_LENGTH];
int ofs = 0;
@@ -93,9 +85,24 @@ void gWriteGSMTAP(unsigned ARFCN, unsigned TS, unsigned FN,
scn = to - GSM::TCHH_0;
break;
case GSM::TDMA_PDCH: // packet data traffic logical channel, full speed.
stype = GSMTAP_CHANNEL_PACCH;
//stype = GSMTAP_CHANNEL_PDCH;
scn = 0; // Is this correct?
break;
case GSM::TDMA_PTCCH: // packet data timing advance logical channel
stype = GSMTAP_CHANNEL_PTCCH;
scn = 0;
break;
case GSM::TDMA_PACCH:
stype = GSMTAP_CHANNEL_PACCH;
scn = 0;
break;
default:
LOG(NOTICE) << "GSMTAP unsupported type-and-offset " << to;
stype = GSMTAP_CHANNEL_UNKNOWN;
scn = 0;
break;
}
if (is_saach)
@@ -112,7 +119,7 @@ void gWriteGSMTAP(unsigned ARFCN, unsigned TS, unsigned FN,
struct gsmtap_hdr *header = (struct gsmtap_hdr *)buffer;
header->version = GSMTAP_VERSION;
header->hdr_len = sizeof(struct gsmtap_hdr) >> 2;
header->type = GSMTAP_TYPE_UM;
header->type = wType; //GSMTAP_TYPE_UM;
header->timeslot = TS;
header->arfcn = htons(ARFCN);
header->signal_dbm = 0; /* FIXME */

View File

@@ -1,22 +1,15 @@
/*
* Copyright 2008, 2009 Free Software Foundation, Inc.
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
*
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.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -31,9 +24,8 @@
void gWriteGSMTAP(unsigned ARFCN, unsigned TS, unsigned FN,
GSM::TypeAndOffset to, bool is_sacch, bool ul_dln,
const BitVector& frame);
const BitVector& frame,
unsigned wType = GSMTAP_TYPE_UM);
#endif
// vim: ts=4 sw=4

View File

@@ -1,24 +1,14 @@
/*
* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -242,6 +232,23 @@ MAKE_TDMA_MAPPING(SACCH_C8_7U,SDCCH_8_7,false,true,0xFF,true,102);
// (pat) The basic 26-multi-frame has SACCH in timeslot #12 and an idle frame in timeslot #35.
// The entries below all follow this format, but a single SACCH message,
// comprised of 4 frames, starts at a different spot for each TCH,
// which is another way of saying that the TCH itself starts in a different place,
// and the odd numbered ones start with a 13 frame (half a multiframe) offset.
// The important point for GPRS is that these are the exact same frames needed
// for the continuous timing advance. If I want to use these, however, it means
// that the absolute frame number at which the GPRS 52-multiframe begins for each
// channel must be syncrhonized with these tables for each channel.
// More specifically, there are really only two cases, since we wont be using
// the SACCH frame-to-message assembling machinery. These cases are whether
// the SACCH frames start at a multiple of frame 0, or of frame 13.
// In other words, assuming all 104-multiframe below begin at time 0, the even numbered
// table entries return SACCH from frame #12 of each 26-multi-frame,
// and the odd ones return SACCH from frame #25, which would normally be the idle frame,
// if the 26-multi-frame were aligned at 0.
// This odd fact is going to get hard-coded into GPRS.
const unsigned SACCH_TF_T0Frames[] = {12,38,64,90};
MAKE_TDMA_MAPPING(SACCH_TF_T0,TCHF_0,true,true,0x01,true,104);

View File

@@ -2,24 +2,14 @@
/*
* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/

View File

@@ -1,24 +1,14 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -29,6 +19,7 @@
#include "GSMTransfer.h"
#include "GSML3Message.h"
#include "Globals.h"
using namespace std;
@@ -217,6 +208,43 @@ void L2Frame::idleFill()
}
}
void L2Frame::randomizeFiller(unsigned start)
{
/* for debugging
// no filler or first filler is 0x2b
if (start-8 < size() && peekField(start-8,8) != 0x2b) {
LOG(ALERT) << *this << " " << start;
assert(0);
}
// reset of filler is 0x2b
for (unsigned i = start; i < size(); i+=8) {
if (peekField(i,8) != 0x2b) {
LOG(ALERT) << *this << " " << start << " " << i;
assert(0);
}
}
*/
for (unsigned i = start; i < size(); i++) {
settfb(i, random() & 1);
}
}
void L2Frame::randomizeFiller(const L2Header& header)
{
switch (header.format()) {
case L2Header::FmtA:
case L2Header::FmtB:
randomizeFiller((header.length().L() + 4) * 8);
return;
case L2Header::FmtBbis:
case L2Header::FmtB4:
randomizeFiller((header.length().L() + 2) * 8);
return;
default:
return;
}
}
L2Frame::L2Frame(const BitVector& bits, Primitive prim)
:BitVector(23*8),mPrimitive(prim)
@@ -227,13 +255,18 @@ L2Frame::L2Frame(const BitVector& bits, Primitive prim)
}
L2Frame::L2Frame(const L2Header& header, const BitVector& l3)
#include <stdio.h>
L2Frame::L2Frame(const L2Header& header, const BitVector& l3, bool noran)
:BitVector(23*8),mPrimitive(DATA)
{
idleFill();
//printf("header.bitsNeeded=%d l3.size=%d this.size=%d\n",
//header.bitsNeeded(),l3.size(),this->size());
assert((header.bitsNeeded()+l3.size())<=this->size());
size_t wp = header.write(*this);
l3.copyToSegment(*this,wp);
// FIXME - figure out why randomizeFiller doesn't like the "noran" headers
if (gConfig.getBool("GSM.Cipher.ScrambleFiller") && !noran) randomizeFiller(header);
}
@@ -242,6 +275,7 @@ L2Frame::L2Frame(const L2Header& header)
{
idleFill();
header.write(*this);
if (gConfig.getBool("GSM.Cipher.ScrambleFiller")) randomizeFiller(header);
}
@@ -306,6 +340,23 @@ L2Control::FrameType L2Frame::SFrameType() const
const L2Frame& GSM::L2IdleFrame()
{
static volatile bool init = false;
static L2Frame idleFrame;
if (!init) {
init = true;
// GSM 04.06 5.4.2.3.
// As sent by the network.
idleFrame.fillField(8*0,3,8); // address
idleFrame.fillField(8*1,3,8); // control
idleFrame.fillField(8*2,1,8); // length
if (gConfig.getBool("GSM.Cipher.ScrambleFiller")) idleFrame.randomizeFiller(8*4);
}
return idleFrame;
}
@@ -442,6 +493,7 @@ ostream& GSM::operator<<(ostream& os, Primitive prim)
case UNIT_DATA: os << "UNIT_DATA"; break;
case ERROR: os << "ERROR"; break;
case HARDRELEASE: os << "HARDRELEASE"; break;
case HANDOVER_ACCESS: os << "HANDOVER_ACCESS"; break;
default: os << "?" << (int)prim << "?";
}
return os;

View File

@@ -1,24 +1,14 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
@@ -27,6 +17,7 @@
#ifndef GSMTRANSFER_H
#define GSMTRANSFER_H
#include "Defines.h"
#include "Interthread.h"
#include "BitVector.h"
#include "GSMCommon.h"
@@ -68,7 +59,8 @@ enum Primitive {
DATA, ///< multiframe data transfer
UNIT_DATA, ///< datagram-type data transfer
ERROR, ///< channel error
HARDRELEASE ///< forced release after an assignment
HARDRELEASE, ///< forced release after an assignment
HANDOVER_ACCESS ///< received inbound handover access burst
};
@@ -106,6 +98,7 @@ class TxBurst : public BitVector {
/**@name Basic accessors. */
//@{
// Since mTime is volatile, we can't return a reference.
Time time() const { return mTime; }
void time(const Time& wTime) { mTime = wTime; }
//@}
@@ -169,6 +162,7 @@ class RxBurst : public SoftVector {
{ }
// Since mTime is volatile, we can't return a reference.
Time time() const { return mTime; }
void time(const Time& wTime) { mTime = wTime; }
@@ -286,7 +280,7 @@ class L2Control {
/** Initialize a U or S frame. */
L2Control(ControlFormat wFormat=UFormat, unsigned wPF=0, unsigned bits=0)
:mFormat(wFormat),mPF(wPF),mSBits(bits),mUBits(bits)
:mFormat(wFormat),mNR(0),mNS(0),mPF(wPF),mSBits(bits),mUBits(bits)
{
assert(mFormat!=IFormat);
assert(mPF<2);
@@ -472,6 +466,9 @@ class L2Frame : public BitVector {
public:
void randomizeFiller(unsigned start);
void randomizeFiller(const L2Header& header);
/** Fill the frame with the GSM idle pattern, GSM 04.06 2.2. */
void idleFill();
@@ -498,7 +495,7 @@ class L2Frame : public BitVector {
The L3Frame must fit in the L2Frame.
The primitive is DATA.
*/
L2Frame(const L2Header&, const BitVector&);
L2Frame(const L2Header&, const BitVector&, bool noran=false);
/**
Make an L2Frame from a header with no payload.
@@ -534,7 +531,10 @@ class L2Frame : public BitVector {
/** Set/clear the PF bit. */
void PF(bool wPF) { mStart[8+3]=wPF; }
/** Look into the header and get the length of the payload. */
/**
Look into the header and get the length of the payload.
Assumes A or B header, or B4 header with L2 pseudo length in L3.
*/
unsigned L() const { return peekField(8*2,6); }
/** Get the "more data" bit (M). */
@@ -551,6 +551,9 @@ class L2Frame : public BitVector {
/** Return the CR bit, GSM 04.06 3.3.2. Assumes A or B header. */
bool CR() const { return mStart[6] & 0x01; }
/** Set/clear the CR bit. */
void CR(bool wCR) { mStart[6]=wCR; }
/** Return truw if this a DCCH idle frame. */
bool DCCHIdle() const
@@ -567,13 +570,16 @@ class L2Frame : public BitVector {
};
/** Return a reference to the standard LAPDm downlink idle frame. */
const L2Frame& L2IdleFrame();
std::ostream& operator<<(std::ostream& os, const L2Frame& msg);
typedef InterthreadQueueWithWait<L2Frame> L2FrameFIFO;
/**
Representation of a GSM L3 message in a bit vector.
Bit ordering is MSB-first in each octet.
@@ -602,7 +608,7 @@ class L3Frame : public BitVector {
L3Frame(const L3Frame& f1, const L3Frame& f2)
:BitVector(f1,f2),mPrimitive(DATA),
mL2Length(f1.mL2Length + f2.mL2Length)
{}
{ }
/** Build from an L2Frame. */
L3Frame(const L2Frame& source)
@@ -625,7 +631,7 @@ class L3Frame : public BitVector {
/** Message Type Indicator, GSM 04.08 10.4. */
unsigned MTI() const { return peekField(8,8); }
/** TI value, GSM 04.07 11.2.3.1.3. */
/** TI (transaction Identifier) value, GSM 04.07 11.2.3.1.3. */
unsigned TI() const { return peekField(0,4); }
/** Return the associated primitive. */
@@ -646,13 +652,18 @@ class L3Frame : public BitVector {
std::ostream& operator<<(std::ostream& os, const L3Frame&);
typedef InterthreadQueue<L3Frame> L3FrameFIFO;
/** A vocoder frame for use in GSM/SIP contexts. */
/**
A vocoder frame for use in GSM/SIP contexts.
This is based on RFC-3551 Section 4.5.8.1.
Note the 4-bit pad at the start of the frame, filled with b1101 (0xd).
*/
class VocoderFrame : public BitVector {
public:
@@ -666,7 +677,10 @@ class VocoderFrame : public BitVector {
:BitVector(264)
{ unpack(src); }
/** Non-const form returns an alias. */
BitVector payload() { return tail(4); }
/** Const form returns a copy. */
const BitVector payload() const { return tail(4); }
};

View File

@@ -20,8 +20,8 @@
include $(top_srcdir)/Makefile.common
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(USB_INCLUDES) $(WITH_INCLUDES) $(OPENBTS_CPPFLAGS)
AM_CXXFLAGS = -Wall -pthread -ldl $(OPENBTS_CXXFLAGS)
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
#AM_CXXFLAGS = -O2 -g
noinst_LTLIBRARIES = libGSM.la
@@ -34,6 +34,7 @@ libGSM_la_SOURCES = \
GSML3CCElements.cpp \
GSML3CCMessages.cpp \
GSML3CommonElements.cpp \
GSML3GPRSElements.cpp \
GSML3Message.cpp \
GSML3MMElements.cpp \
GSML3MMMessages.cpp \
@@ -44,6 +45,7 @@ libGSM_la_SOURCES = \
GSMTDMA.cpp \
GSMTransfer.cpp \
GSMTAPDump.cpp \
GSMSMSCBL3Messages.cpp \
PowerManager.cpp\
PhysicalStatus.cpp
@@ -56,6 +58,7 @@ noinst_HEADERS = \
GSML3CCElements.h \
GSML3CCMessages.h \
GSML3CommonElements.h \
GSML3GPRSElements.h \
GSML3Message.h \
GSML3MMElements.h \
GSML3MMMessages.h \
@@ -67,6 +70,7 @@ noinst_HEADERS = \
GSMTransfer.h \
PowerManager.h \
GSMTAPDump.h \
GSMSMSCBL3Messages.h \
gsmtap.h \
PhysicalStatus.h

View File

@@ -1,31 +1,28 @@
/**@file Declarations for PhysicalStatus and related classes. */
/*
* Copyright 2010, 2011 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
* Copyright 2011 Range Networks, Inc.
* Copyright 2011, 2012 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/
/*
* Copyright 2010 Kestrel Signal Processing, Inc.
* All rights reserved.
*
*/
#include "PhysicalStatus.h"
#include <Logger.h>
@@ -33,6 +30,7 @@
#include <sqlite3.h>
#include <sqlite3util.h>
#include <NeighborTable.h>
#include <GSML3RRElements.h>
#include <GSMLogicalChannel.h>
@@ -58,7 +56,9 @@ static const char* createPhysicalStatus = {
"TIME_ERR FLOAT DEFAULT NULL, " // timing advance error in symbol periods
"TRANS_PWR INTEGER DEFAULT NULL, " // handset tx power in dBm
"TIME_ADVC INTEGER DEFAULT NULL, " // handset timing advance in symbol periods
"FER FLOAT DEFAULT NULL " // uplink FER
"FER FLOAT DEFAULT NULL, " // uplink FER
"NCELL_ARFCN INTEGER DEFAULT NULL, " // ARFCN of strongest neighbor
"NCELL_RSSI INTEGER DEFAULT NULL " // RSSI of strongest neighbor
")"
};
@@ -75,6 +75,10 @@ int PhysicalStatus::open(const char* wPath)
LOG(EMERG) << "Cannot create TMSI table";
return 1;
}
// Set high-concurrency WAL mode.
if (!sqlite3_command(mDB,enableWAL)) {
LOG(EMERG) << "Cannot enable WAL mode on database at " << wPath << ", error message: " << sqlite3_errmsg(mDB);
}
return 0;
}
@@ -115,35 +119,86 @@ bool PhysicalStatus::setPhysical(const LogicalChannel* chan,
assert(mDB);
assert(chan);
// If MEAS_VALID is true, we don't have valid measurements.
// Really. See GSM 04.08 10.5.2.20.
if (measResults.MEAS_VALID()) return true;
ScopedLock lock(mLock);
createEntry(chan);
int CN = -1;
if (measResults.NO_NCELL()>0) CN = measResults.BCCH_FREQ_NCELL(0);
int ARFCN = -1;
if (CN>=0) {
std::vector<unsigned> ARFCNList = gNeighborTable.ARFCNList();
size_t sz = ARFCNList.size();
if (sz!=0) {
if (CN<sz) ARFCN=ARFCNList[CN];
else { LOG(NOTICE) << "BCCH index " << CN << " does not match ARFCN list of size " << sz; }
} else {
LOG(DEBUG) << "empty measurement list";
}
}
char query[500];
sprintf(query,
"UPDATE PHYSTATUS SET "
"RXLEV_FULL_SERVING_CELL=%d, "
"RXLEV_SUB_SERVING_CELL=%d, "
"RXQUAL_FULL_SERVING_CELL_BER=%f, "
"RXQUAL_SUB_SERVING_CELL_BER=%f, "
"RSSI=%f, "
"TIME_ERR=%f, "
"TRANS_PWR=%u, "
"TIME_ADVC=%u, "
"FER=%f, "
"ACCESSED=%u, "
"ARFCN=%u "
"WHERE CN_TN_TYPE_AND_OFFSET==\"%s\"",
measResults.RXLEV_FULL_SERVING_CELL_dBm(),
measResults.RXLEV_SUB_SERVING_CELL_dBm(),
measResults.RXQUAL_FULL_SERVING_CELL_BER(),
measResults.RXQUAL_SUB_SERVING_CELL_BER(),
chan->RSSI(), chan->timingError(),
chan->actualMSPower(), chan->actualMSTiming(),
chan->FER(),
(unsigned)time(NULL),
chan->ARFCN(),
chan->descriptiveString());
if (ARFCN<0) {
sprintf(query,
"UPDATE PHYSTATUS SET "
"RXLEV_FULL_SERVING_CELL=%d, "
"RXLEV_SUB_SERVING_CELL=%d, "
"RXQUAL_FULL_SERVING_CELL_BER=%f, "
"RXQUAL_SUB_SERVING_CELL_BER=%f, "
"RSSI=%f, "
"TIME_ERR=%f, "
"TRANS_PWR=%u, "
"TIME_ADVC=%u, "
"FER=%f, "
"ACCESSED=%u, "
"ARFCN=%u "
"WHERE CN_TN_TYPE_AND_OFFSET==\"%s\"",
measResults.RXLEV_FULL_SERVING_CELL_dBm(),
measResults.RXLEV_SUB_SERVING_CELL_dBm(),
measResults.RXQUAL_FULL_SERVING_CELL_BER(),
measResults.RXQUAL_SUB_SERVING_CELL_BER(),
chan->RSSI(), chan->timingError(),
chan->actualMSPower(), chan->actualMSTiming(),
chan->FER(),
(unsigned)time(NULL),
chan->ARFCN(),
chan->descriptiveString());
} else {
sprintf(query,
"UPDATE PHYSTATUS SET "
"RXLEV_FULL_SERVING_CELL=%d, "
"RXLEV_SUB_SERVING_CELL=%d, "
"RXQUAL_FULL_SERVING_CELL_BER=%f, "
"RXQUAL_SUB_SERVING_CELL_BER=%f, "
"RSSI=%f, "
"TIME_ERR=%f, "
"TRANS_PWR=%u, "
"TIME_ADVC=%u, "
"FER=%f, "
"ACCESSED=%u, "
"ARFCN=%u ,"
"NCELL_ARFCN=%u, "
"NCELL_RSSI=%d "
"WHERE CN_TN_TYPE_AND_OFFSET==\"%s\"",
measResults.RXLEV_FULL_SERVING_CELL_dBm(),
measResults.RXLEV_SUB_SERVING_CELL_dBm(),
measResults.RXQUAL_FULL_SERVING_CELL_BER(),
measResults.RXQUAL_SUB_SERVING_CELL_BER(),
chan->RSSI(), chan->timingError(),
chan->actualMSPower(), chan->actualMSTiming(),
chan->FER(),
(unsigned)time(NULL),
chan->ARFCN(),
(unsigned)ARFCN,
measResults.RXLEV_NCELL_dBm(0),
chan->descriptiveString()
);
}
LOG(DEBUG) << "Query: " << query;

View File

@@ -3,24 +3,16 @@
* Copyright 2010 Kestrel Signal Processing, Inc.
* Copyright 2011 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/

View File

@@ -1,24 +1,14 @@
/*
* Copyright 2009 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/

View File

@@ -1,24 +1,14 @@
/*
* Copyright 2009 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
* 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 free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
*/

View File

@@ -79,9 +79,9 @@
#define GSMTAP_CHANNEL_TCH_H 0x0a
#define GSMTAP_CHANNEL_CBCH51 0x0b
#define GSMTAP_CHANNEL_CBCH52 0x0c
#define GSMTAP_CHANNEL_PDCH 0x0d
#define GSMTAP_CHANNEL_PTCCH 0x0e
#define GSMTAP_CHANNEL_PACCH 0x0f
#define GSMTAP_CHANNEL_PDCH 0x0d // pats note: This one is not implemented in wireshark.
#define GSMTAP_CHANNEL_PTCCH 0x0e // pats note: and neither is this one.
#define GSMTAP_CHANNEL_PACCH 0x0f // pats note: This is the one that is implemented.
#define GSMTAP_CHANNEL_ACCH 0x80
/* ====== DO NOT MAKE UNAPPROVED MODIFICATIONS HERE ===== */