OpenBTS-UMTS/UMTS/UMTSConfig.cpp

1657 lines
74 KiB
C++

/**@file Central organizing object for UMTS Uu state. */
/*
* OpenBTS provides an open source alternative to legacy telco protocols and
* traditionally complex, proprietary hardware systems.
*
* Copyright 2011, 2012, 2014 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero General
* Public License version 3. See the COPYING and NOTICE files in the main
* directory for licensing information.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
*/
#include "UMTSConfig.h"
#include "UMTSTransfer.h"
#include "UMTSLogicalChannel.h"
#include <ControlCommon.h>
#include <Logger.h>
#include <Ggsn.h>
#include "AsnHelper.h"
//#include "asn_system.h" // Dont let other includes land in namespace ASN.
namespace ASN {
#include "asn_SEQUENCE_OF.h"
//#include "SystemInformation-BCH.h"
#include "CompleteSIBshort.h"
#include "MasterInformationBlock.h"
#include "SysInfoType1.h"
#include "SysInfoType2.h"
#include "SysInfoType3.h"
#include "SysInfoType4.h"
#include "SysInfoType5.h"
#include "SysInfoType6.h"
#include "SysInfoType7.h"
#include "SysInfoType8.h"
#include "SysInfoType9.h"
#include "SysInfoType10.h"
#include "SysInfoType11.h"
#include "SysInfoType12.h"
#include "SysInfoType13.h"
#include "SysInfoType14.h"
#include "SysInfoType15.h"
#include "SysInfoType16.h"
#include "SysInfoType17.h"
#include "SysInfoType18.h"
#include "SIB-Type.h"
#include "SystemInformation-BCH.h"
};
#include "URRC.h"
#define PAT_TEST 0
using namespace std;
using namespace UMTS;
using namespace ASN; // Historical: this module written before namespace ASN added.
static const unsigned sBeaconStartInvalid = 1; // Impossible value.
static unsigned sPrevBeaconStart = sBeaconStartInvalid;
static const unsigned sMaxSibId = 18;
/** An array of the SIB types we support. */
//const SIBSb_TypeAndTag_PR UMTSConfig::SIBTypes[] = {
// SIBSb_TypeAndTag_PR_sysInfoType1,
// SIBSb_TypeAndTag_PR_sysInfoType2,
// SIBSb_TypeAndTag_PR_sysInfoType3,
// SIBSb_TypeAndTag_PR_sysInfoType5,
// SIBSb_TypeAndTag_PR_sysInfoType7,
// SIBSb_TypeAndTag_PR_sysInfoType11,
//};
//const unsigned UMTSConfig::numSIBTypes = sizeof(UMTSConfig::SIBTypes)/sizeof(SIBSb_TypeAndTag_PR);
// (pat) The plan for SIB scheduling. I didnt write a scheduler, so must be done manually.
// If we discover that we dont know the number of segs ahead of time, then
// it will be time to write a scheduler.
// Note that only even Frame Numbers are used.
// Uses terminology from 8.1.1.1.5.
struct SibInfo_t {
unsigned mSibIndex; // Index into mSibPhase1, 0..mNumSibTypes-1.
const char *mSibId; // User printable name: MIB or SIB block type id to which this plan applies.
ASN::e_SIB_Type mSibAsnType; // The ASN enum value for this SIB id.
ASN::SIBSb_TypeAndTag_PR mTypeTag; // Another ASN enum value needed for this SIB.
unsigned mSegCount; // Number of segs.
unsigned mSibPos; // The position (phase?) of the first segment within one cycle.
unsigned mSibRep; // Repetition period.
// mSibOff - Documentation sucks so badly for this that I am just using the default,
// which is that all segments are consecutive, even though other layouts might
// have been more clever (like subsequent segments in same slot in next cycle.)
};
class BeaconConfig {
ASN::MasterInformationBlock mMIB;
ASN::SysInfoType1 mSIB1;
ASN::SysInfoType2 mSIB2;
ASN::SysInfoType3 mSIB3;
ASN::SysInfoType3 mSIB4;
ASN::SysInfoType5 mSIB5;
ASN::SysInfoType6 mSIB6;
ASN::SysInfoType7 mSIB7;
ASN::SysInfoType8 mSIB8;
ASN::SysInfoType9 mSIB9;
ASN::SysInfoType10 mSIB10;
ASN::SysInfoType11 mSIB11;
ASN::SysInfoType12 mSIB12;
ASN::SysInfoType13 mSIB13;
ASN::SysInfoType14 mSIB14;
ASN::SysInfoType15 mSIB15;
ASN::SysInfoType16 mSIB16;
ASN::SysInfoType17 mSIB17;
ASN::SysInfoType18 mSIB18;
/**@ Beacon paramters. */
//@{
unsigned mMIBValueTag;
UInt_z mNumSibTypes;
SibInfo_t mSibInfo[sMaxSibId+1];
//static const ASN::SIBSb_TypeAndTag_PR SIBTypes[];
static const unsigned sMaxSibSegments = 4; // Max segments required by a SIB.
//@}
// This lock protects mSibPhase1, which is regnerated and used asynchronously.
mutable Mutex mBeaconLock; ///< multithread access control
// ByteVectors to hold the output of the phase1 SIB encoding.
ByteVector *mSibPhase1[sMaxSibId+1]; // +1 for MIB
/**@ Beacon scheduling table. */
//@{
// Only every other frame is used because the beacon uses TTI 20ms
// and MIB is broadcast every 8th frame, so every 8 frames we can
// broadcast 8/2-1 = 3 SIBs. We currently broadcast 6 SIBs and
// one of them is segmented, so we need a minimum repeat period of 32.
static const unsigned msSibRepeat = 32;
// (pat) Only the even values of mSIBSched are used, because TTI 20ms beacon,
// so we dont bother saving the others.
TransportBlock *mSibSched[msSibRepeat/2];
//@}
/** Encode an SIB to a transpoint block and populate it into the scheduling table. */
void encodeSIBPhase1(
unsigned sibIndex, // Index into mSibInfo.
const char *sibId, // The RRC spec SIB type number used only for user readable messages, may be double in future.
struct ASN::asn_TYPE_descriptor_s *type_descriptor,
void *struct_ptr); /* Structure to be encoded */
void encodeSI(const char *sibId, ASN::SystemInformation_BCH &si, TransportBlock *trb, unsigned sfn);
void encodeSIBPhase2( SibInfo_t *plan, unsigned sfn);
void addSibPlan(const char *wSibId, // user printable name for SIB type id (1,2,..) or 0 for MIB.
unsigned wSibPos, // The position, of the first segment within one cycle.
unsigned wSegCount, // Number of segs.
unsigned wSibRep, // Repetition period.
ASN::e_SIB_Type wSibASNType, // The ASN enum value for this SIB id.
ASN::SIBSb_TypeAndTag_PR wTypeTag); // Another ASN enum value needed for this SIB.
public:
void beaconInit();
BeaconConfig();
void regenerate();
void encodePhase2(unsigned sfn);
TransportBlock *getSITB(unsigned sfn) { // Get System Information Transport Block.
assert(!(sfn&1));
return mSibSched[(sfn % msSibRepeat)/2];
}
};
static class BeaconConfig sBeacon;
BeaconConfig::BeaconConfig()
: mMIBValueTag(0),mNumSibTypes(0)
{
memset(mSibPhase1,0,sizeof(mSibPhase1)); // overkill - be safe
memset(mSibInfo,0,sizeof(mSibInfo)); // overkill - be safe
memset(mSibSched,0,sizeof(mSibSched)); // overkill - be safe
}
// TODO: This code should not be in a constructor because it implicitly references BitVector.
void BeaconConfig::beaconInit()
{
for (unsigned i = 0; i < msSibRepeat/2; i++) {
// Note: The TransportBlock on BCH is all payload.
// If BCCH is mapped to FACH, then there is a 2 bit header, but we dont do that.
mSibSched[i] = new TransportBlock(sSIBTrBlockSize);
RN_MEMLOG(TransportBlock,mSibSched[i]);
}
#define SIB_TAGS(n) \
ASN::SIB_Type_systemInformationBlockType##n, ASN::SIBSb_TypeAndTag_PR_sysInfoType##n
// First entry is for the MIB, transmitted on an 8 frame cycle.
// The final argument is ignored, but we need to provide something that C++ accepts.
addSibPlan("MIB",0,1,8,ASN::SIB_Type_masterInformationBlock, SIBSb_TypeAndTag_PR_NOTHING);
addSibPlan("SIB1",2,1,16,SIB_TAGS(1)); // SIB 1 at pos 2
addSibPlan("SIB2",4,1,16*2,SIB_TAGS(2)); // SIB 2 at pos 4
addSibPlan("SIB3",6,1,16*2,SIB_TAGS(3)); // SIB 3 at pos 6; pos 8 reserved for MIB.
// SIB 5 at pos 10, with 2 segments (ie 2 TransportBlocks)
addSibPlan("SIB5",10,3,16,SIB_TAGS(5));
// SIB 7 at pos 14 in 32-frame cycle.
addSibPlan("SIB7",20,1,32,SIB_TAGS(7));
// SIB 11 shares slot with SIB7 in a 32 frame cycle.
addSibPlan("SIB11",22,1,32,SIB_TAGS(11));
//addSibPlan("SIB12",62,1,64,SIB_TAGS(12));
// (pat) Note: You cant regenerate the beacon in this constructor because
// the other class constructors have not been called yet.
}
static int getConfigSccpchSF()
{
return gConfig.getNum("UMTS.SCCPCH.SF");
}
static int getConfigPrachSF()
{
return gConfig.getNum("UMTS.PRACH.SF");
}
UMTSConfig::UMTSConfig():
// (pat) The radiomodem does not get the downlink scrambling code from here,
// so I am removing it from this constructor as too confusing.
// (pat) The class initializations should be finished before allocating
// the FECs, so I am changing mBCH to a pointer and allocating it later.
//mBCH(gConfig.getNum("UMTS.Downlink.ScramblingCode")),
mInited(0),
mBand((UMTSBand)gConfig.getNum("UMTS.Radio.Band")),
mStartTime(::time(NULL))
{
}
void UMTSConfig::init(ARFCNManager *downstream)
{
if (gConfig.defines("UMTS.Debug")) { rrcDebugLevel = gConfig.getNum("UMTS.Debug.RRC"); }
// The default constructor for mBCH is fine.
mBCH = new BCHFEC(downstream);
// The channels 256,0 and 256,1 are reserved by UMTS.
// TODO: Modify the beacon to get the fec classes.
int chcode = gConfig.getNum("UMTS.SCCPCH.SpreadingCode"); // Use two consecutive ch starting here.
unsigned fachSF = getConfigSccpchSF();
unsigned rachSF = getConfigPrachSF();
rrcInitCommonCh(rachSF,fachSF);
unsigned ulScCode = gConfig.getNum("UMTS.PRACH.ScramblingCode");
RrcTfs *tfs = gRrcCcchConfig->getDlTfs(0);
mFachFec = new FACHFEC(fachSF,chcode,tfs->getPB(),tfs->getTBSize(0),tfs->getTTICode(),downstream);
mFachFec->fecConfig(gRrcCcchConfig->mTrCh);
mFachFec->open();
tfs = gRrcCcchConfig->getUlTfs(0);
//mPchFec = new PCHFEC(fachSF,chcode+1,downstream); Not implemented yet, so dont bother.
mRachFec = new RACHFEC(rachSF,ulScCode,tfs->getPB(),tfs->getTBSize(0),tfs->getTTICode());
mRachFec->fecConfig(gRrcCcchConfig->mTrCh);
mRachFec->open();
macHookupRachFach(mRachFec,mFachFec,true);
mInited = true;
sBeacon.beaconInit();
regenerateBeacon(); // (pat) This is the second call; we ignored the first - see apps/OpenBTS-UMTS.cpp
// TODO: Right now regenerateBeacon is reserving channels.
// That should be done above, but no matter. We can populate the channel tree now.
gChannelTree.chPopulate(downstream);
/***
// For debugging purposes: test the ChannelTree...
std::cout << "Testing ChannelTree\n";
gChannelTree.chTest(std::cout);
exit(1);
***/
// This encodePhase2 is redundant, but causes this code to be tested during
// initialization, even if there is no transciever.
// Use UMTSConfig::time() to make sure we fail if overloaded UMTSConfig::time() is renamed
// we dont get time() from the standard library.
sBeacon.encodePhase2(UMTSConfig::time());
/***
// Debug: do it a few more times.
regenerateBeacon();
sBeacon.encodePhase2(0);
regenerateBeacon();
sBeacon.encodePhase2(1000);
regenerateBeacon();
sBeacon.encodePhase2(2000);
regenerateBeacon();
sBeacon.encodePhase2(3000);
***/
}
void UMTSConfig::start(ARFCNManager* C0)
{
sPrevBeaconStart = sBeaconStartInvalid; // Force beacon re-encoding
//mPowerManager.start();
mPager.start();
//mBCH->setDownstream(C0); (pat) Moved this to the constructor.
mBCH->start();
// mFachFec->setDownstream(C0); (pat) Moved this to the constructor.
// Do not call this until AGCHs are installed.
//mAccessGrantThread.start(RRC::AccessGrantServiceLoop,NULL);
SGSN::Ggsn::start();
l2RlcStart(); // Start the handler for the high side of RLCs.
}
void BeaconConfig::addSibPlan(const char *wSibId, // user printable SIB type id (1,2,..) or 0 for MIB.
unsigned wSibPos, // The position, always even, of the first segment within one cycle.
unsigned wSegCount, // Number of segs.
unsigned wSibRep, // Repetition period.
ASN::e_SIB_Type wSibAsnType, // The ASN enum value for this SIB id.
ASN::SIBSb_TypeAndTag_PR wTypeTag) // Another ASN enum value needed for this SIB.
{
unsigned ind = mNumSibTypes;
mSibInfo[ind].mSibIndex = mNumSibTypes; // Used as index into mSibPhase1.
mSibInfo[ind].mSibId = wSibId; // user printable name
mSibInfo[ind].mSibPos = wSibPos;
mSibInfo[ind].mSegCount = wSegCount;
mSibInfo[ind].mSibRep = wSibRep;
mSibInfo[ind].mSibAsnType = wSibAsnType;
mSibInfo[ind].mTypeTag = wTypeTag;
// Create the buffer for the phase1 encoder:
mSibPhase1[ind] = new ByteVector(1 + (sMaxSibSegments * sSIBTrBlockSize)/8);
mSibPhase1[ind]->fill(0); // unnecessary but neat.
RN_MEMLOG(ByteVector,mSibPhase1[ind]);
mNumSibTypes = mNumSibTypes + 1;
}
//unsigned SIBOffset(unsigned i)
//{
// // The pattern is 2, 4, 6, 10, 12, 14, 18, 20, 22 ...
// // because the MIB goes at position 0, 8, 16, ...
// // The times 2 is because the result is an SFN [frame number] but the beacon
// // is TTI 20ms, ie, 2 frames per SIB.
// unsigned m3 = i%3;
// unsigned d3 = i/3;
// return d3*8 + (m3+1)*2;
//}
// We zero out the entire byte that endBit falls in.
// Unused, untested.
//static void zeroBitPad(char *buf, unsigned startBit, unsigned lengthBits)
//{
// unsigned pos = startBit/8;
// unsigned tailBits = startBit%8;
// if (tailBits) { // Zero the tail of the last byte.
// unsigned mask = (1 << (8-tailBits)) - 1; // Mask of bits we want to zero.
// buf[pos++] &= ~mask;
// }
// while (pos < (lengthBits+7)/8) { buf[pos++] = 0; }
//}
// Encode the SIB into an ASN struct into the corresponding mSibPhase1[] buffer.
void BeaconConfig::encodeSIBPhase1(
unsigned sibIndex,
const char *sibId,
struct asn_TYPE_descriptor_s *type_descriptor,
void *struct_ptr) /* Structure to be encoded */
{
bool rn_asn_debug_beacon = gConfig.getNum("UMTS.Debug.ASN.Beacon");
if (rn_asn_debug_beacon) { printf("=== Phase1 Encoding SIB %s\n",sibId); }
assert(0 == strcmp(sibId,mSibInfo[sibIndex].mSibId));
ByteVector *perBuf = mSibPhase1[sibIndex];
perBuf->resetSize();
asn_enc_rval_t rval = uper_encode_to_buffer(
type_descriptor,struct_ptr,(void*)perBuf->begin(),perBuf->size());
int numBits = rval.encoded; // Must be an int to detect less than zero!!
if (numBits<0) {
LOG(ERR) << "failed to encode SIB " << sibId <<" into buf size="<<perBuf->size();
assert(0);
}
perBuf->setSizeBits(numBits);
printf("=== Phase1 Encoded SIB %s size %u blocks %g\n",sibId,numBits,numBits/226.0);
if (rn_asn_debug_beacon) {
cout << "SIB" << sibIndex << ": bytes: " << *perBuf << endl;
}
fflush(stdout);
}
// Encode the System Information message into a TransportBlock.
void BeaconConfig::encodeSI(const char *sibId, SystemInformation_BCH &si, TransportBlock *trb, unsigned sfn)
{
// Second step encoding of the complete System Information message, as per 25.331 12.1.3-2
const unsigned bufSize = 1+ 1 + sSIBTrBlockSize/8;
unsigned char siPerBuf[bufSize];
// (10-5-2012 pat) The encoder output appears to have interjected randomness, so lets try pre-zeroing out the buffer:
// Update: that did the trick.
memset(siPerBuf,0,bufSize);
// (pat) result.encoded is number of bits, despite documentation
// at asn_enc_rval_t that claims it is in bytes.
//rn_asn_debug = gConfig.getNum("UMTS.Debug.ASN.Beacon");
asn_enc_rval_t siRval = uper_encode_to_buffer(&asn_DEF_SystemInformation_BCH,&si,(void*)siPerBuf,bufSize);
if (siRval.encoded<0) {
LOG(ERR) << "failed to encode SIB " << sibId;
assert(0);
}
int sizeBits = siRval.encoded;
if (sizeBits > (int)trb->size()) {
LOG(ERR) << "SIB " << sibId << " size " << sizeBits << " does not fit BCH transfer block " << trb->size();
}
// TODO: Just zero out the tail, but I didnt want to risk changing this while Harvind
// is busily debugging it.
trb->zero(); // Pat added.
trb->unpack(siPerBuf);
trb->setSchedule(sfn);
trb->mDescr = (string)sibId; // TODO: make sibId a string so this does not bother to allocate memory.
}
// Put the SIBs, which were previously phase1 encoded into PER strings, into
// one or more System Information messages inside TransportBlocks to go in the beacon.
// We have to run this anew for each beacon because the blocks include the SFN.
// See 10.2.48 SYSTEM INFORMATION message.
// See also: 8.1.1.1.3 "Segmentation and concatenation of system information blocks",
// and there is a picture at Figure 12.1.3-2: "Padding for System Information."
void BeaconConfig::encodeSIBPhase2(
SibInfo_t *plan,
unsigned sfn)
{
SystemInformation_BCH si;
memset(&si,0,sizeof(si));
assert(!(sfn&1)); // sfn is even.
si.sfn_Prime = sfn/2;
unsigned pos = sfn % msSibRepeat; // Position in the beacon.
ByteVector *in = mSibPhase1[plan->mSibIndex];
#if 0
// DIETER messages
/*if (plan->mSibIndex == 1) { // SIB1
const char dufus[] = "C4020188000C10001802019C035680";
BitVector tmp(15*8);
tmp.unhex(dufus);
in = new ByteVector(tmp);
}*/
/*if (plan->mSibIndex == 3) { // SIB3
const char dufus[] = "800000001B0C00080000969BC0";
BitVector tmp(13*8);
tmp.unhex(dufus);
in = new ByteVector(tmp);
}*/
/*if (plan->mSibIndex == 3) { // SIB5
const char dufus[] = "256C3AFFFF43FFFC5210F0290C0A8018000C8FF7B17EE10FF000003F3647FF03202038101608100088642990A50018088B9581000F18C108B6D850021844A05880318400";
BitVector tmp(68*8);
tmp.unhex(dufus);
in = new ByteVector(tmp);
}*/
/*if (plan->mSibIndex == 6) { // SIB11
const char dufus[] = "019FC10609B20696B29201020A2A80A80BB005411400049F600A00";
BitVector tmp(27*8);
tmp.unhex(dufus);
in = new ByteVector(tmp);
}*/
#endif
//LOG(INFO) << "sfn: " << sfn << " ix: " << plan->mSibIndex;
// (pat) 25.331 12.1.3-2 "Padding for System Information" is difficult reading.
// Translated: you use the exact bit-length from the first per encoder step above,
// which is equivalent to "ignoring the padding added to achieve octet alignment".
// Then if you land in one of the fixed length variants below (eg, completeSIB)
// you must zero-bit-pad to the fixed length of the buffer, eg 226.
int numBits = in->sizeBits();
if (numBits <= 214) {
// Short variant: 10.2.48.7. 214 is a magic number from the IE description.
// Note: the IE description says "upto 214 bits" but they mean inclusive.
assert(plan->mSegCount == 1);
si.payload.present = SystemInformation_BCH__payload_PR_completeSIB_List;
CompleteSIBshort_t sibShort;
memset(&sibShort,0,sizeof(sibShort));
asn_long2INTEGER(&sibShort.sib_Type, plan->mSibAsnType);
// We use the exact bit length here, which is equivalent
// to truncating the "encoder added padding".
setAsnBIT_STRING(&sibShort.sib_Data_variable,in->begin(),numBits);
ASN_SEQUENCE_ADD(&si.payload.choice.completeSIB_List,&sibShort);
encodeSI(plan->mSibId, si, getSITB(pos),sfn);
} else if (numBits <= 226) {
// Long variant: 10.2.48.6 226 is the magic maximum length number from the IE description.
assert(plan->mSegCount == 1);
si.payload.present = SystemInformation_BCH__payload_PR_completeSIB;
// In this case the bit string is zero padded out to length 226.
// 12.1.3. says the worst case padding needed is 17, so 32 should be plenty.
in->setField(numBits,0,32);
asn_long2INTEGER(&si.payload.choice.completeSIB.sib_Type, plan->mSibAsnType);
// (10-2012 pat) The 226 is longer than in.size but the underlying ByteVector is large enough to
// hold the maximum size payload so we are not reading beyond the end of the ByteVector storage.
setAsnBIT_STRING(&si.payload.choice.completeSIB.sib_Data_fixed,in->begin(),226);
encodeSI(plan->mSibId, si, getSITB(pos),sfn);
} else {
// The first segment holds 222 bits.
// The second segment uses "Last segment (short)" format up to 214 bits.
// There are longer formats but we dont need them yet.
assert(plan->mSegCount > 1);
// First Segment 10.2.48.1
int i = 0;
do {
if (i == 0) {
si.payload.present = SystemInformation_BCH__payload_PR_firstSegment;
FirstSegment_t *firstSeg = &si.payload.choice.firstSegment;
asn_long2INTEGER(&firstSeg->sib_Type, plan->mSibAsnType);
firstSeg->seg_Count = plan->mSegCount;
//LOG(INFO) << "SIB5: " << *in;
setAsnBIT_STRING(&firstSeg->sib_Data_fixed,in->begin(),222);
encodeSI(plan->mSibId, si, getSITB(pos), sfn);
} else {
// Harvind was here...
si.payload.present = SystemInformation_BCH__payload_PR_subsequentSegment;
SubsequentSegment_t *subSeg = &si.payload.choice.subsequentSegment;
asn_long2INTEGER(&subSeg->sib_Type, plan->mSibAsnType);
subSeg->segmentIndex = i;
//LOG(INFO) << "SIB5: " << *in;
setAsnBIT_STRING(&subSeg->sib_Data_fixed,in->begin(),222);
encodeSI(plan->mSibId, si, getSITB(pos), sfn);
}
// We need to chop off the first 222 bits. 222 == 27*8+6.
// todo: make this more efficient.
numBits = numBits-222;
#if PAT_TEST
// TODO: Try to test this:
ByteVector *in2 = new ByteVector((numBits+7)/8);
for (int j = 0; j < numBits; j++) {
in2->setBit(j,in->getBit(j+222));
}
in = in2;
#else
BitVector tmp1(numBits +6+8);
tmp1.unpack(in->begin()+27);
BitVector tmp2(tmp1.tail(6));
unsigned char buf[numBits/8+2];
tmp2.pack(buf);
if (i > 0) delete in;
in = new ByteVector(buf,numBits/8+2); // convert back to byte array.
RN_MEMLOG(ByteVector,in);
#endif
// Next segment
sfn += 2;
pos = sfn % msSibRepeat; // Position in the beacon.
memset(&si,0,sizeof(si));
si.sfn_Prime = sfn/2;
i++;
} while (numBits > 222);
if (numBits <= 214) {
si.payload.present = SystemInformation_BCH__payload_PR_lastSegmentShort;
LastSegmentShort_t *lastSegShort = &si.payload.choice.lastSegmentShort;
asn_long2INTEGER(&lastSegShort->sib_Type, plan->mSibAsnType);
// This is the 0 based segment index, but since it does not appear in
// the first block, it is range 1..15
lastSegShort->segmentIndex = i;
setAsnBIT_STRING(&lastSegShort->sib_Data_variable,in->begin(),numBits);
encodeSI(plan->mSibId, si, getSITB(pos), sfn);
}
else {
si.payload.present = SystemInformation_BCH__payload_PR_lastSegment;
LastSegment_t *lastSeg = &si.payload.choice.lastSegment;
asn_long2INTEGER(&lastSeg->sib_Type, plan->mSibAsnType);
lastSeg->segmentIndex = i;
#if PAT_TEST
if (numBits < 222) { in->setField(numBits,0,222 - numBits); } // (pat) zero pad the tail.
#endif
setAsnBIT_STRING(&lastSeg->sib_Data_fixed,in->begin(),222); //numBits);
encodeSI(plan->mSibId, si, getSITB(pos), sfn);
}
delete in;
} /*else {
LOG(ERR) << "SIB " << plan->mSibId << " size " << numBits << " does not fit SI block";
assert(0);
}*/
}
// (pat) And just where are we supposed to put the additional segments for multi-segment SIBs?
// The documentation for this totally sucks.
// In 8.1.1.1.5, the intro comment indicates they wanted to have short-rep period blocks
// interspersed with "blocks with segmentation over many frames".
// Well, first there is no necessary reason why rep-period and segmentation are
// mutually exclusive so the comment is intrinsically slightly nonsensical.
// Elsewhere in this paragraph the word "frame" means a radio frame;
// I think they meant to say "cycle" to mean a group of rep-period [eg 16] frames.
// Later there is a formula that specifies non-uniform offsets, implying that
// the segments can be scattered over long distances, as is their intention.
// But SIB_OFF is an indexed variable in the repetition formula. Sigh.
// The real clue is in a comment from 10.3.8.16, and I quote:
// "SIB_POS Offset Info: The default value is that all segments are
// consecutive, i.e., that the SIB_OFF = 2 for all
// segments except when MIB segment/complete MIB is
// scheduled to be transmitted in between segments
// from same SIB. In that case, SIB_OFF=4 in between
// segments which are scheduled to be transmitted at
// SFNprime = 8 *n-2 and 8*n + 2, and SIB_OFF=2 for the rest of the segments."
// Ah ha! So the SIB_POS Offset IE affects the segment position in a way
// that is not documented precisely. But apparently we can ignore all this and
// just use the default value so the consecutive segments be, well, consecutive.
//void UMTSConfig::fillMIBSchedule()
//{
// // Encode MIB into transport block.
// encodeSIB(SIB_Type_masterInformationBlock, &asn_DEF_MasterInformationBlock,&mMIB,0);
// // Put pointers to MIB in SIB scheduling table at 0, 8, 16, ...
// // For FDD MIB, per table 8.1.1: SIB_POS = 0, SIB_REP = 8, SIB_OFF = 2.
// unsigned FN = 0;
// while (FN<mSIBRepeat) {
// mSibSched[FN] = tbMIB;
// FN += 8;
// }
//
//}
long UMTSConfig::getULInterference() const
{
// TODO UMTS -- This needs to really calculate something.
return -70;
}
static long *newlong(long value) {
long *result = RN_CALLOC(long);
*result = value;
return result;
}
// This fills in the mMIB and mSIB* structures.
void UMTSConfig::regenerateBeacon()
{
// The BeaconConfig::regenerate itself calls gConfig, which may try
// to do a recursive call through here; we prevent that with noRecursionPlease
static int noRecursionPlease = 0;
// This check for mInited is needed because regenerateBeacon()
// is called from purgeconfig in apps/OpenBTS-UMTS.cpp before
// the UMTSConfig class has been initialized.
if (!mInited) {return;}
ScopedLock lock(mLock); // First wait to lock the configuration.
if (noRecursionPlease) return;
noRecursionPlease++;
sBeacon.regenerate();
noRecursionPlease--;
}
static SCCPCH_SystemInformation *generateSCCPCH(unsigned fachChCode, bool addPICH,unsigned pichChCode)
{
// (pat) See 10.3.6.72: Secondary CCPCH Info IE.
SCCPCH_SystemInformation *sCCPCH_SI = RN_CALLOC(ASN::SCCPCH_SystemInformation);
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.present = SecondaryCCPCH_Info__modeSpecificInfo_PR_fdd;
asn_long2INTEGER(&(sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.dummy1),PCPICH_UsageForChannelEst_mayBeUsed);
// FIXME -- Figure out what STTD is and be sure we don't use it.
// (pat) See 10.3.6.86: STTD is one of the TX Diversity modes.
// SCCPCH Secondary Common Control Physical Channel is the one carrying FACH and PCH.
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.sttd_Indicator = false;
unsigned scc_sf = getConfigSccpchSF(); // (pat) Not currently programmable.
switch (scc_sf) {
case 256:
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.sf_AndCodeNumber.present = SF256_AndCodeNumber_PR_sf256;
break;
case 128:
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.sf_AndCodeNumber.present = SF256_AndCodeNumber_PR_sf128; //256;
break;
case 64:
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.sf_AndCodeNumber.present = SF256_AndCodeNumber_PR_sf64; //256;
break;
case 32:
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.sf_AndCodeNumber.present = SF256_AndCodeNumber_PR_sf32; //256;
break;
case 16:
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.sf_AndCodeNumber.present = SF256_AndCodeNumber_PR_sf16; //256;
break;
case 8:
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.sf_AndCodeNumber.present = SF256_AndCodeNumber_PR_sf8; //256;
break;
case 4:
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.sf_AndCodeNumber.present = SF256_AndCodeNumber_PR_sf4; //256;
break;
default:
break;
}
// We are assigning to choice.sf256 but it is the same variable location for all SFs.
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.sf_AndCodeNumber.choice.sf256 = fachChCode;
// (pat) We must reserve this spot in the ChannelTree.
// This code is redundant with the one that creates the channel in FACHFEC(),
// but cant be too careful.
// (pat) If scc_sf is not 256, then the other FACH/PICH channels are going to collide with this in the
// tree of spreading codes and need to be changed.
//gChannelTree.chReserve(scc_sf,fachChCode); // (pat) This channel may not be used for DCH.
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.pilotSymbolExistence = false;
// (pat) No tfci implies "blind" transport format selection.
// It can be used if you are not multiplexing channels so you can use the number of bits
// to imply the transport format selected.
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.tfci_Existence = true;
asn_long2INTEGER(&(sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.positionFixedOrFlexible),PositionFixedOrFlexible_fixed);
// (pat) First FACH TFS+TFCS is mandatory.
// I believe the subsequent ones are optional and will use the same one if not specified.
FACH_PCH_Information *fachPchInfo = RN_CALLOC(ASN::FACH_PCH_Information);
#if 1 //PAT_TEST
// (pat) It is 1, not 3.
fachPchInfo->transportChannelIdentity = gRrcDcchConfig->getDlTrChInfo(0)->mTransportChannelIdentity; // Range is 1..32
assert(fachPchInfo->transportChannelIdentity == 1);
#else
fachPchInfo->transportChannelIdentity = 1+1;
#endif
// We are leaving CTCH indicator false.
// PICH_info is optional - needed only if PCH is multiplexed.
gRrcCcchConfig->getDlTfs()->toAsnTfs(&fachPchInfo->transportFormatSet,true);
gRrcCcchConfig->getDlTfcs()->toAsnTfcs((sCCPCH_SI->tfcs = RN_CALLOC(ASN::TFCS)),TrChFACHType);
sCCPCH_SI->fach_PCH_InformationList = RN_CALLOC(ASN::FACH_PCH_InformationList);
ASN_SEQUENCE_ADD(&sCCPCH_SI->fach_PCH_InformationList->list,fachPchInfo);
// FIXME: Adding second FACH to SIB5, though it doesn't really exist. Phone assumes first FACH is PCH and won't go into the RACH procedure
#if 0 // unused code
/*FACH_PCH_Information *fachPchInfo2 = RN_CALLOC(ASN::FACH_PCH_Information);
memcpy(fachPchInfo2,fachPchInfo,sizeof(ASN::FACH_PCH_Information));
fachPchInfo2->transportChannelIdentity = 2;
ASN_SEQUENCE_ADD(&sCCPCH_SI->fach_PCH_InformationList->list,fachPchInfo2);*/
/*FACH_PCH_Information *fachPchInfo3 = RN_CALLOC(ASN::FACH_PCH_Information);
memcpy(fachPchInfo3,fachPchInfo,sizeof(ASN::FACH_PCH_Information));
fachPchInfo3->transportChannelIdentity = 3;
ASN_SEQUENCE_ADD(&sCCPCH_SI->fach_PCH_InformationList->list,fachPchInfo3);*/
#endif
if (addPICH) { // Add PICH
PICH_Info_t *pichInfo = RN_CALLOC(ASN::PICH_Info);
pichInfo->present = PICH_Info_PR_fdd;
assert(pichChCode < scc_sf); // Configuration error if this happens.
pichInfo->choice.fdd.channelisationCode256 = pichChCode;
asn_long2INTEGER(&(pichInfo->choice.fdd.pi_CountPerFrame),PI_CountPerFrame_e18);
pichInfo->choice.fdd.sttd_Indicator = false;
sCCPCH_SI->pich_Info = pichInfo;
}
return sCCPCH_SI;
}
// This macro is from ASN/.../constr_TYPE.h
#undef ASN_STRUCT_FREE_CONTENTS_ONLY
#define ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF,ptr) { \
rn_asn_debug = asn_debug_free; \
(asn_DEF).free_struct(&(asn_DEF),ptr,1); \
rn_asn_debug = asn_debug_beacon; \
}
void BeaconConfig::regenerate()
{
bool asn_debug_beacon = gConfig.getNum("UMTS.Debug.ASN.Beacon");
bool asn_debug_free = gConfig.getNum("UMTS.Debug.ASN.Free");
rn_asn_debug = asn_debug_beacon;
// Note: we already locked UMTSConfig.
// Currently, the only other locker is encodePhase2 which is brief.
// But make sure you dont insert a race condition here.
// (pat) NOTE: The mutex we use is recursive, so it does not prevent the same
// thread from going right through here.
ScopedLock lock(mBeaconLock);
sPrevBeaconStart = sBeaconStartInvalid; // Force beacon re-encoding, but hardly matters.
// Update everything from the configuration.
LOG(NOTICE) << "regenerating system information messages";
// TODO: Update LAI.
// TODO: We are throwing away the memory allocated in sub-structures, which is
// easy to fix, but the amount is small so defer.
// Note: You must clear the mMIB and mSIB structs before using them to make
// sure that the lists are inited to 0 size. Otherwise they just get bigger
// every time through this loop.
// Generate the MIB.
// 3GPP 25.331 10.2.48.8.1
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_MasterInformationBlock,&mMIB);
// Value Tag, 10.3.8.1
memset(&mMIB,0,sizeof(mMIB));
mMIB.mib_ValueTag = mMIBValueTag%8 + 1;
// PLMN parameters, 10.3.1.12, 10.3.1.11
mMIB.plmn_Type.present = PLMN_Type_PR_gsm_MAP;
const string MCC = gConfig.getStr("UMTS.Identity.MCC");
setASN1SeqOfDigits(
(void*)&mMIB.plmn_Type.choice.gsm_MAP.plmn_Identity.mcc.list,
MCC.c_str());
const string MNC = gConfig.getStr("UMTS.Identity.MNC");
setASN1SeqOfDigits(
(void*)&mMIB.plmn_Type.choice.gsm_MAP.plmn_Identity.mnc.list,
MNC.c_str());
// SIB reference list, 10.3.8.14
for (unsigned i=1; i<mNumSibTypes; i++) { // Skip 0, which is for the MIB
SibInfo_t *plan = &mSibInfo[i];
// (david) A bit of a hack - We are putting the MOB value tag everywhere.
// (pat) There are different versions of this list for different releases of RRC spec.
// We are using the oldest one, which uses IE 10.3.18a instead of other variants.
// List of: Scheduling Information IE 10.3.8.16 + SIB & SB Type IE 10.3.8.18a.
SchedulingInformationSIBSb *SIBSb = RN_CALLOC(ASN::SchedulingInformationSIBSb);
SIBSb->sibSb_Type.present = plan->mTypeTag;
//printf("SIB %d type %d\n",i,(int)plan->mTypeTag);
switch (plan->mTypeTag) {
case SIBSb_TypeAndTag_PR_sysInfoType1:
// type is PLMN-ValueTag, 1..256
SIBSb->sibSb_Type.choice.sysInfoType1 = mMIBValueTag%256 + 1;
break;
case SIBSb_TypeAndTag_PR_sysInfoType2:
// type is CellValueTag, 1..4
SIBSb->sibSb_Type.choice.sysInfoType2 = mMIBValueTag%4 + 1;
break;
case SIBSb_TypeAndTag_PR_sysInfoType3:
// type is CellValueTag, 1..4
SIBSb->sibSb_Type.choice.sysInfoType3 = mMIBValueTag%4 + 1;
break;
case SIBSb_TypeAndTag_PR_sysInfoType5:
// type is CellValueTag, 1..4
SIBSb->sibSb_Type.choice.sysInfoType5 = mMIBValueTag%4 + 1;
break;
case SIBSb_TypeAndTag_PR_sysInfoType7:
// type is NULL
break;
case SIBSb_TypeAndTag_PR_sysInfoType11:
// type is CellValueTag, 1..4
SIBSb->sibSb_Type.choice.sysInfoType11 = mMIBValueTag%4 + 1;
break;
case SIBSb_TypeAndTag_PR_sysInfoType12:
// type is CellValueTag, 1..4
SIBSb->sibSb_Type.choice.sysInfoType12 = mMIBValueTag%4 + 1;
break;
default:
LOG(ERR) << "uncoded sys info type " <<plan->mSibId <<" asn type "<<(int)plan->mTypeTag;
assert(0);
}
// (pat) 10.3.8.16 indicates the position is "INTEGER (0 ..Rep-2 by step of 2)",
// but the constraints in rrc.asn1 for SchedulingInformation sib-Pos are:
// rep8 INTEGER (0..3),
// rep16 INTEGER (0..7),
// rep32 INTEGER (0..15),
// In other words, we are supposed to pre-divide it by 2. Gotta love it.
switch (plan->mSibRep) {
case 8:
SIBSb->scheduling.scheduling.sib_Pos.present = SchedulingInformation__scheduling__sib_Pos_PR_rep8;
SIBSb->scheduling.scheduling.sib_Pos.choice.rep8 = plan->mSibPos/2;
break;
case 16:
SIBSb->scheduling.scheduling.sib_Pos.present = SchedulingInformation__scheduling__sib_Pos_PR_rep16;
SIBSb->scheduling.scheduling.sib_Pos.choice.rep16 = plan->mSibPos/2;
break;
case 32:
SIBSb->scheduling.scheduling.sib_Pos.present = SchedulingInformation__scheduling__sib_Pos_PR_rep32;
SIBSb->scheduling.scheduling.sib_Pos.choice.rep32 = plan->mSibPos/2;
break;
case 64:
SIBSb->scheduling.scheduling.sib_Pos.present = SchedulingInformation__scheduling__sib_Pos_PR_rep64;
SIBSb->scheduling.scheduling.sib_Pos.choice.rep64 = plan->mSibPos/2;
break;
default:
assert(0); // To fix just add the case you need.
}
if (plan->mSegCount != 1) {
SIBSb->scheduling.scheduling.segCount = RN_CALLOC(ASN::SegCount_t);
*SIBSb->scheduling.scheduling.segCount = plan->mSegCount;
#if PAT_TEST
// Try leaving this out. It is supposed to default correctly.
// The TEMS phone worked even when this was encoded incorrectly.
// The Samsung phone works without it.
#else
SIBSb->scheduling.scheduling.sib_PosOffsetInfo = RN_CALLOC(struct SibOFF_List);
// (pat) This is an array of enumerated values, not simple integers.
for (int j = 0 ; j < (int)plan->mSegCount-1; j++) {
//SibOFF* sibOff = RN_CALLOC(ASN::SibOFF);
SibOFF_t* sibOff = RN_CALLOC(ASN::SibOFF_t);
//*sibOff = SibOFF_so4; //FIXME: Why isn't this SibOFF_so2?
// (pat) Because is it is an ASN "ENUMERATED" value, a simple int, so we were
// putting the entirely wrong value in here. Amazing it worked at all.
asn_long2INTEGER(sibOff,SibOFF_so2);
ASN_SEQUENCE_ADD(&SIBSb->scheduling.scheduling.sib_PosOffsetInfo->list,sibOff);
}
#endif
}
ASN_SEQUENCE_ADD(&mMIB.sibSb_ReferenceList.list,SIBSb);
}
//fillMIBSchedule();
mMIBValueTag++;
// The SIBs themselves.
// Behold the glory that is UMTS!!
// Type 1
// 3GPP 25.331 10.2.48.8.4
// ASN SysInfoType1
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_SysInfoType1,&mSIB1);
memset(&mSIB1,0,sizeof(mSIB1));
// cn_CommonGSM_MAP_NAS_SysInfo
// See 3GPP 24.008 10.5.1.12.1. It's just the LAC.
// Let's see how many lines of C it takes to encode it!
uint16_t *LAC = (uint16_t*)calloc(1,sizeof(*LAC));
*LAC = htons(gConfig.getNum("UMTS.Identity.LAC"));
// LAC is an OCTET_STRING
mSIB1.cn_CommonGSM_MAP_NAS_SysInfo.buf = (uint8_t*)LAC;
mSIB1.cn_CommonGSM_MAP_NAS_SysInfo.size = 2;
// cn_DomainSysInfoList
// See 3GPP 24.008 10.5.1.12.2-3. Domain-specific NAS sysinfo
// For now, we are advertising PS domain only.
CN_DomainSysInfo *dsi = RN_CALLOC(ASN::CN_DomainSysInfo);
asn_long2INTEGER(&(dsi->cn_DomainIdentity), CN_DomainIdentity_ps_domain);
dsi->cn_Type.present = CN_DomainSysInfo__cn_Type_PR_gsm_MAP;
// RAC is a 2 byte OCTET_STRING: first byte is RAC, second byte is:
// 0 => NMO I, 1 => NMO II, top 7 bits in that byte unused.
// 23.060 6.5.2:
// "A GPRS-attached MS makes an IMSI attach via the SGSN with the combined RA / LA update
// procedure if the network operates in mode I. If the network operates in mode II,
// or if the MS is not GPRS-attached, the MS makes a normal IMSI attach.
// An IMSI-attached MS engaged in a CS connection shall use the (non-combined)
// GPRS Attach procedure when it performs a GPRS attach."
// Pat says: These NMO are different than GPRS.
// We will try to use NMO I, combined attach.
// The SGSN supports NMO I, without security, and without actually doing anything
// with the CS connection imsi-attach, which currently has no meaning for UMTS anyway.
// This also hopefully allows us to bypass UMTS security.
// Update: no it did not.
int nmo = gConfig.getNum("GPRS.NMO"); // config value is 1 based
uint8_t *RAC = (uint8_t*)calloc(2,sizeof(char));
RAC[0] = gConfig.getNum("GPRS.RAC");
RAC[1] = RN_BOUND((nmo-1),0,1);
dsi->cn_Type.choice.gsm_MAP.buf = RAC; // It is an OCTET_STRING_T
dsi->cn_Type.choice.gsm_MAP.size = 2;
dsi->cn_DRX_CycleLengthCoeff = gConfig.getNum("UMTS.CN-DSI.CycleLengthCoeff"); // FIXME -- What does this mean?!
// add the element to the list
ASN_SEQUENCE_ADD(&mSIB1.cn_DomainSysInfoList.list,dsi);
#if PAT_TEST
if (1) {
// Advertise a CS domain also. Pat put this back in 10-23-2012
CN_DomainSysInfo *dsi2 = RN_CALLOC(CN_DomainSysInfo);
asn_long2INTEGER(&(dsi2->cn_DomainIdentity), CN_DomainIdentity_cs_domain);
dsi2->cn_Type.present = CN_DomainSysInfo__cn_Type_PR_gsm_MAP;
uint8_t *CS_domain_specific_info = (uint8_t*)calloc(2,sizeof(char));
// octet 0 is T3212 in deci-hours.
CS_domain_specific_info[0] = gConfig.getNum("UMTS.Timer.T3212");
// octet 1 is attach-detach allowed flag: 1 means "MSs shall apply IMSI attach and detach procedure".
CS_domain_specific_info[1] = 1;
dsi2->cn_Type.choice.gsm_MAP.buf = CS_domain_specific_info;
dsi2->cn_Type.choice.gsm_MAP.size = 2;
// DRX_CycleLengthCoeff: "A coefficient in the formula to count the paging occasions to be used by a specific UE (specified
// in 3GPP TS 25.304: "UE Procedures in Idle Mode and Procedures for Cell Reselection in Connected Mode".)
dsi2->cn_DRX_CycleLengthCoeff = gConfig.getNum("UMTS.CN-DSI.CycleLengthCoeff"); // FIXME -- What does this mean?!
ASN_SEQUENCE_ADD(&mSIB1.cn_DomainSysInfoList.list,dsi2);
}
#endif
// (pat) I tried taking this out but was not sure if it changed the blackberry SIB1 report or not.
// Everything else is optional, so ignore it.
UE_ConnTimersAndConstants *connTimers = RN_CALLOC(ASN::UE_ConnTimersAndConstants);
connTimers->t_301 = RN_CALLOC(ASN::T_301_t); asn_long2INTEGER(connTimers->t_301,ASN::T_301_ms2000);
connTimers->n_301 = RN_CALLOC(ASN::N_301_t); *(connTimers->n_301) = 2;
connTimers->t_302 = RN_CALLOC(ASN::T_302_t); asn_long2INTEGER(connTimers->t_302,ASN::T_302_ms4000);
connTimers->n_302 = RN_CALLOC(ASN::N_302_t); *(connTimers->n_302) = 3;
connTimers->t_304 = RN_CALLOC(ASN::T_304_t); asn_long2INTEGER(connTimers->t_304,ASN::T_304_ms2000);
connTimers->n_304 = RN_CALLOC(ASN::N_304_t); *(connTimers->n_304) = 2;
connTimers->t_305 = RN_CALLOC(ASN::T_305_t); asn_long2INTEGER(connTimers->t_305,ASN::T_305_m30);
connTimers->t_307 = RN_CALLOC(ASN::T_307_t); asn_long2INTEGER(connTimers->t_307,ASN::T_307_s30);
connTimers->t_308 = RN_CALLOC(ASN::T_308_t); asn_long2INTEGER(connTimers->t_308,ASN::T_308_ms320);
connTimers->t_309 = RN_CALLOC(ASN::T_309_t); *(connTimers->t_309) = 5;
connTimers->t_310 = RN_CALLOC(ASN::T_310_t); asn_long2INTEGER(connTimers->t_310,ASN::T_310_ms160);
connTimers->n_310 = RN_CALLOC(ASN::N_310_t); *(connTimers->n_310) = 4;
connTimers->t_311 = RN_CALLOC(ASN::T_311_t); asn_long2INTEGER(connTimers->t_311,ASN::T_311_ms2000);
connTimers->t_312 = RN_CALLOC(ASN::T_312_t); *(connTimers->t_312) = 1;
connTimers->n_312 = RN_CALLOC(ASN::N_312_t); asn_long2INTEGER(connTimers->n_312,ASN::N_312_s1);
connTimers->t_313 = RN_CALLOC(ASN::T_313_t); *(connTimers->t_313) = 3;
connTimers->n_313 = RN_CALLOC(ASN::N_313_t); asn_long2INTEGER(connTimers->n_313,ASN::N_313_s20);
connTimers->t_314 = RN_CALLOC(ASN::T_314_t); asn_long2INTEGER(connTimers->t_314,ASN::T_314_s0);
connTimers->t_315 = RN_CALLOC(ASN::T_315_t); asn_long2INTEGER(connTimers->t_315,ASN::T_315_s0);
connTimers->n_315 = RN_CALLOC(ASN::N_315_t); asn_long2INTEGER(connTimers->n_315,ASN::N_315_s1);
connTimers->t_316 = RN_CALLOC(ASN::T_316_t); asn_long2INTEGER(connTimers->t_316,ASN::T_316_s30);
connTimers->t_317 = RN_CALLOC(ASN::T_317_t); asn_long2INTEGER(connTimers->t_317,ASN::T_317_infinity1);
UE_IdleTimersAndConstants *idleTimers = RN_CALLOC(ASN::UE_IdleTimersAndConstants_t);
/* need to fill in idleTimers parameters? */
mSIB1.ue_ConnTimersAndConstants = connTimers;
mSIB1.ue_IdleTimersAndConstants = idleTimers;
asn_long2INTEGER(&idleTimers->t_300,T_300_ms2000);
idleTimers->n_300 = 5;
asn_long2INTEGER(&idleTimers->n_312,N_312_s1);
idleTimers->t_312 = 10;
// Type 2
// 3GPP 25.331 10.2.48.8.5
// ASN SysInfoType2
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_SysInfoType2,&mSIB2);
memset(&mSIB2,0,sizeof(mSIB2));
// ura_IdentityList
// URA is "UTRAN registration area".
// FIXME -- Where in the spec is that defined??
// (pat) See 25.331 8.1.1.6.2: I think this is only used if we put the UE in URA_PCH mode, which we dont.
// It looks like just another organizational aggregation of RNCs within a PLMN and I think we can ignore it.
URA_Identity_t *urai = (URA_Identity_t*)calloc(1,sizeof(*urai));
// urai is a BIT_STRING.
uint16_t *uraval = (uint16_t*)calloc(1,sizeof(*uraval));
*uraval = htons(gConfig.getNum("UMTS.Identity.URAI"));
setAsnBIT_STRING(urai,(uint8_t*)uraval,16);
ASN_SEQUENCE_ADD(&mSIB2.ura_IdentityList.list,urai);
// Type 3
// 3GPP 25.331 10.2.48.8.6
// ASN SysInfoType3
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_SysInfoType3,&mSIB3);
memset(&mSIB3,0,sizeof(mSIB3));
// sib4indicator, 0 if there's no SIB4.
mSIB3.sib4indicator = 0;
// cellIdentity, 10.3.2.2
// This field is implementation specific, up to 28 bits.
// We will implement it as a 16-bit value, but we have to encode all 28 bit.
// From 25.401: The Cell identifier (C-Id) is used to uniquely identify a cell within an RNS/BSS.
// [pat - RNS = one RNC + one or more Node-Bs]
// The Cell-Id together with the identifier of the controlling RNC/BSS (CRNC-Id) constitutes the UTRAN/GERAN
// Cell Identity (UC-Id) and is used to identify the cell uniquely within UTRAN/GERAN Iu mode.
// UC-Id or C-Id is used to identify a cell in UTRAN Iub and Iur interfaces or Iur-g interface: UC-Id = RNC-Id + C-Id.
// (pat) This last does not apply to us because we dont use the Iub/Iur interfaces.
uint32_t *cellID = RN_CALLOC(uint32_t);
// (pat) TODO: Is this right? network order is high byte first.
// Luckily, hardly matters.
*cellID = gConfig.getNum("UMTS.Identity.CI");
// UMTS protocol specifies that the cell ID is a 28 bit number, but it is casted into a 32 bit value. The 4 LSB bits are considered padding, so the "real" data must be shifted about this padding.
*cellID = *cellID << 4;
*cellID = htonl(*cellID);
// cellID is a 28-bit BIT_STRING
setAsnBIT_STRING(&mSIB3.cellIdentity,(uint8_t*)cellID,28);
// ASN CellSelectReselectInfoSIB_3_4 cellSelectReselectInfo, 10.3.2.3
// mappingInfo - optional - skip it
// cellSelectQualityMeasure
mSIB3.cellSelectReselectInfo.cellSelectQualityMeasure.present =
CellSelectReselectInfoSIB_3_4__cellSelectQualityMeasure_PR_cpich_Ec_N0;
mSIB3.cellSelectReselectInfo.cellSelectQualityMeasure.choice.cpich_Ec_N0.q_HYST_2_S = new long(1);
// modeSpecificInfo, skipping optional parts
//mSIB3.cellSelectReselectInfo.modeSpecificInfo.present=CellSelectReselectInfoSIB_3_4__modeSpecificInfo_PR_NOTHING;
mSIB3.cellSelectReselectInfo.modeSpecificInfo.present=CellSelectReselectInfoSIB_3_4__modeSpecificInfo_PR_fdd;
mSIB3.cellSelectReselectInfo.modeSpecificInfo.choice.fdd.q_QualMin=-24; //gConfig.getNum("UMTS.CellSelect.QualMin", -12);
mSIB3.cellSelectReselectInfo.modeSpecificInfo.choice.fdd.q_RxlevMin=-58; //gConfig.getNum("UMTS.CellSelect.Q-RxlevMin",-20);
mSIB3.cellSelectReselectInfo.modeSpecificInfo.choice.fdd.s_Intrasearch = new long(-16);
mSIB3.cellSelectReselectInfo.modeSpecificInfo.choice.fdd.s_Intersearch = new long(8); //long(0);
// q_Hyst_l_S
mSIB3.cellSelectReselectInfo.q_Hyst_l_S = 1; //gConfig.getNum("UMTS.CellSelect.Q-Hyst1s",6);
// t_Reselection_S
mSIB3.cellSelectReselectInfo.t_Reselection_S = 5; //gConfig.getNum("UMTS.CellSelect.T-Reselection-S",6);
// hcs_ServingCellInformation - optional - skip it
// maxAllowedUL_TX_Power
mSIB3.cellSelectReselectInfo.maxAllowedUL_TX_Power = gConfig.getNum("UMTS.CellSelect.MaxAlloweddUL-TX-Power");
// cellAccessRestriction
mSIB3.cellAccessRestriction.cellBarred.present = CellBarred_PR_notBarred;
asn_long2INTEGER(&mSIB3.cellAccessRestriction.cellReservedForOperatorUse,ReservedIndicator_notReserved);
asn_long2INTEGER(&mSIB3.cellAccessRestriction.cellReservationExtension,ReservedIndicator_notReserved);
mSIB3.cellAccessRestriction.accessClassBarredList = RN_CALLOC(ASN::AccessClassBarredList);
for (int q=0; q< 16; q++) {
AccessClassBarred_t *acb = RN_CALLOC(ASN::AccessClassBarred_t);
asn_long2INTEGER(acb,ASN::AccessClassBarred_notBarred);
ASN_SEQUENCE_ADD(&mSIB3.cellAccessRestriction.accessClassBarredList->list,acb);
}
// Type 4
// 3GPP 25.331 10.2.48.8.7
// We're skipping this one, using Type 3 to fill its defaults.
// Type 5
// 3GPP 25.331 10.2.48.8.8
//ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_SysInfoType5,&mSIB5);
memset(&mSIB5,0,sizeof(mSIB5));
mSIB5.sib6indicator = 0;
mSIB5.pich_PowerOffset = gConfig.getNum("UMTS.PICH.PICH-PowerOffset");
// modeSpecificInfo
mSIB5.modeSpecificInfo.present = SysInfoType5__modeSpecificInfo_PR_fdd;
mSIB5.modeSpecificInfo.choice.fdd.aich_PowerOffset = gConfig.getNum("UMTS.AICH.AICH-PowerOffset");
// (pat) The only thing primaryCCPH_Info has in it for FDD is a boolean Tx diversity flag.
// primaryCCPCH_Info - optional - skip (pat) Lets try putting it in.
#if PAT_TEST
mSIB5.primaryCCPCH_Info = RN_CALLOC(PrimaryCCPCH_Info);
mSIB5.primaryCCPCH_Info->present = ASN::PrimaryCCPCH_Info_PR_fdd;
mSIB5.primaryCCPCH_Info->choice.fdd.tx_DiversityIndicator = 0;
#endif
mSIB5.primaryCCPCH_Info = RN_CALLOC(ASN::PrimaryCCPCH_Info);
mSIB5.primaryCCPCH_Info->present = PrimaryCCPCH_Info_PR_fdd;
mSIB5.primaryCCPCH_Info->choice.fdd.tx_DiversityIndicator = false;
{ // start of 10.3.6.55 prach_SystemInformationList, with one entry
PRACH_SystemInformation *prach_SI = RN_CALLOC(PRACH_SystemInformation);
// 10.3.6.52 PRACH-RACH-Info
prach_SI->prach_RACH_Info.modeSpecificInfo.present = PRACH_RACH_Info__modeSpecificInfo_PR_fdd;
uint16_t * PRACHSigs = RN_CALLOC(uint16_t);
//*PRACHSigs = htons(0x08000 >> gConfig.getNum("UMTS.PRACH.Signature"));
// (pat) tried: *PRACHSigs = htons(0xffff);
*PRACHSigs = htons(0x0001 << gConfig.getNum("UMTS.PRACH.Signature"));
setAsnBIT_STRING(&prach_SI->prach_RACH_Info.modeSpecificInfo.choice.fdd.availableSignatures,(uint8_t*)PRACHSigs,16);
// spreading factor
unsigned rachSF = gConfig.getNum("UMTS.PRACH.SF");
switch (rachSF) {
case 256:
asn_long2INTEGER(&(prach_SI->prach_RACH_Info.modeSpecificInfo.choice.fdd.availableSF),SF_PRACH_sfpr256);
break;
case 128:
asn_long2INTEGER(&(prach_SI->prach_RACH_Info.modeSpecificInfo.choice.fdd.availableSF),SF_PRACH_sfpr128);
break;
case 64:
asn_long2INTEGER(&(prach_SI->prach_RACH_Info.modeSpecificInfo.choice.fdd.availableSF),SF_PRACH_sfpr64);
break;
case 32:
asn_long2INTEGER(&(prach_SI->prach_RACH_Info.modeSpecificInfo.choice.fdd.availableSF),SF_PRACH_sfpr32);
break;
default:
break;
}
// scrambling code
prach_SI->prach_RACH_Info.modeSpecificInfo.choice.fdd.preambleScramblingCodeWordNumber = gConfig.getNum("UMTS.PRACH.ScramblingCode");
// (pat) 25.212 4.2.7.1.1 indicates that the SF for uplink is chosen based on the
// number of bits needed for the TF after mutilation by puncturing, so it looks
// like the PL Puncturing Limit indirectly selects the SF for the TF. What a mess.
// There is a hint in the Change History of the Layer 1 spec that indicates that
// the Punturing Limit was moved around in 2000.
// The Puncturing Limit from 10.3.6.52: PRACH info specifies PunturingLimit is
// Real(0.4..1.0 by step of 0.4) which gets ASN encoded as an enumeration
// called, are you ready? PuncturingLimit. I am setting it to a value of PL=1.00
// which means no puncturing, whose enumeration name is PunturingLimit_pl1 == 15
// Tried for testing, did not help samsung:
// asn_long2INTEGER(&(prach_SI->prach_RACH_Info.modeSpecificInfo.choice.fdd.puncturingLimit),PuncturingLimit_pl0_80);
asn_long2INTEGER(&(prach_SI->prach_RACH_Info.modeSpecificInfo.choice.fdd.puncturingLimit),PuncturingLimit_pl1);
// subchannel number
uint16_t * PRACHSubChan = RN_CALLOC(uint16_t);
*PRACHSubChan = htons(0x0010 << gConfig.getNum("UMTS.PRACH.Subchannel"));
// (pat) tried: *PRACHSubChan = htons(0xffff);
setAsnBIT_STRING(&prach_SI->prach_RACH_Info.modeSpecificInfo.choice.fdd.availableSubChannelNumbers,(uint8_t*)PRACHSubChan,12);
// transportChannelIdentity
// FIXME -- I don't understand the encoding of this one.
// (pat) Yes, the spec doesnt really explain what TrCh id is for.
// There can be multiple PRACH, each one serving some subset of UEs,
// so it would be possible to download a single Transport Format Set and then steer
// each PRACH onto a different Transport Format by specifying a different TrCh id.
// If they were going to allow voice channels on RACH, then they would need to specify
// three transport channels, not just one, so it makes no sense for that.
// Pat says: Whatever this is, it is not a config option - it is determined by the TFS setup.
// prach_SI->transportChannelIdentity = gConfig.getNum("UMTS.PRACH.TransportChannel",2);
#if PAT_TEST
// (pat) It is 1, not 3.
prach_SI->transportChannelIdentity = gRrcDcchConfig->getUlTrChInfo(0)->mTransportChannelIdentity; // Range is 1..32
assert(prach_SI->transportChannelIdentity == 1);
#else
prach_SI->transportChannelIdentity = 3;
#endif
// (pat) The RACH TFS and TFCS are MD, meaning they are only optional after the first one.
// Note: the description and picture of the MAC-s/ch/m imply there is no TFCS on RACH, but there is.
// The 10.3.5.23 TFS for RACH differs from a normal TFS only in the rlcsize encoding. Geesh.
// Note that the RACH includes an "ASC" code that replaces logical channel.
// (pat) First RACH TFS+TFCS is mandatory.
// If there are multiple PRACH channels, subsequent ones are optional: all use first TFS.
gRrcCcchConfig->getUlTfs()->toAsnTfs((prach_SI->rach_TransportFormatSet = RN_CALLOC(ASN::TransportFormatSet)));
gRrcCcchConfig->getUlTfcs()->toAsnTfcs((prach_SI->rach_TFCS = RN_CALLOC(ASN::TFCS)),TrChRACHType);
// 10.3.6.53 prach_Partitioning - optional (pat) It defaults to all ASC are available, which is what we want.
// (pat) If you take out prach_partitioning, the Samsung does not RACH, or if it does, something is wrong.
prach_SI->prach_Partitioning = RN_CALLOC(ASN::PRACH_Partitioning);
prach_SI->prach_Partitioning->present = PRACH_Partitioning_PR_fdd;
// 10.3.6.6 ASC Setting
AccessServiceClass_FDD_t *asc = RN_CALLOC(ASN::AccessServiceClass_FDD_t);
// We are only using one signature
asc->availableSignatureStartIndex = 0; //gConfig.getNum("UMTS.PRACH.Signature");
asc->availableSignatureEndIndex = 0; //gConfig.getNum("UMTS.PRACH.Signature");
uint8_t *assignedSubChan = RN_CALLOC(uint8_t);
// (pat) This is a very weird bit mask defined in 25.331 8.6.6.29.
// The 4 bits are duplicated in the mask to cover the 12 sub-channels.
*assignedSubChan = 0x0f << 4;
setAsnBIT_STRING(&asc->assignedSubChannelNumber,assignedSubChan,4);
ASCSetting_FDD_t *ptt = RN_CALLOC(ASN::ASCSetting_FDD_t);
ptt->accessServiceClass_FDD = asc;
ASN_SEQUENCE_ADD(&prach_SI->prach_Partitioning->choice.fdd.list,ptt);
// persistenceScalingFactorList - optional
// (pat) According to of 10.3.6.55 ac_to_ASC mapping is not optional,
// but it is not very interesting.
// Mapping described in 8.5.13, and more in some other document, and if you
// find it put a reference here. They can be used to prioritize, ie,
// emergency services.
// I dont think we need any values other than 0.
// But TODO: Figure out how the other values work.
// Update: The rrc.asn1 specifies that if you supply these, then you
// must supply a sequence of 7 values, which specifically
// contradicts RRC sec 10.3.6.53, that says that they default after the first one.
// AC_To_ASC_Mapping is list of AC_To_ASC_Mapping.
prach_SI->ac_To_ASC_MappingTable = RN_CALLOC(ASN::AC_To_ASC_MappingTable);
for (unsigned i = 0; i < 7; i++) {
long *ac = newlong(0); //i; // Must be in the range 0..7
ASN_SEQUENCE_ADD(&prach_SI->ac_To_ASC_MappingTable->list,ac);
}
// mode specific information - all of its elements are optional but we have to pick a type
// Not convinced this is optional...adding AICH parameters was required to make phone work.
prach_SI->modeSpecificInfo.present = PRACH_SystemInformation__modeSpecificInfo_PR_fdd;
prach_SI->modeSpecificInfo.choice.fdd.primaryCPICH_TX_Power = RN_CALLOC(ASN::PrimaryCPICH_TX_Power_t);
*prach_SI->modeSpecificInfo.choice.fdd.primaryCPICH_TX_Power = 10; //dBm
prach_SI->modeSpecificInfo.choice.fdd.constantValue = RN_CALLOC(ASN::ConstantValue_t);
*prach_SI->modeSpecificInfo.choice.fdd.constantValue = -10;
prach_SI->modeSpecificInfo.choice.fdd.prach_PowerOffset = RN_CALLOC(ASN::PRACH_PowerOffset);
prach_SI->modeSpecificInfo.choice.fdd.prach_PowerOffset->powerRampStep = 1;
prach_SI->modeSpecificInfo.choice.fdd.prach_PowerOffset->preambleRetransMax = 64;
prach_SI->modeSpecificInfo.choice.fdd.rach_TransmissionParameters = RN_CALLOC(ASN::RACH_TransmissionParameters);
prach_SI->modeSpecificInfo.choice.fdd.rach_TransmissionParameters->mmax = 32;
prach_SI->modeSpecificInfo.choice.fdd.rach_TransmissionParameters->nb01Min = 0;
prach_SI->modeSpecificInfo.choice.fdd.rach_TransmissionParameters->nb01Max = 50;
prach_SI->modeSpecificInfo.choice.fdd.aich_Info = RN_CALLOC(ASN::AICH_Info);
// AICH Info 10.3.6.2
#if PAT_TEST
prach_SI->modeSpecificInfo.choice.fdd.aich_Info->channelisationCode256 = cAICHSpreadingCodeIndex;
// (pat) This ch does not need to be reserved here for the uplink channel - chReserve is for downlink
// channels only; the uplink channels use a completely different underlying differentiation
// mechanism, namely scrambling codes, not spreading codes.
// Harvind probably put this to fix a bug, but the bug was that channel 2 was not being
// reserved in the FACH setup code below.
#else
gChannelTree.chReserve(256,2); // (harvind) This channel may not be used for DCH.
prach_SI->modeSpecificInfo.choice.fdd.aich_Info->channelisationCode256 = 2;
#endif
prach_SI->modeSpecificInfo.choice.fdd.aich_Info->sttd_Indicator = false;
// NOTE: we want AICH timing to be e1 (5 slots) to give us a little more time to respond
if (cAICHRACHOffset == 5) {
asn_long2INTEGER(&(prach_SI->modeSpecificInfo.choice.fdd.aich_Info->aich_TransmissionTiming),AICH_TransmissionTiming_e1);
} else {
assert(0); // Only value 5 is supported.
}
// insert the PRACH_SystemInformation into the list.
ASN_SEQUENCE_ADD(&mSIB5.prach_SystemInformationList.list,prach_SI);
//asn_fprint(stdout,&ASN::asn_DEF_PRACH_SystemInformation, prach_SI);
} // end of 10.3.6.55 prach_SystemInformationList
// (pat) This is the SCCPCH [FACH] channel code. TODO: Why a lower case 's'?
// (pat) Clean this up a little. Harvind is allocating three downlink channels for PICH and two FACH.
// (pat) channels 0,sf=256 and 1,sf=256 are reserved so channels ch=0,sf=64 is also reserved.
unsigned fachChCode = gConfig.getNum("UMTS.SCCPCH.SpreadingCode");
unsigned pichChCode = fachChCode + 2;
{ // start of sCCPCH_SystemInformationList
#if 1 //PAT_TEST
unsigned pchChCode = fachChCode + 1;
// 25.331 10.3.6.72 note says that the first one is PCH if PCH exists. Only PCH has a PICH.
SCCPCH_SystemInformation *sCCPCH_SI = generateSCCPCH(pchChCode,true,pichChCode);
unsigned scc_sf = getConfigSccpchSF(); // (pat) Not currently programmable.
gChannelTree.chReserve(scc_sf,pchChCode); // (pat) This channel may not be used for DCH.
// (pat) This code may be redundant with a reservation to create the FEC, but cant be too careful.
// TODO: The 256 should be scc_sf.
gChannelTree.chReserve(256,pichChCode); // (pat) This channel may not be used for DCH.
// FIXME: Try taking out pch...
// Doesnt seem to matter if this is here or not for either Samsung or Blackberry.
ASN_SEQUENCE_ADD(&mSIB5.sCCPCH_SystemInformationList.list,sCCPCH_SI);
SCCPCH_SystemInformation *sCCPCH_SI2 = generateSCCPCH(fachChCode,false,0);
// TODO: The 256 should be scc_sf.
gChannelTree.chReserve(scc_sf,fachChCode); // (pat) This channel may not be used for DCH.
ASN_SEQUENCE_ADD(&mSIB5.sCCPCH_SystemInformationList.list,sCCPCH_SI2);
#else
// (pat) See 10.3.6.72: Secondary CCPCH Info IE.
SCCPCH_SystemInformation *sCCPCH_SI = RN_CALLOC(ASN::SCCPCH_SystemInformation);
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.present = SecondaryCCPCH_Info__modeSpecificInfo_PR_fdd;
asn_long2INTEGER(&(sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.dummy1),PCPICH_UsageForChannelEst_mayBeUsed);
// FIXME -- Figure out what STTD is and be sure we don't use it.
// (pat) See 10.3.6.86: STTD is one of the TX Diversity modes.
// SCCPCH Secondary Common Control Physical Channel is the one carrying FACH and PCH.
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.sttd_Indicator = false;
unsigned scc_sf = getConfigSccpchSF(); // (pat) Not currently programmable.
switch (scc_sf) {
case 256:
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.sf_AndCodeNumber.present = SF256_AndCodeNumber_PR_sf256;
break;
case 128:
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.sf_AndCodeNumber.present = SF256_AndCodeNumber_PR_sf128; //256;
break;
case 64:
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.sf_AndCodeNumber.present = SF256_AndCodeNumber_PR_sf64; //256;
break;
case 32:
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.sf_AndCodeNumber.present = SF256_AndCodeNumber_PR_sf32; //256;
break;
case 16:
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.sf_AndCodeNumber.present = SF256_AndCodeNumber_PR_sf16; //256;
break;
case 8:
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.sf_AndCodeNumber.present = SF256_AndCodeNumber_PR_sf8; //256;
break;
case 4:
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.sf_AndCodeNumber.present = SF256_AndCodeNumber_PR_sf4; //256;
break;
default:
break;
}
// We are assigning to choice.sf256 but it is the same variable location for all SFs.
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.sf_AndCodeNumber.choice.sf256 = fachChCode+1;
// (pat) We must reserve this spot in the ChannelTree.
// This code is redundant with the one that creates the channel in FACHFEC(),
// but cant be too careful.
// (pat) If scc_sf is not 256, then the other FACH/PICH channels are going to collide with this in the
// tree of spreading codes and need to be changed.
// (pat) This is wrong - should be fachChCode+1 as above.
gChannelTree.chReserve(scc_sf,fachChCode); // (pat) This channel may not be used for DCH.
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.pilotSymbolExistence = false;
// (pat) No tfci implies "blind" transport format selection.
// It can be used if you are not multiplexing channels so you can use the number of bits
// to imply the transport format selected.
sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.tfci_Existence = true;
asn_long2INTEGER(&(sCCPCH_SI->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.positionFixedOrFlexible),PositionFixedOrFlexible_fixed);
// (pat) First FACH TFS+TFCS is mandatory.
// I believe the subsequent ones are optional and will use the same one if not specified.
FACH_PCH_Information *fachPchInfo = RN_CALLOC(ASN::FACH_PCH_Information);
#if PAT_TEST
// (pat) It should be 1, not 3.
fachPchInfo->transportChannelIdentity = gRrcDcchConfig->getDlTrChInfo(0)->mTransportChannelIdentity; // Range is 1..32
assert(fachPchInfo->transportChannelIdentity == 1);
#else
fachPchInfo->transportChannelIdentity = 1+1;
#endif
// We are leaving CTCH indicator false.
// PICH_info is optional - needed only if PCH is multiplexed.
gRrcCcchConfig->getDlTfs()->toAsnTfs(&fachPchInfo->transportFormatSet,true);
gRrcCcchConfig->getDlTfcs()->toAsnTfcs((sCCPCH_SI->tfcs = RN_CALLOC(ASN::TFCS)),TrChFACHType);
sCCPCH_SI->fach_PCH_InformationList = RN_CALLOC(ASN::FACH_PCH_InformationList);
ASN_SEQUENCE_ADD(&sCCPCH_SI->fach_PCH_InformationList->list,fachPchInfo);
// FIXME: Adding second FACH to SIB5, though it doesn't really exist. Phone assumes first FACH is PCH and won't go into the RACH procedure
#if 0 // unused code
/*FACH_PCH_Information *fachPchInfo2 = RN_CALLOC(ASN::FACH_PCH_Information);
memcpy(fachPchInfo2,fachPchInfo,sizeof(ASN::FACH_PCH_Information));
fachPchInfo2->transportChannelIdentity = 2;
ASN_SEQUENCE_ADD(&sCCPCH_SI->fach_PCH_InformationList->list,fachPchInfo2);*/
/*FACH_PCH_Information *fachPchInfo3 = RN_CALLOC(ASN::FACH_PCH_Information);
memcpy(fachPchInfo3,fachPchInfo,sizeof(ASN::FACH_PCH_Information));
fachPchInfo3->transportChannelIdentity = 3;
ASN_SEQUENCE_ADD(&sCCPCH_SI->fach_PCH_InformationList->list,fachPchInfo3);*/
#endif
PICH_Info_t *pichInfo = RN_CALLOC(ASN::PICH_Info);
pichInfo->present = PICH_Info_PR_fdd;
pichInfo->choice.fdd.channelisationCode256 = pichChCode;
// (pat) This code may be redundant with a reservation to create the FEC, but cant be too careful.
// TODO: The 256 should be scc_sf.
gChannelTree.chReserve(256,pichChCode); // (pat) This channel may not be used for DCH.
asn_long2INTEGER(&(pichInfo->choice.fdd.pi_CountPerFrame),PI_CountPerFrame_e18);
pichInfo->choice.fdd.sttd_Indicator = false;
sCCPCH_SI->pich_Info = pichInfo;
ASN_SEQUENCE_ADD(&mSIB5.sCCPCH_SystemInformationList.list,sCCPCH_SI);
SCCPCH_SystemInformation *sCCPCH_SI2 = RN_CALLOC(ASN::SCCPCH_SystemInformation);
memcpy(sCCPCH_SI2,sCCPCH_SI,sizeof(ASN::SCCPCH_SystemInformation));
sCCPCH_SI2->secondaryCCPCH_Info.modeSpecificInfo.choice.fdd.sf_AndCodeNumber.choice.sf256 = fachChCode;
gChannelTree.chReserve(scc_sf,fachChCode);
//sCCPCH_SI2->tfcs = RN_CALLOC(ASN::TFCS);
//memcpy(sCCPCH_SI2->tfcs,sCCPCH_SI->tfcs,sizeof(ASN::TFCS));
sCCPCH_SI2->pich_Info = NULL;
FACH_PCH_Information *fachPchInfo2 = RN_CALLOC(ASN::FACH_PCH_Information);
gRrcCcchConfig->getDlTfs()->toAsnTfs(&fachPchInfo2->transportFormatSet,true);
gRrcCcchConfig->getDlTfcs()->toAsnTfcs((sCCPCH_SI2->tfcs = RN_CALLOC(ASN::TFCS)),TrChFACHType);
//memcpy(fachPchInfo2,fachPchInfo,sizeof(ASN::FACH_PCH_Information));
// (pat) We already set the transportChannelIdentity above, and it is the same.
// These are different channels. They all use the transport channel id in the TFS. Same TFS is used for all.
fachPchInfo2->transportChannelIdentity = 1;
sCCPCH_SI2->fach_PCH_InformationList = RN_CALLOC(ASN::FACH_PCH_InformationList);
ASN_SEQUENCE_ADD(&sCCPCH_SI2->fach_PCH_InformationList->list,fachPchInfo2);
ASN_SEQUENCE_ADD(&mSIB5.sCCPCH_SystemInformationList.list,sCCPCH_SI2);
#endif
} // end of sCCPCH_SystemInformationList
// (pat) This print has been superceded by asn2String dumping all the SIBs to the log at end of function below.
if (gConfig.getNum("UMTS.Debug.SIB")) {
printf("Dumping SIB5...\n");
asn_fprint(stdout,&ASN::asn_DEF_SysInfoType5, &mSIB5); // Dump it all.
}
// cbs_DRX_Level1Information - optional - skip
// Type 6
// Optional, so skip it.
// Type 7
// 3GPP 25.331 10.2.48.8.10
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_SysInfoType7,&mSIB7);
memset(&mSIB7,0,sizeof(mSIB7));
mSIB7.modeSpecificInfo.present = SysInfoType7__modeSpecificInfo_PR_fdd;
mSIB7.modeSpecificInfo.choice.fdd.ul_Interference = gNodeB.getULInterference();
// SIB5 dynamic persistence level list
//DynamicPersistenceLevel_t *dpl = (DynamicPersistenceLevel_t*)calloc(1,sizeof(*dpl));
//*dpl = gConfig.getNum("UMTS.PRACH.DynamicPersistenceLevel"); // TODO UMTS -- what does this mean?
DynamicPersistenceLevel_t *dpl = newlong(gConfig.getNum("UMTS.PRACH.DynamicPersistenceLevel"));
ASN_SEQUENCE_ADD(&mSIB7.prach_Information_SIB5_List.list,dpl);
mSIB7.expirationTimeFactor = newlong(1);
// Type 8-10 are obsolete.
// Type 11
// 3GPP 25.331 10.2.48.8.14
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_SysInfoType11,&mSIB11);
memset(&mSIB11,0,sizeof(mSIB11));
mSIB11.sib12indicator = false;
mSIB11.fach_MeasurementOccasionInfo = NULL;
//mSIB11.fach_MeasurementControlSysInfo = NULL;//RN_CALLOC(ASN::FACH_MeasurementOccasionInfo);
mSIB11.measurementControlSysInfo.use_of_HCS.present = MeasurementControlSysInfo__use_of_HCS_PR_hcs_not_used;
mSIB11.measurementControlSysInfo.use_of_HCS.choice.hcs_not_used.cellSelectQualityMeasure.present = MeasurementControlSysInfo__use_of_HCS__hcs_not_used__cellSelectQualityMeasure_PR_cpich_Ec_N0;
// Type 12
// optional, skip it
// Type 13
// not applicable in GSM-MAP UTRAN
// Type 14
// TDD only, skip it
// Type 15
// 3GPP 25.331 10.2.48.8.18
#if 0
Comment this out until we are further along.
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_SysInfoType15,&mSIB15);
memset(&mSIB15,0,sizeof(mSIB15));
float refLat = gConfig.getFloat("GSM.RRLP.SEED.LATITUDE");
EllipsoidPointAltitudeEllipsoide__latitudeSign latSign;
if (refLat<0.0F) latSign = EllipsoidPointAltitudeEllipsoide__latitudeSign_south;
else latSign = EllipsoidPointAltitudeEllipsoide__latitudeSign_south;
mSIB15.ue_positioning_GPS_ReferenceLocation.ellipsoidPointAltitudeEllipsoide.latitudeSign = latSign;
long latVal = (long)(0.5F + 8388608.0 * (fabs(refLat)/90.0F));
mSIB15.ue_positioning_GPS_ReferenceLocation.ellipsoidPointAltitudeEllipsoide.latitude = latVal;
float refLong = gConfig.getFloat("GSM.RRLP.SEED.LONGITUDE");
long longVal = (long)(0.5F + 8388608.0 * (fabs(refLat)/180.0F));
// There are lots of uncertainty fields here that we are defaulting to 0.
mSIB15.ue_positioning_GPS_ReferenceLocation.ellipsoidPointAltitudeEllipsoide.confidence = 50;
#endif
#if 0
Comment this out until we are further along.
// Type 16
// 3GPP 25.331 10.2.48.8.19
// If we don't do handover yet, do we need this?
// (pat) If you look at 8.1.1.6.16, looks like these are used to setup pre-defined
// RAB/RB/TrCh configurations, which are optional.
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_SysInfoType16,&mSIB16);
memset(&mSIB16,0,sizeof(mSIB16));
// preDefinedRadioConfiguration
mSIB16.preDefinedRadioConfiguration.ul_DPCH_InfoPredef.present = UL_DPCH_PowerControlInfoPredef_PR_fdd;
mSIB16.preDefinedRadioConfiguration.ul_DPCH_InfoPredef.choice.fdd.powerControlAlgorithm.present = PowerControlAlgorithm_PR_algorithm2;
#endif
// Type 17
// TDD only, skip
// Type 18
// All parts are optional, so do we need it?
LOG(INFO) << asn2string(&ASN::asn_DEF_MasterInformationBlock, &mMIB);
LOG(INFO) << asn2string(&ASN::asn_DEF_SysInfoType1, &mSIB1);
LOG(INFO) << asn2string(&ASN::asn_DEF_SysInfoType2, &mSIB2);
LOG(INFO) << asn2string(&ASN::asn_DEF_SysInfoType3, &mSIB3);
LOG(INFO) << asn2string(&ASN::asn_DEF_SysInfoType5, &mSIB5);
LOG(INFO) << asn2string(&ASN::asn_DEF_SysInfoType7, &mSIB7);
LOG(INFO) << asn2string(&ASN::asn_DEF_SysInfoType11, &mSIB11);
cout << asn2string(&ASN::asn_DEF_SysInfoType11, &mSIB11);
//LOG(INFO) << asn2string(&ASN::asn_DEF_SysInfoType12, &mSIB12);
// Phase1 encoding - just turns them into a single buffer apiece.
encodeSIBPhase1(0, "MIB", &asn_DEF_MasterInformationBlock,&mMIB);
encodeSIBPhase1(1, "SIB1", &asn_DEF_SysInfoType1,(void*)&mSIB1);
encodeSIBPhase1(2, "SIB2", &asn_DEF_SysInfoType2,(void*)&mSIB2);
encodeSIBPhase1(3, "SIB3", &asn_DEF_SysInfoType3,(void*)&mSIB3);
encodeSIBPhase1(4, "SIB5", &asn_DEF_SysInfoType5,(void*)&mSIB5);
encodeSIBPhase1(5, "SIB7", &asn_DEF_SysInfoType7,(void*)&mSIB7);
encodeSIBPhase1(6, "SIB11",&asn_DEF_SysInfoType11,(void*)&mSIB11);
//encodeSIBPhase1(7, "SIB12",&asn_DEF_SysInfoType12,(void*)&mSIB12);
// We are done with the SIB structs; we could free them now.
rn_asn_debug = gConfig.getNum("UMTS.Debug.ASN");
}
// Unfortunately the System Information messages in the beacon
// include the SFN, so we must re-encode them, at least the phase2 part, for each beacon.
void BeaconConfig::encodePhase2(unsigned sfn)
{
// Re-run the phase2 encoding for the beacon at the start of every beacon cycle,
// to bring the SFN up-to-date in the System Information messages.
// We are doing it this way instead of testing SFN % mSibRepeat == 0 because
// we may start in the middle of a cycle.
// back up to the start of the beacon cycle:
sfn = (sfn / msSibRepeat) * msSibRepeat;
if (sfn == sPrevBeaconStart) { return; } // Already encoded this beacon cycle.
// BeaconLock makes sure we dont do this at the same time as regenerateBeacon
// Note: Do not lock the UMTSConfig here or you will create a deadlock race condition.
ScopedLock lock(mBeaconLock);
sPrevBeaconStart = sfn;
// Debug test: clear out the scheduling from the TransportBlocks.
for (unsigned j = 0; j < sizeof(mSibSched)/sizeof(TransportBlock*); j++) {
mSibSched[j]->mScheduled = false;
}
for (unsigned i=0; i<mNumSibTypes; i++) {
SibInfo_t *plan = &mSibInfo[i];
// Now rerun the phase2 encoder to generate transport blocks
// for each location in the beacon where this SIB goes.
for (unsigned pos = plan->mSibPos; pos < msSibRepeat; pos += plan->mSibRep) {
//LOG(INFO) << "i: " << i << " sfn: " << sfn << " pos: " << pos;
encodeSIBPhase2(plan,sfn+pos);
}
}
for (unsigned j = 0; j < sizeof(mSibSched)/sizeof(TransportBlock*); j++) {
assert(mSibSched[j]->scheduled());
}
}
template <class ChanType> ChanType* getChan(vector<ChanType*>& chanList)
{
#if CS_SERVICES_ENABLED
// (pat) I am removing this until we need CS channels.
// For PS channels, see: ChannelTree.chChooseBySF()
const unsigned sz = chanList.size();
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;
}
#endif
return NULL;
}
// Pat removed. For UMTS, DCCH is not in a pool. The DCCH is SRB3 of a UEInfo.
//DCCHLogicalChannel *UMTSConfig::getDCCH()
//{
// ScopedLock lock(mLock);
// DCCHLogicalChannel *chan = getChan<DCCHLogicalChannel>(mDCCHPool);
// if (chan) chan->open();
// return chan;
//}
//DTCHLogicalChannel *UMTSConfig::getDTCH()
//{
// ScopedLock lock(mLock);
// DTCHLogicalChannel *chan = getChan<DTCHLogicalChannel>(mDTCHPool);
// if (chan) chan->open();
// return chan;
//}
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]->recyclable()) count++;
}
return count;
}
//size_t UMTSConfig::DCCHAvailable() const
//{
// ScopedLock lock(mLock);
// return chanAvailable<DCCHLogicalChannel>(mDCCHPool);
//}
// 9-2012 (pat) TODO: This needs lots more work.
// First, the DCH available for voice calls have to plucked
// from the channel tree at a particular SF, probably 256.
// Second, we dont currently maintain gActiveDCH.
// No one currently calls open()/close() for any DCH.
// We need to keep a list of DCH that have been used for voice calls,
// and keep them somewhere until they can be recycled.
size_t UMTSConfig::DTCHAvailable() const // size_t?
{
return 1; // for now punt, but tell the caller to try to allocate.
// ScopedLock lock(mLock);
// return chanAvailable<DTCHLogicalChannel>(mDTCHPool);
}
template <class ChanType> unsigned countActive(const vector<ChanType*>& 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]->recyclable()) active++;
}
return active;
}
//unsigned UMTSConfig::DCCHActive() const
//{
// return countActive(mDCCHPool);
//}
unsigned UMTSConfig::DTCHActive() const
{
return countActive(mDTCHPool);
}
void UMTSConfig::hold(bool val)
{
ScopedLock lock(mLock); // currently irrelevant
mHold = val;
}
bool UMTSConfig::hold() const
{
ScopedLock lock(mLock); // currently irrelevant
return mHold;
}
const TransportBlock* UMTSConfig::getTxSIB(unsigned SFN)
{
// Note: This may take some time...
sBeacon.encodePhase2(SFN);
//LOG(INFO) << "SFN: " << SFN << ", length: " << *(sBeacon.getSITB(SFN));
return sBeacon.getSITB(SFN);
}
// vim: ts=4 sw=4