Files
openbts/GSM/GSML3GPRSElements.cpp
2014-07-16 23:57:22 +02:00

379 lines
13 KiB
C++

/**@file @brief L3 Radio Resource messages related to GPRS */
/*
* Copyright 2008, 2010 Free Software Foundation, Inc.
* Copyright 2011 Kestrel Signal Processing, Inc.
* Copyright 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 distribution.
*
* 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.
*/
#define LOG_GROUP LogGroup::GSM // Can set Log.Level.GSM for debugging
#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) << ")";
}
};