Files
openbts/GSM/GSML3RRElements.h
2014-03-25 00:06:30 +01:00

1214 lines
33 KiB
C++

/**@file @brief Elements for Radio Resource messsages, GSM 04.08 10.5.2. */
/*
* Copyright 2008, 2009 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
* Copyright 2011, 2012, 2014 Range Networks, 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 GSML3RRELEMENTS_H
#define GSML3RRELEMENTS_H
#include <vector>
#include "GSML3Message.h"
#include "GSML3GPRSElements.h"
#include <Globals.h>
namespace GSM {
/** Cell Options (BCCH), GSM 04.08 10.5.2.3 */
class L3CellOptionsBCCH : public L3ProtocolElement {
private:
unsigned mPWRC; ///< 1 -> downlink power control may be used
unsigned mDTX; ///< discontinuous transmission state
unsigned mRADIO_LINK_TIMEOUT; ///< timeout to declare dead phy link
public:
/** Sets defaults for no use of DTX or downlink power control. */
L3CellOptionsBCCH()
:L3ProtocolElement()
{
// Values dictated by the current implementation are hard-coded.
mPWRC=0;
mDTX=2;
// Configuarable values.
mRADIO_LINK_TIMEOUT= gConfig.getNum("GSM.CellOptions.RADIO-LINK-TIMEOUT");
}
size_t lengthV() const { return 1; }
void writeV(L3Frame& dest, size_t &wp) const;
void parseV(const L3Frame&, size_t&) { assert(0); }
void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
void text(std::ostream&) const;
};
/** Cell Options (SACCH), GSM 04.08 10.5.2.3a */
class L3CellOptionsSACCH : public L3ProtocolElement {
private:
unsigned mPWRC; ///< 1 -> downlink power control may be used
unsigned mDTX; ///< discontinuous transmission state
unsigned mRADIO_LINK_TIMEOUT; ///< timeout to declare dead phy link
public:
/** Sets defaults for no use of DTX or downlink power control. */
L3CellOptionsSACCH()
:L3ProtocolElement()
{
// Values dictated by the current implementation are hard-coded.
mPWRC=0;
mDTX=2;
// Configuarable values.
mRADIO_LINK_TIMEOUT=gConfig.getNum("GSM.CellOptions.RADIO-LINK-TIMEOUT");
}
size_t lengthV() const { return 1; }
void writeV(L3Frame& dest, size_t &wp) const;
void parseV(const L3Frame&, size_t&) { assert(0); }
void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
void text(std::ostream&) const;
};
/** Cell Selection Parameters, GSM 04.08 10.5.2.4 */
class L3CellSelectionParameters : public L3ProtocolElement {
private:
unsigned mACS;
unsigned mNECI;
unsigned mCELL_RESELECT_HYSTERESIS;
unsigned mMS_TXPWR_MAX_CCH;
unsigned mRXLEV_ACCESS_MIN;
public:
/** Sets defaults to reduce gratuitous handovers. */
L3CellSelectionParameters()
:L3ProtocolElement()
{
// Values dictated by the current implementation are hard-coded.
mACS=0; // We don't support SI16 & SI17 yet.
// Configurable values.
mNECI=gConfig.getNum("GSM.CellSelection.NECI");
mMS_TXPWR_MAX_CCH=gConfig.getNum("GSM.CellSelection.MS-TXPWR-MAX-CCH");
mRXLEV_ACCESS_MIN=gConfig.getNum("GSM.CellSelection.RXLEV-ACCESS-MIN");
mCELL_RESELECT_HYSTERESIS=gConfig.getNum("GSM.CellSelection.CELL-RESELECT-HYSTERESIS");
}
size_t lengthV() const { return 2; }
void writeV(L3Frame& dest, size_t &wp) const;
void parseV(const L3Frame&, size_t&) { assert(0); }
void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
void text(std::ostream&) const;
};
/** Control Channel Description, GSM 04.08 10.5.2.11 */
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:
/** Sets reasonable defaults for a single-ARFCN system. */
L3ControlChannelDescription():L3ProtocolElement()
{
// Values dictated by the current implementation are hard-coded.
mBS_AG_BLKS_RES=2; // reserve 2 CCCHs for access grant
mBS_PA_MFRMS=0; // minimum PCH spacing
// Configurable values.
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); }
void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
void text(std::ostream&) const;
};
/**
A generic frequency list element base class, GSM 04.08 10.5.2.13.
This implementation supports only the "variable bit map" format
(GSM 04.08 10.5.2.13.7).
*/
class L3FrequencyList : public L3ProtocolElement {
protected:
std::vector<unsigned> mARFCNs; ///< ARFCN list to encode/decode
public:
/** Default constructor creates an empty list. */
L3FrequencyList():L3ProtocolElement() {}
L3FrequencyList(const std::vector<unsigned>& wARFCNs)
:L3ProtocolElement(),
mARFCNs(wARFCNs)
{}
//void push_back(unsigned ARFCN) { mARFCNs.push_back(ARFCN); }
void ARFCNs(const std::vector<unsigned>& wARFCNs) { mARFCNs=wARFCNs; }
const std::vector<unsigned>& ARFCNs() const { return mARFCNs; }
size_t lengthV() const { return 16; }
void writeV(L3Frame& dest, size_t &wp) const;
void parseV(const L3Frame&, size_t&) { assert(0); }
void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
void text(std::ostream&) const;
private:
/**@name ARFCN set browsing. */
//@{
/** Return minimum-numbered ARFCN. */
unsigned base() const;
/** Return numeric spread of ARFNs. */
unsigned spread() const;
/** Return true if a given ARFCN is in the list. */
bool contains(unsigned wARFCN) const;
//@}
};
/**
Cell Channel Description, GSM 04.08 10.5.2.1b.
This element is used to provide the Cell Allocation
for frequency hopping configurations.
It lists the ARFCNs available for hopping and
normally lists all of the ARFCNs for the system.
It is mandatory, even if you don't use hopping.
*/
class L3CellChannelDescription : public L3FrequencyList {
public:
L3CellChannelDescription()
:L3FrequencyList()
{}
void writeV(L3Frame& dest, size_t &wp) const;
};
/**
Neighbor Cells Description, GSM 04.08 or 44.018 10.5.2.22 and 10.5.2.1b
Note that in the spec the NeighborCellDescription is just a variation of the CellChannelDescription IE,
which is where the main documentation resides.
(A kind of frequency list.)
This element describes neighboring cells that may be
candidates for handovers.
*/
class L3NeighborCellsDescription : public L3FrequencyList {
public:
L3NeighborCellsDescription() {}
//L3NeighborCellsDescription()
// :L3FrequencyList(gConfig.getVector("GSM.CellSelection.Neighbors"))
//{}
L3NeighborCellsDescription(const std::vector<unsigned>& neighbors)
:L3FrequencyList(neighbors)
{}
void writeV(L3Frame& dest, size_t &wp) const;
void parseV(const L3Frame&, size_t&) { assert(0); }
void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
void text(std::ostream&) const;
};
/** NCC Permitted, GSM 04.08 10.5.2.27 */
class L3NCCPermitted : public L3ProtocolElement {
private:
unsigned mPermitted; ///< NCC allowance mask (NCCs 0-7)
public:
/** Get default parameters from gConfig. */
L3NCCPermitted()
:L3ProtocolElement()
{
mPermitted = gConfig.getNum("GSM.CellSelection.NCCsPermitted");
mPermitted |= 1 << gConfig.getNum("GSM.Identity.BSIC.NCC");
}
size_t lengthV() const { return 1; }
void writeV(L3Frame& dest, size_t &wp) const;
void parseV(const L3Frame&, size_t&) { assert(0); }
void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
void text(std::ostream&) const;
};
// T3126 is how long the MS listens to CCCH after a RACH, and is dependent on parameters broadcast in L3RACHControlParameters.
// 4.08/24.008 says value is T+2S but no longer than 5secs, where T and S are defined in 44.018 3.3.1.2:
// T is the "Tx Integer" broadcast on BCCH (we default to 14), S is defined by table 3.3.1.1.2.1:
// TX-integer non-combined-CCCH combined-CCH/SDCCH
// 3,8,14,50 55 41
// 4,9,16 76 52
// 5,10,20 109 58
// 6,11,25 163 86
// 7,12,32 217 115
// See further documentation at the config value GSM.CCCH.AGCH.QMax.
/** RACH Control Parameters GSM 04.08 10.5.2.29 */
class L3RACHControlParameters : public L3ProtocolElement {
private:
unsigned mMaxRetrans; ///< code for 1-7 RACH retransmission attempts
// 44.018 Table 10.5.2.29.1: coding of MaxRetransmissions:
// 0 => Maximum 1 retransmission.
// 1 => Maximum 2 retransmission.
// 2 => Maximum 4 retransmission.
// 3 => Maximum 7 retransmission.
unsigned mTxInteger; ///< code for 3-50 slots to spread transmission
unsigned mCellBarAccess; ///< if true, phones cannot camp
unsigned mRE; ///< if true, call reestablishment is not allowed
uint16_t mAC; ///< mask of barring flags for the 16 access classes
public:
/** Default constructor parameters allows all access. */
L3RACHControlParameters()
:L3ProtocolElement()
{
// Values ditected by imnplementation are hard-coded.
mRE=1;
mCellBarAccess=0;
// Configurable values.
mMaxRetrans = gConfig.getNum("GSM.RACH.MaxRetrans");
mTxInteger = gConfig.getNum("GSM.RACH.TxInteger");
mAC = gConfig.getNum("GSM.RACH.AC");
}
size_t lengthV() const { return 3; }
void writeV(L3Frame& dest, size_t &wp) const;
void parseV(const L3Frame&, size_t&) { assert(0); }
void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
void text(std::ostream&) const;
};
/** PageMode, GSM 04.08 10.5.2.26 */
class L3PageMode : public L3ProtocolElement
{
unsigned mPageMode;
public:
/** Default mode is "normal paging". */
L3PageMode(unsigned wPageMode=0)
:L3ProtocolElement(),
mPageMode(wPageMode)
{}
size_t lengthV() const { return 1; }
void writeV( L3Frame& dest, size_t &wp ) const;
void parseV( const L3Frame &src, size_t &rp );
void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
void text(std::ostream&) const;
};
/** 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).
public:
L3DedicatedModeOrTBF(bool forTBF, bool wDownlink)
:L3ProtocolElement(),
mDownlink(wDownlink), mTMA(0), mDMOrTBF(forTBF)
{}
size_t lengthV() const { return 1; }
void writeV(L3Frame &dest, size_t &wp ) const;
void parseV( const L3Frame&, size_t&) { assert(0); }
void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
void text(std::ostream&) const;
};
/** 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 {
// Channel Description Format.
// 7 6 5 4 3 2 1 0
// [ ChannelTypeTDMAOffset[4:0] ][ TN[2:0] ] Octect 1
// [ TSC ][ H=0 ][ SPARE(0,0)][ ARFCN[9:8] ] Octect 2
// [ [ H=1 ][ MAIO[5:2] ] Octect 2
// [ ARFCN[7:0] ] Octect 3 H=0
// [ MAIO[1:0] ][ HSN[5:0] ] Octect 3 H=1
//
// Octet 2.
TypeAndOffset mTypeAndOffset; // 5 bit
unsigned mTN; //3 bit Timeslot Number
// Octet 3 & 4.
unsigned mTSC; // 3 bit Training Sequence Number.
unsigned mHFlag; // 1 bit If true, it is a hopping channel.
unsigned mARFCN; // 10 bit overflows
unsigned mMAIO; // 6 bit overflows Mobile Allocation Index Offset (for hopping channels)
unsigned mHSN; // 6 bit Hopping Sequence Number (for hopping channels)
public:
/** Non-hopping initializer. */
L3ChannelDescription(TypeAndOffset wTypeAndOffset, unsigned wTN,
unsigned wTSC, unsigned wARFCN)
:L3ProtocolElement(),
mTypeAndOffset(wTypeAndOffset),mTN(wTN),
mTSC(wTSC),
mHFlag(0),
mARFCN(wARFCN),
mMAIO(0),mHSN(0)
{ }
/** Blank initializer */
L3ChannelDescription()
:mTypeAndOffset(TDMA_MISC),
mTN(0),mTSC(0),mHFlag(0),mARFCN(0),mMAIO(0),mHSN(0)
{ }
size_t lengthV() const { return 3; }
void writeV( L3Frame &dest, size_t &wp ) const;
void parseV(const L3Frame& src, size_t &rp);
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 44.018 10.5.2.5a */
class L3ChannelDescription2 : public L3ChannelDescription {
public:
L3ChannelDescription2(TypeAndOffset wTypeAndOffset, unsigned wTN,
unsigned wTSC, unsigned wARFCN)
:L3ChannelDescription(wTypeAndOffset,wTN,wTSC,wARFCN)
{ }
L3ChannelDescription2(const L3ChannelDescription &other) : L3ChannelDescription(other) {}
L3ChannelDescription2() { }
};
/** RequestReference, GSM 04.08 10.5.2.30 */
class L3RequestReference : public L3ProtocolElement
{
// 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
unsigned mRA; ///< random tag from original RACH burst
/**@name Timestamp of the corresponing RACH burst. */
//@{
unsigned mT1p; ///< T1 mod 32
unsigned mT2;
unsigned mT3;
//@}
public:
L3RequestReference() {}
L3RequestReference(unsigned wRA, const GSM::Time& when)
:mRA(wRA),
mT1p(when.T1()%32),mT2(when.T2()),mT3(when.T3())
{}
size_t lengthV() const { return 3; }
void writeV(L3Frame &, size_t &wp ) const;
void parseV( const L3Frame&, size_t&) { assert(0); }
void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
void text(std::ostream&) const;
};
/** Timing Advance, GSM 04.08 10.5.2.40 */
class L3TimingAdvance : public L3ProtocolElement
{
// TimingAdvance
// 7 6 5 4 3 2 1 0
// [ spare(0,0) ][ TimingAdvance [5:0] ] Octet 1
unsigned mTimingAdvance;
public:
L3TimingAdvance(unsigned wTimingAdvance=0)
:L3ProtocolElement(),
mTimingAdvance(wTimingAdvance)
{}
size_t lengthV() const { return 1; }
void writeV(L3Frame&, size_t &wp) 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.31 */
// 44.018 10.5.2.31
// (pat) The default RR cause 0 indicates "Normal Event"
class L3RRCause : public L3ProtocolElement
{
public:
enum RRCause {
NormalEvent = 0,
Unspecified = 1,
ChannelUnacceptable = 2,
TimerExpired = 3,
NoActivityOnTheRadio = 4,
PreemptiveRelease = 5,
UTRANConfigurationUnknown = 6,
HandoverImpossible = 8, // (Timing out of range)
ChannelModeUnacceptable = 9,
FrequencyNotImplemented = 0xa,
LeavingGroupCallArea = 0xb,
LowerLayerFailure = 0xc,
CallAlreadyCleared = 0x41,
SemanticallyIncorrectMessage = 0x5f,
InvalidMandatoryInformation = 0x60,
MessageTypeInvalid = 0x61, // Not implemented or non-existent
MessageTypeNotCompapatibleWithProtocolState = 0x62,
ConditionalIEError = 0x64,
NoCellAvailable = 0x65,
ProtocolErrorUnspecified = 0x6f
};
private: RRCause mCauseValue;
public:
/** Constructor cause defaults to "normal event". */
L3RRCause(RRCause wValue=NormalEvent)
:L3ProtocolElement()
{ mCauseValue=wValue; }
RRCause causeValue() const { return mCauseValue; }
size_t lengthV() const { return 1; }
void writeV(L3Frame&, size_t&) const;
void parseV(const L3Frame&, size_t&);
void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
void text(std::ostream&) const;
};
typedef L3RRCause::RRCause RRCause;
/** GSM 04.08 10.5.2.28 */
class L3PowerCommand : public L3ProtocolElement
{
unsigned mCommand;
public:
L3PowerCommand(unsigned wCommand=0)
:L3ProtocolElement(),
mCommand(wCommand)
{}
size_t lengthV() const { return 1; }
void writeV( L3Frame &dest, size_t &wp ) const;
void parseV( const L3Frame&, size_t&);
void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
void text(std::ostream&) const;
};
/** GSM 04.08 10.5.2.6 */
class L3ChannelMode : public L3ProtocolElement {
public:
enum Mode
{
SignallingOnly=0,
SpeechV1=1, // GSM FR or HR
SpeechV2=2, // GSM EFR (half rate not defined in this version of the protocol.)
SpeechV3=3 // AMR FR or HR
};
private:
Mode mMode;
public:
L3ChannelMode(Mode wMode=SignallingOnly)
:L3ProtocolElement(),
mMode(wMode)
{}
bool isAMR() const { return mMode == SpeechV3; }
bool operator==(const L3ChannelMode& other) const { return mMode==other.mMode; }
bool operator!=(const L3ChannelMode& other) const { return mMode!=other.mMode; }
size_t lengthV() const { return 1; }
void writeV(L3Frame&, size_t&) const;
void parseV(const L3Frame&, size_t&);
void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
void text(std::ostream&) const;
};
// 3GPP 44.018 10.5.2.21aa
// (pat) 10-2012: Multi-rate element needed for AMR codecs when L3ChannelMode is set to SpeechV3.
// Not to be confused with unrelated GPRS multi-slot.
// It is sent in the L3 Channel Mode Modify, possibly among others.
// It is a variable length element with room to specify multiple codecs,
// but we do not support AMR rate adaptation yet so we use it with just one codec.
class L3MultiRateConfiguration : public L3ProtocolElement {
// IE specifies a set of 4 among the many AMR codecs, but there are only 3 possible configurations
// that are ever of any interest to us: AMR_FR, AMR_HR, and if we ever support
// rate-adaptation, the recommended multi-rate set from 28.062 table 7.11.3.1.3-2,
// which is Config-NB-1 includes codecs: 12.2, 7.4, 5.9, 4.75 for FR_AMR and compatible with GSM AMR.
// For multi-rate we must also specify the threshold and hystersis to switch codecs, which are black
// magic and possibly dependent on MS manufacturer - gotta love that, and we also have to implement
// the TFO/TrFO (Tandem Free/Transcoder Free) Operation controller, not to mention implementing
// codec negotation through SIP. It is a lot of work.
// The options byte is a bit field defined in 10.5.2.21aa.1.
// There are only 3 possible values that will ever by useful:
enum AmrCodecSet {
codec_set_AMR_FR = 0x80,
codec_set_AMR_HR = 0x10,
codec_set_UMTS_AMR = 0x80 + 0x10 + 4 + 1 // AMR multi-rate config, in case we ever use it.
};
unsigned mOptions; // octet "3".
AmrCodecSet mAmrCodecSet; // Choose one of the above.
public:
L3MultiRateConfiguration(bool halfrate=0) {
mOptions = 0x20; // AMR version 1 (ie, not WB), no noise suppression, no initial codec.
mAmrCodecSet = halfrate ? codec_set_AMR_HR : codec_set_AMR_FR;
}
// excluding IEI and the length byte itself, the fixed length for a single non-adaptive codec is 2.
size_t lengthV() const { return 2; }
void parseV(const L3Frame&, size_t&) { assert(0); }
void parseV(const L3Frame&, size_t& , size_t) { assert(0); } // Use this one for TLV format
void writeV(L3Frame&, size_t&) const;
void text(std::ostream&) const;
};
std::ostream& operator<<(std::ostream&, L3ChannelMode::Mode);
/** GSM 04.08 10.5.2.43 */
class L3WaitIndication : public L3ProtocolElement {
private:
unsigned mValue; ///< T3122 or T3142 value in seconds
public:
L3WaitIndication(unsigned seconds)
:L3ProtocolElement(),
mValue(seconds)
{}
size_t lengthV() const { return 1; }
void writeV(L3Frame& dest, size_t &wp) const
{ dest.writeField(wp,mValue,8); }
void parseV(const L3Frame&, size_t&) { assert(0); }
void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
void text(std::ostream& os) const { os << mValue; }
};
/**
Application Information Information Elements (encapsulates the RRLP message)
*/
/** GSM 04.08 10.5.2.48 */
class L3APDUID : public L3ProtocolElement {
private:
unsigned mProtocolIdentifier;
public:
/** Default Protocol Identifier is RRLP=0, the only one defined so far (rest are reserved). */
L3APDUID(unsigned protocolIdentifier=0)
:L3ProtocolElement(),
mProtocolIdentifier(protocolIdentifier)
{}
size_t lengthV() const { return 1; }
void writeV(L3Frame& dest, size_t &wp) const;
void parseV(const L3Frame&, size_t&);
void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
void text(std::ostream& os) const;
};
/** GSM 04.08 10.5.2.49 */
class L3APDUFlags : public L3ProtocolElement {
private:
// TODO - use bool for flags?
unsigned mCR;
unsigned mFirstSegment;
unsigned mLastSegment;
// TODO - put enums for CR, FirstSegment, LastSegment
public:
/** Default is the flags for a single segment APDU - one that fits in a single
Application Information message **/
L3APDUFlags(unsigned cr=0, unsigned firstSegment=0, unsigned lastSegment=0)
:L3ProtocolElement(),
mCR(cr), mFirstSegment(firstSegment), mLastSegment(lastSegment)
{}
size_t lengthV() const { return 1; }
void writeV(L3Frame& dest, size_t &wp) const;
void parseV(const L3Frame&, size_t&);
void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
void text(std::ostream& os) const;
};
/** GSM 04.08 10.5.2.50 */
class L3APDUData : public L3ProtocolElement {
private:
BitVector2 mData; // will contain a RRLP message
public:
virtual ~L3APDUData();
/** Default is a zero length APDUData IE */
L3APDUData();
L3APDUData(BitVector2 data);
size_t lengthV() const
{
// Return number of bytes neede to hold mData
size_t sz = mData.size();
size_t ln = sz/8;
if (sz % 8) ln++;
return ln;
}
void writeV(L3Frame& dest, size_t &wp) const;
void parseV( const L3Frame& src, size_t &rp, size_t expectedLength );
void parseV(const L3Frame&, size_t&) { abort(); }
void text(std::ostream& os) const;
};
/** GSM 04.08 10.5.2.20 */
class L3MeasurementResults : public L3ProtocolElement {
private:
bool mBA_USED;
bool mDTX_USED;
bool mMEAS_VALID; ///< 0 for valid, 1 for non-valid
unsigned mRXLEV_FULL_SERVING_CELL;
unsigned mRXLEV_SUB_SERVING_CELL;
unsigned mRXQUAL_FULL_SERVING_CELL;
unsigned mRXQUAL_SUB_SERVING_CELL;
unsigned mNO_NCELL;
unsigned mRXLEV_NCELL[6];
unsigned mBCCH_FREQ_NCELL[6];
unsigned mBSIC_NCELL[6];
public:
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)
{ }
size_t lengthV() const { return 16; }
void writeV(L3Frame&, size_t&) const { assert(0); }
void parseV(const L3Frame&, size_t&);
void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
void text(std::ostream& os) const;
string text() const;
/**@name Accessors. */
//@{
bool BA_USED() const { return mBA_USED; }
bool DTX_USED() const { return mDTX_USED; }
bool MEAS_VALID() const { return mMEAS_VALID; }
unsigned RXLEV_FULL_SERVING_CELL() const { return mRXLEV_FULL_SERVING_CELL; }
unsigned RXLEV_SUB_SERVING_CELL() const { return mRXLEV_SUB_SERVING_CELL; }
unsigned RXQUAL_FULL_SERVING_CELL() const { return mRXQUAL_FULL_SERVING_CELL; }
unsigned RXQUAL_SUB_SERVING_CELL() const { return mRXQUAL_SUB_SERVING_CELL; }
unsigned NO_NCELL() const { return mNO_NCELL; }
unsigned RXLEV_NCELL(unsigned i) const { assert(i<mNO_NCELL); return mRXLEV_NCELL[i]; }
unsigned RXLEV_NCELLs(unsigned *) const;
unsigned BCCH_FREQ_NCELL(unsigned i) const { assert(i<mNO_NCELL); return mBCCH_FREQ_NCELL[i]; }
unsigned BCCH_FREQ_NCELLs(unsigned *) const;
unsigned BSIC_NCELL(unsigned i) const { assert(i<mNO_NCELL); return mBSIC_NCELL[i]; }
unsigned BSIC_NCELLs(unsigned *) const;
//@}
/**@ Real-unit conversions. */
//@{
/** Given an encoded level, return a value in dBm. */
int decodeLevToDBm(unsigned lev) const;
/** Given an encoded quality, return a BER. */
float decodeQualToBER(unsigned qual) const;
/**@ Converted accessors. */
//@{
int RXLEV_FULL_SERVING_CELL_dBm() const
{ return decodeLevToDBm(mRXLEV_FULL_SERVING_CELL); }
int RXLEV_SUB_SERVING_CELL_dBm() const
{ return decodeLevToDBm(mRXLEV_SUB_SERVING_CELL); }
float RXQUAL_FULL_SERVING_CELL_BER() const
{ return decodeQualToBER(mRXQUAL_FULL_SERVING_CELL); }
float RXQUAL_SUB_SERVING_CELL_BER() const
{ return decodeQualToBER(mRXQUAL_SUB_SERVING_CELL); }
int RXLEV_NCELL_dBm(unsigned i) const
{ assert(i<mNO_NCELL); return decodeLevToDBm(mRXLEV_NCELL[i]); }
//@}
//@}
};
/** 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&);
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; // Range 0 to 255
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&src, size_t&rp) { mValue = src.readField(rp,8); }
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; // Normal Cell Indication. 0 => ignore TA out of range. 1 => handover fail on TA out of range.
bool mROT; // Report Observed Time difference in Handover Complete.
int mSI; // Synchronization Indication. 0 = unsynchronized.
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&);
void text(std::ostream&) const;
unsigned NCI() const { return mNCI; }
unsigned ROT() const { return mROT; }
};
/** GSM 04.08 10.5.2.28a */
// (pat) Defaults to 0 which is maximum possible power.
class L3PowerCommandAndAccessType : public L3PowerCommand { };
/** A special subclass for rest octets, just in case we need it later. */
class L3RestOctets : public L3ProtocolElement {
};
class L3SI3RestOctets : public L3RestOctets {
private:
// We do not yet support the full parameter set.
bool mHaveSI3RestOctets;
bool mHaveSelectionParameters;
bool mCBQ;
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:
L3SI3RestOctets();
size_t lengthV() const;
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;
};
#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
#endif
// vim: ts=4 sw=4