mirror of
https://github.com/RangeNetworks/openbts.git
synced 2025-10-23 07:42:01 +00:00
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:
22
GSM/AppInfTest.cpp
Normal file
22
GSM/AppInfTest.cpp
Normal 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;
|
||||
}
|
||||
|
@@ -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.
|
||||
|
||||
*/
|
||||
|
||||
|
@@ -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.
|
||||
|
||||
*/
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@@ -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
|
||||
|
109
GSM/GSMConfig.h
109
GSM/GSMConfig.h
@@ -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. */
|
||||
|
747
GSM/GSML1FEC.cpp
747
GSM/GSML1FEC.cpp
File diff suppressed because it is too large
Load Diff
465
GSM/GSML1FEC.h
465
GSM/GSML1FEC.h
@@ -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); }
|
||||
//@}
|
||||
};
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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); }
|
||||
|
||||
|
@@ -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){
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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();
|
||||
|
@@ -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 {
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -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
375
GSM/GSML3GPRSElements.cpp
Normal 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
180
GSM/GSML3GPRSElements.h
Normal 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
|
@@ -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;
|
||||
|
@@ -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'; }
|
||||
|
||||
|
@@ -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 << ")";
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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. */
|
||||
|
@@ -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.
|
||||
|
||||
*/
|
||||
|
||||
|
@@ -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
115
GSM/GSMSMSCBL3Messages.cpp
Normal 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
182
GSM/GSMSMSCBL3Messages.h
Normal 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
|
@@ -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 */
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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.
|
||||
|
||||
*/
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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); }
|
||||
|
||||
};
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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.
|
||||
|
||||
*/
|
||||
|
||||
|
@@ -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.
|
||||
|
||||
*/
|
||||
|
||||
|
@@ -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.
|
||||
|
||||
*/
|
||||
|
||||
|
@@ -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 ===== */
|
||||
|
Reference in New Issue
Block a user