added files from openbts for tch/f decoding and removed openbts

This commit is contained in:
Piotr Krysik 2009-06-27 13:14:30 +02:00
parent 81c29dbb87
commit f1df46a5c0
20 changed files with 4485 additions and 0 deletions

View File

@ -0,0 +1,173 @@
#
# Copyright 2008 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
David A. Burgess, dburgess@kestrelsp.com:
CommonLibs/Assert.h
CommonLibs/BitVector.cpp
CommonLibs/BitVectorTest.cpp
CommonLibs/Interthread.h
CommonLibs/InterthreadTest.cpp
CommonLibs/LinkedLists.cpp
CommonLibs/LinkedLists.h
CommonLibs/Sockets.cpp
CommonLibs/Sockets.h
CommonLibs/SocketsTest.cpp
CommonLibs/Threads.cpp
CommonLibs/Threads.h
CommonLibs/Timeval.cpp
CommonLibs/Timeval.h
CommonLibs/TimevalTest.cpp
CommonLibs/Vector.h
CommonLibs/VectorTest.cpp
Control/CallControl.cpp
Control/ControlCommon.cpp
Control/ControlCommon.h
Control/FACCHDispatch.cpp
Control/MobilityManagement.cpp
Control/PagerTest.cpp
Control/RadioResource.cpp
Control/SDCCHDispatch.cpp
GSM/GSM610Tables.cpp
GSM/GSM610Tables.h
GSM/GSMCommon.cpp
GSM/GSMCommon.h
GSM/GSMConfig.h
GSM/GSML1FEC.cpp
GSM/GSML1FEC.h
GSM/GSML2LAPDm.cpp
GSM/GSML2LAPDm.h
GSM/GSML3CCElements.cpp
GSM/GSML3CCElements.h
GSM/GSML3CCMessages.cpp
GSM/GSML3CCMessages.h
GSM/GSML3CommonElements.cpp
GSM/GSML3CommonElements.h
GSM/GSML3MMElements.cpp
GSM/GSML3MMElements.h
GSM/GSML3MMMessages.cpp
GSM/GSML3MMMessages.h
GSM/GSML3Message.cpp
GSM/GSML3Message.h
GSM/GSML3RRElements.cpp
GSM/GSML3RRElements.h
GSM/GSML3RRMessages.cpp
GSM/GSML3RRMessages.h
GSM/GSMLogicalChannel.h
GSM/GSMTDMA.cpp
GSM/GSMTDMA.h
GSM/GSMTransfer.cpp
GSM/GSMTransfer.h
LICENSEBLOCK
SIP/SIPEngine.h
SIP/SIPInterface.h
TRXManager/TRXManager.cpp
Transceiver/Complex.h
apps/OpenBTS900.cpp
tests/AGCHTest.cpp
tests/BeaconTest.cpp
tests/CallTest.cpp
tests/CallTest2.cpp
tests/LAPDmTest.cpp
tests/LoopbackTest.cpp
tests/RegistrationTest.cpp
tests/TRXSimulator.cpp
Harvind S. Samra, hssamra@kestrelsp.com:
Control/PagerTest.cpp
Control/RadioResource.cpp
GSM/GSMConfig.h
GSM/GSMTransfer.h
LICENSEBLOCK
Transceiver/ComplexTest.cpp
Transceiver/Transceiver.cpp
Transceiver/Transceiver.h
Transceiver/USRPDevice.cpp
Transceiver/USRPDevice.h
Transceiver/USRPping.cpp
Transceiver/radioInterface.cpp
Transceiver/radioInterface.h
Transceiver/rcvLPF_651.h
Transceiver/runTransceiver.cpp
Transceiver/sendLPF_961.h
Transceiver/sigProcLib.cpp
Transceiver/sigProcLib.h
Transceiver/sigProcLibTest.cpp
Transceiver/sweepGenerator.cpp
Transceiver/testRadio.cpp
Raffi Sevlian, raffisev@gmail.com:
Control/CallControl.cpp
Control/ControlCommon.cpp
Control/ControlCommon.h
Control/FACCHDispatch.cpp
Control/MobilityManagement.cpp
Control/PagerTest.cpp
Control/RadioResource.cpp
GSM/GSMCommon.h
GSM/GSMConfig.h
GSM/GSML1FEC.h
GSM/GSML3CCElements.cpp
GSM/GSML3CCElements.h
GSM/GSML3CCMessages.cpp
GSM/GSML3CCMessages.h
GSM/GSML3CommonElements.cpp
GSM/GSML3CommonElements.h
GSM/GSML3MMElements.cpp
GSM/GSML3MMElements.h
GSM/GSML3MMMessages.cpp
GSM/GSML3MMMessages.h
GSM/GSML3Message.cpp
GSM/GSML3Message.h
GSM/GSML3RRElements.cpp
GSM/GSML3RRElements.h
GSM/GSML3RRMessages.cpp
GSM/GSML3RRMessages.h
GSM/GSMLogicalChannel.h
GSM/GSMSAPMux.cpp
GSM/GSMSAPMux.h
GSM/GSMTransfer.h
LICENSEBLOCK
SIP/SIPEngine.cpp
SIP/SIPInterface.cpp
SIP/SIPInterface.h
SIP/SIPMessage.cpp
SIP/SIPMessage.h
SIP/SIPUtility.cpp
SIP/SIPUtility.h
SMS/CMMessage.cpp
SMS/CMMessage.h
SMS/CMProcessor.cpp
SMS/CMProcessor.h
SMS/CMTest.cpp
SMS/RLMessage.cpp
SMS/RLMessage.h
SMS/RLProcessor.cpp
SMS/RLProcessor.h
SMS/SMSMessages.cpp
SMS/SMSMessages.h
SMS/SMSProcessors.cpp
SMS/SMSProcessors.h
SMS/SMSTransfer.cpp
SMS/SMSTransfer.h
SMS/TLMessage.cpp
SMS/TLMessage.h
SMS/TLProcessor.cpp
SMS/TLProcessor.h
TRXManager/TRXManager.h

View File

@ -0,0 +1,49 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Public License.
* See the COPYING file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ASSERT_H
#define ASSERT_H
#include "stdio.h"
/** This is thrown by assert() so that gdb can catch it. */
class Assertion {
public:
Assertion()
{
fprintf(stderr,"Try setting a breakpoint @ %s:%u.\n",__FILE__,__LINE__);
return;
}
};
#ifdef NDEBUG
#define assert(EXPR) {};
#else
/** This replaces the regular assert() with a C++ exception. */
#include "stdio.h"
#define assert(E) { if (!(E)) { fprintf(stderr,"%s:%u failed assertion '%s'\n",__FILE__,__LINE__,#E); throw Assertion(); } }
#endif
#endif

View File

@ -0,0 +1,513 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Public License.
* See the COPYING file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "BitVector.h"
#include <iostream>
using namespace std;
/**
Apply a Galois polymonial to a binary seqeunce.
@param val The input sequence.
@param poly The polynomial.
@param order The order of the polynomial.
@return Single-bit result.
*/
unsigned applyPoly(uint64_t val, uint64_t poly, unsigned order)
{
uint64_t prod = val & poly;
unsigned sum = prod;
for (unsigned i=1; i<order; i++) sum ^= prod>>i;
return sum & 0x01;
}
BitVector::BitVector(const char *valString)
:Vector<char>(strlen(valString))
{
uint32_t accum = 0;
for (size_t i=0; i<size(); i++) {
accum <<= 1;
if (valString[i]=='1') accum |= 0x01;
mStart[i] = accum;
}
}
uint64_t BitVector::peekField(size_t readIndex, unsigned length) const
{
uint64_t accum = 0;
char *dp = mStart + readIndex;
assert(dp+length <= mEnd);
for (unsigned i=0; i<length; i++) {
accum = (accum<<1) | ((*dp++) & 0x01);
}
return accum;
}
uint64_t BitVector::readField(size_t& readIndex, unsigned length) const
{
const uint64_t retVal = peekField(readIndex,length);
readIndex += length;
return retVal;
}
void BitVector::fillField(size_t writeIndex, uint64_t value, unsigned length)
{
char *dpBase = mStart + writeIndex;
char *dp = dpBase + length - 1;
assert(dp < mEnd);
while (dp>=dpBase) {
*dp-- = value & 0x01;
value >>= 1;
}
}
void BitVector::writeField(size_t& writeIndex, uint64_t value, unsigned length)
{
fillField(writeIndex,value,length);
writeIndex += length;
}
void BitVector::invert()
{
for (size_t i=0; i<size(); i++) {
mStart[i] = ~mStart[i];
}
}
void BitVector::reverse8()
{
assert(size()>=8);
char tmp0 = mStart[0];
mStart[0] = mStart[7];
mStart[7] = tmp0;
char tmp1 = mStart[1];
mStart[1] = mStart[6];
mStart[6] = tmp1;
char tmp2 = mStart[2];
mStart[2] = mStart[5];
mStart[5] = tmp2;
char tmp3 = mStart[3];
mStart[3] = mStart[4];
mStart[4] = tmp3;
}
void BitVector::LSB8MSB()
{
size_t size8 = 8*(size()/8);
size_t iTop = size8 - 8;
for (size_t i=0; i<=iTop; i+=8) segment(i,8).reverse8();
}
uint64_t BitVector::syndrome(Generator& gen) const
{
gen.clear();
const char *dp = mStart;
while (dp<mEnd) gen.syndromeShift(*dp++);
return gen.state();
}
uint64_t BitVector::parity(Generator& gen) const
{
gen.clear();
const char *dp = mStart;
while (dp<mEnd) gen.encoderShift(*dp++);
return gen.state();
}
void BitVector::encode(const ViterbiR2O4& coder, BitVector& target)
{
size_t sz = size();
assert(sz*coder.iRate() == target.size());
// Build a "history" array where each element contains the full history.
uint32_t history[sz];
uint32_t accum = 0;
for (size_t i=0; i<sz; i++) {
accum = (accum<<1) | bit(i);
history[i] = accum;
}
// Look up histories in the pre-generated state table.
char *op = target.begin();
for (size_t i=0; i<sz; i++) {
unsigned index = coder.cMask() & history[i];
for (unsigned g=0; g<coder.iRate(); g++) {
*op++ = coder.stateTable(g,index);
}
}
}
unsigned BitVector::sum() const
{
unsigned sum = 0;
for (size_t i=0; i<size(); i++) sum += mStart[i] & 0x01;
return sum;
}
void BitVector::map(const unsigned *map, size_t mapSize, BitVector& dest) const
{
for (unsigned i=0; i<mapSize; i++) {
dest.mStart[i] = mStart[map[i]];
}
}
void BitVector::unmap(const unsigned *map, size_t mapSize, BitVector& dest) const
{
for (unsigned i=0; i<mapSize; i++) {
dest.mStart[map[i]] = mStart[i];
}
}
ostream& operator<<(ostream& os, const BitVector& hv)
{
for (size_t i=0; i<hv.size(); i++) {
if (hv.bit(i)) os << '1';
else os << '0';
}
return os;
}
ViterbiR2O4::ViterbiR2O4()
{
assert(mDeferral < 32);
mCoeffs[0] = 0x019;
mCoeffs[1] = 0x01b;
computeStateTables(0);
computeStateTables(1);
computeGeneratorTable();
}
void ViterbiR2O4::initializeStates()
{
for (unsigned i=0; i<mIStates; i++) clear(mSurvivors[i]);
for (unsigned i=0; i<mNumCands; i++) clear(mCandidates[i]);
}
void ViterbiR2O4::computeStateTables(unsigned g)
{
assert(g<mIRate);
for (unsigned state=0; state<mIStates; state++) {
// 0 input
uint32_t inputVal = state<<1;
mStateTable[g][inputVal] = applyPoly(inputVal, mCoeffs[g], mOrder+1);
// 1 input
inputVal |= 1;
mStateTable[g][inputVal] = applyPoly(inputVal, mCoeffs[g], mOrder+1);
}
}
void ViterbiR2O4::computeGeneratorTable()
{
for (unsigned index=0; index<mIStates*2; index++) {
mGeneratorTable[index] = (mStateTable[0][index]<<1) | mStateTable[1][index];
}
}
void ViterbiR2O4::branchCandidates()
{
// Branch to generate new input states.
const vCand *sp = mSurvivors;
for (unsigned i=0; i<mNumCands; i+=2) {
// extend and suffix
const uint32_t iState0 = (sp->iState) << 1; // input state for 0
const uint32_t iState1 = iState0 | 0x01; // input state for 1
const uint32_t oStateShifted = (sp->oState) << mIRate; // shifted output
const float cost = sp->cost;
sp++;
// 0 input extension
mCandidates[i].cost = cost;
mCandidates[i].oState = oStateShifted | mGeneratorTable[iState0 & mCMask];
mCandidates[i].iState = iState0;
// 1 input extension
mCandidates[i+1].cost = cost;
mCandidates[i+1].oState = oStateShifted | mGeneratorTable[iState1 & mCMask];
mCandidates[i+1].iState = iState1;
}
}
void ViterbiR2O4::getSoftCostMetrics(const uint32_t inSample, const float *matchCost, const float *mismatchCost)
{
const float *cTab[2] = {matchCost,mismatchCost};
for (unsigned i=0; i<mNumCands; i++) {
vCand& thisCand = mCandidates[i];
// We examine input bits 2 at a time for a rate 1/2 coder.
const unsigned mismatched = inSample ^ (thisCand.oState);
thisCand.cost += cTab[mismatched&0x01][1] + cTab[(mismatched>>1)&0x01][0];
}
}
void ViterbiR2O4::pruneCandidates()
{
const vCand* c1 = mCandidates; // 0-prefix
const vCand* c2 = mCandidates + mIStates; // 1-prefix
for (unsigned i=0; i<mIStates; i++) {
if (c1[i].cost < c2[i].cost) mSurvivors[i] = c1[i];
else mSurvivors[i] = c2[i];
}
}
const ViterbiR2O4::vCand& ViterbiR2O4::minCost() const
{
int minIndex = 0;
float minCost = mSurvivors[0].cost;
for (unsigned i=1; i<mIStates; i++) {
const float thisCost = mSurvivors[i].cost;
if (thisCost>=minCost) continue;
minCost = thisCost;
minIndex=i;
}
return mSurvivors[minIndex];
}
const ViterbiR2O4::vCand& ViterbiR2O4::step(uint32_t inSample, const float *probs, const float *iprobs)
{
branchCandidates();
getSoftCostMetrics(inSample,probs,iprobs);
pruneCandidates();
return minCost();
}
uint64_t Parity::syndrome(const BitVector& receivedCodeword)
{
return receivedCodeword.syndrome(*this);
}
void Parity::writeParityWord(const BitVector& data, BitVector& parityTarget, bool invert)
{
uint64_t pWord = data.parity(*this);
if (invert) pWord = ~pWord;
parityTarget.fillField(0,pWord,size());
}
SoftVector::SoftVector(const BitVector& source)
{
resize(source.size());
for (size_t i=0; i<size(); i++) {
if (source.bit(i)) mStart[i]=1.0F;
else mStart[i]=0.0F;
}
}
BitVector SoftVector::sliced() const
{
size_t sz = size();
BitVector newSig(sz);
for (size_t i=0; i<sz; i++) {
if (mStart[i]>0.5F) newSig[i]=1;
else newSig[i] = 0;
}
return newSig;
}
void SoftVector::decode(ViterbiR2O4 &decoder, BitVector& target) const
{
const size_t sz = size();
const unsigned deferral = decoder.deferral();
const size_t ctsz = sz + deferral;
assert(sz <= decoder.iRate()*target.size());
// Build a "history" array where each element contains the full history.
uint32_t history[ctsz];
{
BitVector bits = sliced();
uint32_t accum = 0;
for (size_t i=0; i<sz; i++) {
accum = (accum<<1) | bits.bit(i);
history[i] = accum;
}
// Repeat last bit at the end.
for (size_t i=sz; i<ctsz; i++) {
accum = (accum<<1) | (accum & 0x01);
history[i] = accum;
}
}
// Precompute metric tables.
float matchCostTable[ctsz];
float mismatchCostTable[ctsz];
{
const float *dp = mStart;
for (size_t i=0; i<sz; i++) {
// pVal is the probability that a bit is correct.
// ipVal is the probability that a bit is correct.
float pVal = dp[i];
if (pVal>0.5F) pVal = 1.0F-pVal;
float ipVal = 1.0F-pVal;
// This is a cheap approximation to an ideal cost function.
if (pVal<0.01F) pVal = 0.01;
if (ipVal<0.01F) ipVal = 0.01;
matchCostTable[i] = 0.25F/ipVal;
mismatchCostTable[i] = 0.25F/pVal;
}
// pad end of table with unknowns
for (size_t i=sz; i<ctsz; i++) {
matchCostTable[i] = 0.5F;
mismatchCostTable[i] = 0.5F;
}
}
{
decoder.initializeStates();
// Each sample of history[] carries its history.
// So we only have to process every iRate-th sample.
const unsigned step = decoder.iRate();
// input pointer
const uint32_t *ip = history + step - 1;
// output pointers
char *op = target.begin();
const char *const opt = target.end();
// table pointers
const float* match = matchCostTable;
const float* mismatch = mismatchCostTable;
size_t oCount = 0;
while (op<opt) {
// Viterbi algorithm
const ViterbiR2O4::vCand &minCost = decoder.step(*ip, match, mismatch);
ip += step;
match += step;
mismatch += step;
// output
if (oCount>=deferral) *op++ = (minCost.iState >> deferral);
oCount++;
}
}
}
ostream& operator<<(ostream& os, const SoftVector& sv)
{
for (size_t i=0; i<sv.size(); i++) {
if (sv[i]<0.25) os << "0";
else if (sv[i]>0.75) os << "1";
else os << "-";
}
return os;
}
void BitVector::pack(unsigned char* targ) const
{
// Assumes MSB-first packing.
unsigned bytes = size()/8;
for (unsigned i=0; i<bytes; i++) {
targ[i] = peekField(i*8,8);
}
unsigned whole = bytes*8;
unsigned rem = size() - whole;
if (rem==0) return;
targ[bytes] = peekField(whole,rem) << (8-rem);
}
void BitVector::unpack(const unsigned char* src)
{
// Assumes MSB-first packing.
unsigned bytes = size()/8;
for (unsigned i=0; i<bytes; i++) {
fillField(i*8,src[i],8);
}
unsigned whole = bytes*8;
unsigned rem = size() - whole;
if (rem==0) return;
fillField(whole,src[bytes],rem);
}
// vim: ts=4 sw=4

View File

@ -0,0 +1,427 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Public License.
* See the COPYING file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FECVECTORS_H
#define FECVECTORS_H
#include "Vector.h"
#include <stdint.h>
class BitVector;
class SoftVector;
/** Shift-register (LFSR) generator. */
class Generator {
private:
uint64_t mCoeff; ///< polynomial coefficients. LSB is zero exponent.
uint64_t mState; ///< shift register state. LSB is most recent.
uint64_t mMask; ///< mask for reading state
unsigned mLen; ///< number of bits used in shift register
unsigned mLen_1; ///< mLen - 1
public:
Generator(uint64_t wCoeff, unsigned wLen)
:mCoeff(wCoeff),mState(0),
mMask((1ULL<<wLen)-1),
mLen(wLen),mLen_1(wLen-1)
{ assert(wLen<64); }
void clear() { mState=0; }
/**@name Accessors */
//@{
uint64_t state() const { return mState & mMask; }
unsigned size() const { return mLen; }
//@}
/**
Calculate one bit of a syndrome.
This is in the .h for inlining.
*/
void syndromeShift(unsigned inBit)
{
const unsigned fb = (mState>>(mLen_1)) & 0x01;
mState = (mState<<1) ^ (inBit & 0x01);
if (fb) mState ^= mCoeff;
}
/**
Update the generator state by one cycle.
This is in the .h for inlining.
*/
void encoderShift(unsigned inBit)
{
const unsigned fb = ((mState>>(mLen_1)) ^ inBit) & 0x01;
mState <<= 1;
if (fb) mState ^= mCoeff;
}
};
/** Parity (CRC-type) generator and checker based on a Generator. */
class Parity : public Generator {
protected:
unsigned mCodewordSize;
public:
Parity(uint64_t wCoefficients, unsigned wParitySize, unsigned wCodewordSize)
:Generator(wCoefficients, wParitySize),
mCodewordSize(wCodewordSize)
{ }
/** Compute the parity word and write it into the target segment. */
void writeParityWord(const BitVector& data, BitVector& parityWordTarget, bool invert=true);
/** Compute the syndrome of a received sequence. */
uint64_t syndrome(const BitVector& receivedCodeword);
};
/**
Class to represent convolutional coders/decoders of rate 1/2, memory length 4.
This is the "workhorse" coder for most GSM channels.
*/
class ViterbiR2O4 {
private:
/**name Lots of precomputed elements so the compiler can optimize like hell. */
//@{
/**@name Core values. */
//@{
static const unsigned mIRate = 2; ///< reciprocal of rate
static const unsigned mOrder = 4; ///< memory length of generators
//@}
/**@name Derived values. */
//@{
static const unsigned mIStates = 0x01 << mOrder; ///< number of states, number of survivors
static const uint32_t mSMask = mIStates-1; ///< survivor mask
static const uint32_t mCMask = (mSMask<<1) | 0x01; ///< candidate mask
static const uint32_t mOMask = (0x01<<mIRate)-1; ///< ouput mask, all iRate low bits set
static const unsigned mNumCands = mIStates*2; ///< number of candidates to generate during branching
static const unsigned mDeferral = 6*mOrder; ///< deferral to be used
//@}
//@}
/** Precomputed tables. */
//@{
uint32_t mCoeffs[mIRate]; ///< polynomial for each generator
uint32_t mStateTable[mIRate][2*mIStates]; ///< precomputed generator output tables
uint32_t mGeneratorTable[2*mIStates]; ///< precomputed coder output table
//@}
public:
/**
A candidate sequence in a Viterbi decoder.
The 32-bit state register can support a deferral of 6 with a 4th-order coder.
*/
typedef struct candStruct {
uint32_t iState; ///< encoder input associated with this candidate
uint32_t oState; ///< encoder output associated with this candidate
float cost; ///< cost (metric value), float to support soft inputs
} vCand;
/** Clear a structure. */
void clear(vCand& v)
{
v.iState=0;
v.oState=0;
v.cost=0;
}
private:
/**@name Survivors and candidates. */
//@{
vCand mSurvivors[mIStates]; ///< current survivor pool
vCand mCandidates[2*mIStates]; ///< current candidate pool
//@}
public:
unsigned iRate() const { return mIRate; }
uint32_t cMask() const { return mCMask; }
uint32_t stateTable(unsigned g, unsigned i) const { return mStateTable[g][i]; }
unsigned deferral() const { return mDeferral; }
ViterbiR2O4();
/** Set all cost metrics to zero. */
void initializeStates();
/**
Full cycle of the Viterbi algorithm: branch, metrics, prune, select.
@return reference to minimum-cost candidate.
*/
const vCand& step(uint32_t inSample, const float *probs, const float *iprobs);
private:
/** Branch survivors into new candidates. */
void branchCandidates();
/** Compute cost metrics for soft-inputs. */
void getSoftCostMetrics(uint32_t inSample, const float *probs, const float *iprobs);
/** Select survivors from the candidate set. */
void pruneCandidates();
/** Find the minimum cost survivor. */
const vCand& minCost() const;
/**
Precompute the state tables.
@param g Generator index 0..((1/rate)-1)
*/
void computeStateTables(unsigned g);
/**
Precompute the generator outputs.
mCoeffs must be defined first.
*/
void computeGeneratorTable();
};
class BitVector : public Vector<char> {
public:
/**@name Constructors. */
//@{
/**@name Casts of Vector constructors. */
//@{
BitVector(char* wData, char* wStart, char* wEnd)
:Vector<char>(wData,wStart,wEnd)
{ }
BitVector(size_t len=0):Vector<char>(len) {}
BitVector(const Vector<char>& source):Vector<char>(source) {}
BitVector(Vector<char>& source):Vector<char>(source) {}
BitVector(const Vector<char>& source1, const Vector<char> source2):Vector<char>(source1,source2) {}
//@}
/** Construct from a string of "0" and "1". */
BitVector(const char* valString);
//@}
/** Index a single bit. */
bool bit(size_t index) const
{
// We put this code in .h for fast inlining.
const char *dp = mStart+index;
assert(dp<mEnd);
return (*dp) & 0x01;
}
/**@name Casts and overrides of Vector operators. */
//@{
BitVector segment(size_t start, size_t span)
{
char* wStart = mStart + start;
char* wEnd = wStart + span;
assert(wEnd<=mEnd);
return BitVector(NULL,wStart,wEnd);
}
BitVector alias()
{ return segment(0,size()); }
const BitVector segment(size_t start, size_t span) const
{ return (BitVector)(Vector<char>::segment(start,span)); }
BitVector head(size_t span) { return segment(0,span); }
const BitVector head(size_t span) const { return segment(0,span); }
BitVector tail(size_t start) { return segment(start,size()-start); }
const BitVector tail(size_t start) const { return segment(start,size()-start); }
//@}
void zero() { fill(0); }
/**@name FEC operations. */
//@{
/** Calculate the syndrome of the vector with the given Generator. */
uint64_t syndrome(Generator& gen) const;
/** Calculate the parity word for the vector with the given Generator. */
uint64_t parity(Generator& gen) const;
/** Encode the signal with the GSM rate 1/2 convolutional encoder. */
void encode(const ViterbiR2O4& encoder, BitVector& target);
//@}
/** Invert 0<->1. */
void invert();
/**@name Byte-wise operations. */
//@{
/** Reverse an 8-bit vector. */
void reverse8();
/** Reverse groups of 8 within the vector (byte reversal). */
void LSB8MSB();
//@}
/**@name Serialization and deserialization. */
//@{
uint64_t peekField(size_t readIndex, unsigned length) const;
uint64_t readField(size_t& readIndex, unsigned length) const;
void fillField(size_t writeIndex, uint64_t value, unsigned length);
void writeField(size_t& writeIndex, uint64_t value, unsigned length);
//@}
/** Sum of bits. */
unsigned sum() const;
/** Reorder bits, dest[i] = this[map[i]]. */
void map(const unsigned *map, size_t mapSize, BitVector& dest) const;
/** Reorder bits, dest[map[i]] = this[i]. */
void unmap(const unsigned *map, size_t mapSize, BitVector& dest) const;
/** Pack into a char array. */
void pack(unsigned char*) const;
/** Unopack from a char array. */
void unpack(const unsigned char*);
};
std::ostream& operator<<(std::ostream&, const BitVector&);
/**
The SoftVector class is used to represent a soft-decision signal.
Values 0..1 represent probabilities that a bit is "true".
*/
class SoftVector: public Vector<float> {
public:
/** Build a SoftVector of a given length. */
SoftVector(size_t wSize=0):Vector<float>(wSize) {}
/** Construct a SoftVector from a C string of "0", "1", and "X". */
SoftVector(const char* valString);
/** Construct a SoftVector from a BitVector. */
SoftVector(const BitVector& source);
/**
Wrap a SoftVector around a block of floats.
The block will be delete[]ed upon desctuction.
*/
SoftVector(float *wData, unsigned length)
:Vector<float>(wData,length)
{}
SoftVector(float* wData, float* wStart, float* wEnd)
:Vector<float>(wData,wStart,wEnd)
{ }
/**
Casting from a Vector<float>.
Note that this is NOT pass-by-reference.
*/
SoftVector(Vector<float> source)
:Vector<float>(source)
{}
/**@name Casts and overrides of Vector operators. */
//@{
SoftVector segment(size_t start, size_t span)
{
float* wStart = mStart + start;
float* wEnd = wStart + span;
assert(wEnd<=mEnd);
return SoftVector(NULL,wStart,wEnd);
}
SoftVector alias()
{ return segment(0,size()); }
const SoftVector segment(size_t start, size_t span) const
{ return (SoftVector)(Vector<float>::segment(start,span)); }
SoftVector head(size_t span) { return segment(0,span); }
const SoftVector head(size_t span) const { return segment(0,span); }
SoftVector tail(size_t start) { return segment(start,size()-start); }
const SoftVector tail(size_t start) const { return segment(start,size()-start); }
//@}
/** Decode soft symbols with the GSM rate-1/2 Viterbi decoder. */
void decode(ViterbiR2O4 &decoder, BitVector& target) const;
/** Fill with "unknown" values. */
void unknown() { fill(0.5F); }
/** Return a hard bit value from a given index by slicing. */
bool bit(size_t index) const
{
const float *dp = mStart+index;
assert(dp<mEnd);
return (*dp)>0.5F;
}
/** Slice the whole signal into bits. */
BitVector sliced() const;
};
std::ostream& operator<<(std::ostream&, const SoftVector&);
#endif
// vim: ts=4 sw=4

View File

@ -0,0 +1,492 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Public License.
* See the COPYING file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "GSM610Tables.h"
/*
RFC 3551 RTP A/V Profile July 2003
Octet Bit 0 Bit 1 Bit 2 Bit 3 Bit 4 Bit 5 Bit 6 Bit 7
_____________________________________________________________________
0 1 1 0 1 LARc0.0 LARc0.1 LARc0.2 LARc0.3
1 LARc0.4 LARc0.5 LARc1.0 LARc1.1 LARc1.2 LARc1.3 LARc1.4 LARc1.5
2 LARc2.0 LARc2.1 LARc2.2 LARc2.3 LARc2.4 LARc3.0 LARc3.1 LARc3.2
3 LARc3.3 LARc3.4 LARc4.0 LARc4.1 LARc4.2 LARc4.3 LARc5.0 LARc5.1
4 LARc5.2 LARc5.3 LARc6.0 LARc6.1 LARc6.2 LARc7.0 LARc7.1 LARc7.2
5 Nc0.0 Nc0.1 Nc0.2 Nc0.3 Nc0.4 Nc0.5 Nc0.6 bc0.0
6 bc0.1 Mc0.0 Mc0.1 xmaxc00 xmaxc01 xmaxc02 xmaxc03 xmaxc04
7 xmaxc05 xmc0.0 xmc0.1 xmc0.2 xmc1.0 xmc1.1 xmc1.2 xmc2.0
8 xmc2.1 xmc2.2 xmc3.0 xmc3.1 xmc3.2 xmc4.0 xmc4.1 xmc4.2
9 xmc5.0 xmc5.1 xmc5.2 xmc6.0 xmc6.1 xmc6.2 xmc7.0 xmc7.1
10 xmc7.2 xmc8.0 xmc8.1 xmc8.2 xmc9.0 xmc9.1 xmc9.2 xmc10.0
11 xmc10.1 xmc10.2 xmc11.0 xmc11.1 xmc11.2 xmc12.0 xmc12.1 xcm12.2
12 Nc1.0 Nc1.1 Nc1.2 Nc1.3 Nc1.4 Nc1.5 Nc1.6 bc1.0
13 bc1.1 Mc1.0 Mc1.1 xmaxc10 xmaxc11 xmaxc12 xmaxc13 xmaxc14
14 xmax15 xmc13.0 xmc13.1 xmc13.2 xmc14.0 xmc14.1 xmc14.2 xmc15.0
15 xmc15.1 xmc15.2 xmc16.0 xmc16.1 xmc16.2 xmc17.0 xmc17.1 xmc17.2
16 xmc18.0 xmc18.1 xmc18.2 xmc19.0 xmc19.1 xmc19.2 xmc20.0 xmc20.1
17 xmc20.2 xmc21.0 xmc21.1 xmc21.2 xmc22.0 xmc22.1 xmc22.2 xmc23.0
18 xmc23.1 xmc23.2 xmc24.0 xmc24.1 xmc24.2 xmc25.0 xmc25.1 xmc25.2
19 Nc2.0 Nc2.1 Nc2.2 Nc2.3 Nc2.4 Nc2.5 Nc2.6 bc2.0
20 bc2.1 Mc2.0 Mc2.1 xmaxc20 xmaxc21 xmaxc22 xmaxc23 xmaxc24
21 xmaxc25 xmc26.0 xmc26.1 xmc26.2 xmc27.0 xmc27.1 xmc27.2 xmc28.0
22 xmc28.1 xmc28.2 xmc29.0 xmc29.1 xmc29.2 xmc30.0 xmc30.1 xmc30.2
23 xmc31.0 xmc31.1 xmc31.2 xmc32.0 xmc32.1 xmc32.2 xmc33.0 xmc33.1
24 xmc33.2 xmc34.0 xmc34.1 xmc34.2 xmc35.0 xmc35.1 xmc35.2 xmc36.0
25 Xmc36.1 xmc36.2 xmc37.0 xmc37.1 xmc37.2 xmc38.0 xmc38.1 xmc38.2
26 Nc3.0 Nc3.1 Nc3.2 Nc3.3 Nc3.4 Nc3.5 Nc3.6 bc3.0
27 bc3.1 Mc3.0 Mc3.1 xmaxc30 xmaxc31 xmaxc32 xmaxc33 xmaxc34
28 xmaxc35 xmc39.0 xmc39.1 xmc39.2 xmc40.0 xmc40.1 xmc40.2 xmc41.0
29 xmc41.1 xmc41.2 xmc42.0 xmc42.1 xmc42.2 xmc43.0 xmc43.1 xmc43.2
30 xmc44.0 xmc44.1 xmc44.2 xmc45.0 xmc45.1 xmc45.2 xmc46.0 xmc46.1
31 xmc46.2 xmc47.0 xmc47.1 xmc47.2 xmc48.0 xmc48.1 xmc48.2 xmc49.0
32 xmc49.1 xmc49.2 xmc50.0 xmc50.1 xmc50.2 xmc51.0 xmc51.1 xmc51.2
Table 3: GSM payload format
*/
/*
This file encodes a mapping between
GSM 05.03 Table 2 and RFC-3551 Table 3.
*/
/*
Naming convention:
xxx_p position (bit index)
xxx_l length (bit field length)
LAR log area ratio
N LTP lag
b LTP gain
M grid
Xmax block amplitude
x RPE pulses
*/
/**@name Lengths of GSM 06.10 fields */
//@{
const unsigned int LAR1_l=6; ///< log area ratio
const unsigned int LAR2_l=6; ///< log area ratio
const unsigned int LAR3_l=5; ///< log area ratio
const unsigned int LAR4_l=5; ///< log area ratio
const unsigned int LAR5_l=4; ///< log area ratio
const unsigned int LAR6_l=4; ///< log area ratio
const unsigned int LAR7_l=3; ///< log area ratio
const unsigned int LAR8_l=3; ///< log area ratio
const unsigned int N_l=7; ///< LTP lag
const unsigned int b_l=2; ///< LTP gain
const unsigned int M_l=2; ///< grid position
const unsigned int Xmax_l=6; ///< block amplitude
const unsigned int x_l=3; ///< RPE pulses
//@}
/*@name Indecies of GSM 06.10 fields as they appear in RFC-3551 Table 3. */
//@{
/**@name Log area ratios, apply to whole frame. */
//@{
const unsigned int LAR1_p = 0;
const unsigned int LAR2_p = LAR1_p + LAR1_l;
const unsigned int LAR3_p = LAR2_p + LAR2_l;
const unsigned int LAR4_p = LAR3_p + LAR3_l;
const unsigned int LAR5_p = LAR4_p + LAR4_l;
const unsigned int LAR6_p = LAR5_p + LAR5_l;
const unsigned int LAR7_p = LAR6_p + LAR6_l;
const unsigned int LAR8_p = LAR7_p + LAR7_l;
//@}
/**@name Subframe 1 */
//@{
const unsigned int N1_p = LAR8_p + LAR8_l;
const unsigned int b1_p = N1_p + N_l;
const unsigned int M1_p = b1_p + b_l;
const unsigned int Xmax1_p = M1_p + M_l;
const unsigned int x1_0_p = Xmax1_p + Xmax_l;
const unsigned int x1_1_p = x1_0_p + x_l;
const unsigned int x1_2_p = x1_1_p + x_l;
const unsigned int x1_3_p = x1_2_p + x_l;
const unsigned int x1_4_p = x1_3_p + x_l;
const unsigned int x1_5_p = x1_4_p + x_l;
const unsigned int x1_6_p = x1_5_p + x_l;
const unsigned int x1_7_p = x1_6_p + x_l;
const unsigned int x1_8_p = x1_7_p + x_l;
const unsigned int x1_9_p = x1_8_p + x_l;
const unsigned int x1_10_p = x1_9_p + x_l;
const unsigned int x1_11_p = x1_10_p + x_l;
const unsigned int x1_12_p = x1_11_p + x_l;
//@}
/**@name Subframe 2 */
//@{
const unsigned int N2_p = x1_12_p + x_l;
const unsigned int b2_p = N2_p + N_l;
const unsigned int M2_p = b2_p + b_l;
const unsigned int Xmax2_p = M2_p + M_l;
const unsigned int x2_0_p = Xmax2_p + Xmax_l;
const unsigned int x2_1_p = x2_0_p + x_l;
const unsigned int x2_2_p = x2_1_p + x_l;
const unsigned int x2_3_p = x2_2_p + x_l;
const unsigned int x2_4_p = x2_3_p + x_l;
const unsigned int x2_5_p = x2_4_p + x_l;
const unsigned int x2_6_p = x2_5_p + x_l;
const unsigned int x2_7_p = x2_6_p + x_l;
const unsigned int x2_8_p = x2_7_p + x_l;
const unsigned int x2_9_p = x2_8_p + x_l;
const unsigned int x2_10_p = x2_9_p + x_l;
const unsigned int x2_11_p = x2_10_p + x_l;
const unsigned int x2_12_p = x2_11_p + x_l;
//@}
/**@mame Subframe 3 */
//@{
const unsigned int N3_p = x2_12_p + x_l;
const unsigned int b3_p = N3_p + N_l;
const unsigned int M3_p = b3_p + b_l;
const unsigned int Xmax3_p = M3_p + M_l;
const unsigned int x3_0_p = Xmax3_p + Xmax_l;
const unsigned int x3_1_p = x3_0_p + x_l;
const unsigned int x3_2_p = x3_1_p + x_l;
const unsigned int x3_3_p = x3_2_p + x_l;
const unsigned int x3_4_p = x3_3_p + x_l;
const unsigned int x3_5_p = x3_4_p + x_l;
const unsigned int x3_6_p = x3_5_p + x_l;
const unsigned int x3_7_p = x3_6_p + x_l;
const unsigned int x3_8_p = x3_7_p + x_l;
const unsigned int x3_9_p = x3_8_p + x_l;
const unsigned int x3_10_p = x3_9_p + x_l;
const unsigned int x3_11_p = x3_10_p + x_l;
const unsigned int x3_12_p = x3_11_p + x_l;
//@}
/**@name Subframe 4 */
//@{
const unsigned int N4_p = x3_12_p + x_l;
const unsigned int b4_p = N4_p + N_l;
const unsigned int M4_p = b4_p + b_l;
const unsigned int Xmax4_p = M4_p + M_l;
const unsigned int x4_0_p = Xmax4_p + Xmax_l;
const unsigned int x4_1_p = x4_0_p + x_l;
const unsigned int x4_2_p = x4_1_p + x_l;
const unsigned int x4_3_p = x4_2_p + x_l;
const unsigned int x4_4_p = x4_3_p + x_l;
const unsigned int x4_5_p = x4_4_p + x_l;
const unsigned int x4_6_p = x4_5_p + x_l;
const unsigned int x4_7_p = x4_6_p + x_l;
const unsigned int x4_8_p = x4_7_p + x_l;
const unsigned int x4_9_p = x4_8_p + x_l;
const unsigned int x4_10_p = x4_9_p + x_l;
const unsigned int x4_11_p = x4_10_p + x_l;
const unsigned int x4_12_p = x4_11_p + x_l;
//@}
//@}
/*
This array encodes GSM 05.03 Table 2.
It's also GSM 06.10 Table A2.1a.
This is the order of bits as they appear in
the d[] bits of the GSM TCH/F.
RTP[4+g610BitOrder[i]] <=> GSM[i]
*/
unsigned int GSM::g610BitOrder[260] = {
/**@name importance class 1 */
//@{
/** LAR1:5 */ LAR1_p+LAR1_l-1-5, /* bit 0 */
/** Xmax1:5 */ Xmax1_p+Xmax_l-1-5,
/** Xmax2:5 */ Xmax2_p+Xmax_l-1-5,
/** Xmax3:5 */ Xmax3_p+Xmax_l-1-5,
/** Xmax4:5 */ Xmax4_p+Xmax_l-1-5,
//@}
/**@name importance class 2 */
//@{
/** LAR1:4 */ LAR1_p+LAR1_l-1-4,
/** LAR2:5 */ LAR2_p+LAR2_l-1-5,
/** LAR3:4 */ LAR3_p+LAR3_l-1-4,
//@}
/**@name importance class 3 */
//@{
/** LAR1:3 */ LAR1_p+LAR1_l-1-3,
/** LAR2:4 */ LAR2_p+LAR2_l-1-4,
/** LAR3:3 */ LAR3_p+LAR3_l-1-3, /* bit 10 */
/** LAR4:4 */ LAR4_p+LAR4_l-1-4,
/** N1:6 */ N1_p+N_l-1-6,
/** N2:6 */ N2_p+N_l-1-6,
/** N3:6 */ N3_p+N_l-1-6,
/** N4:6 */ N4_p+N_l-1-6,
/** Xmax1:4 */ Xmax1_p+Xmax_l-1-4,
/** Xmax2:4 */ Xmax2_p+Xmax_l-1-4,
/** Xmax3:4 */ Xmax3_p+Xmax_l-1-4,
/** Xmax4:4 */ Xmax4_p+Xmax_l-1-4,
/** LAR2:3 */ LAR2_p+LAR2_l-1-3, /* bit 20 */
/** LAR5:3 */ LAR5_p+LAR5_l-1-3,
/** LAR6:3 */ LAR6_p+LAR6_l-1-3,
/** N1:5 */ N1_p+N_l-1-5,
/** N2:5 */ N2_p+N_l-1-5,
/** N3:5 */ N3_p+N_l-1-5,
/** N4:5 */ N4_p+N_l-1-5,
/** N1:4 */ N1_p+N_l-1-4,
/** N2:4 */ N2_p+N_l-1-4,
/** N3:4 */ N3_p+N_l-1-4,
/** N4:4 */ N4_p+N_l-1-4, /* bit 30 */
/** N1:3 */ N1_p+N_l-1-3,
/** N2:3 */ N2_p+N_l-1-3,
/** N3:3 */ N3_p+N_l-1-3,
/** N4:3 */ N4_p+N_l-1-3,
/** N1:2 */ N1_p+N_l-1-2,
/** N2:2 */ N2_p+N_l-1-2,
/** N3:2 */ N3_p+N_l-1-2,
/** N4:2 */ N4_p+N_l-1-2,
//@}
/**@name importance class 4 */
//@{
/** Xmax1:3 */ Xmax1_p+Xmax_l-1-3,
/** Xmax2:3 */ Xmax2_p+Xmax_l-1-3, /* bit 40 */
/** Xmax3:3 */ Xmax3_p+Xmax_l-1-3,
/** Xmax4:3 */ Xmax4_p+Xmax_l-1-3,
/** LAR1:2 */ LAR1_p+LAR1_l-1-2,
/** LAR4:3 */ LAR4_p+LAR4_l-1-3,
/** LAR7:2 */ LAR7_p+LAR7_l-1-2,
/** N1:1 */ N1_p+N_l-1-1,
/** N2:1 */ N2_p+N_l-1-1,
/** N3:1 */ N3_p+N_l-1-1,
/** N4:1 */ N4_p+N_l-1-1,
/** LAR5:2 */ LAR5_p+LAR5_l-1-2, /* bit 50 */
/** LAR6:2 */ LAR6_p+LAR6_l-1-2,
/** b1:1 */ b1_p+b_l-1-1,
/** b2:1 */ b2_p+b_l-1-1,
/** b3:1 */ b3_p+b_l-1-1,
/** b4:1 */ b4_p+b_l-1-1,
/** N1:0 */ N1_p+N_l-1-0,
/** N2:0 */ N2_p+N_l-1-0,
/** N3:0 */ N3_p+N_l-1-0,
/** N4:0 */ N4_p+N_l-1-0,
/** M1:1 */ M1_p+M_l-1-1, /* bit 60 */
/** M2:1 */ M2_p+M_l-1-1,
/** M3:1 */ M3_p+M_l-1-1,
/** M4:1 */ M4_p+M_l-1-1,
//@}
/**@name importance class 5 */
//@{
/** LAR1:1 */ LAR1_p+LAR1_l-1-1,
/** LAR2:2 */ LAR2_p+LAR2_l-1-2,
/** LAR3:2 */ LAR3_p+LAR3_l-1-2,
/** LAR8:2 */ LAR8_p+LAR8_l-1-2,
/** LAR4:2 */ LAR4_p+LAR4_l-1-2,
/** LAR5:1 */ LAR5_p+LAR5_l-1-1,
/** LAR7:1 */ LAR7_p+LAR7_l-1-1, /* bit 70 */
/** b1:0 */ b1_p+b_l-1-0,
/** b2:0 */ b2_p+b_l-1-0,
/** b3:0 */ b3_p+b_l-1-0,
/** b4:0 */ b4_p+b_l-1-0,
/** Xmax1:2 */ Xmax1_p+Xmax_l-1-2,
/** Xmax2:2 */ Xmax2_p+Xmax_l-1-2,
/** Xmax3:2 */ Xmax3_p+Xmax_l-1-2,
/** Xmax4:2 */ Xmax4_p+Xmax_l-1-2,
/** x1_0:2 */ x1_0_p+x_l-1-2,
/** x1_1:2 */ x1_1_p+x_l-1-2, /* bit 80 */
/** x1_2:2 */ x1_2_p+x_l-1-2,
/** x1_3:2 */ x1_3_p+x_l-1-2,
/** x1_4:2 */ x1_4_p+x_l-1-2,
/** x1_5:2 */ x1_5_p+x_l-1-2,
/** x1_6:2 */ x1_6_p+x_l-1-2,
/** x1_7:2 */ x1_7_p+x_l-1-2,
/** x1_8:2 */ x1_8_p+x_l-1-2,
/** x1_9:2 */ x1_9_p+x_l-1-2,
/** x1_10:2 */ x1_10_p+x_l-1-2,
/** x1_11:2 */ x1_11_p+x_l-1-2, /* bit 90 */
/** x1_12:2 */ x1_12_p+x_l-1-2,
/** x2_0:2 */ x2_0_p+x_l-1-2,
/** x2_1:2 */ x2_1_p+x_l-1-2,
/** x2_2:2 */ x2_2_p+x_l-1-2,
/** x2_3:2 */ x2_3_p+x_l-1-2,
/** x2_4:2 */ x2_4_p+x_l-1-2,
/** x2_5:2 */ x2_5_p+x_l-1-2,
/** x2_6:2 */ x2_6_p+x_l-1-2,
/** x2_7:2 */ x2_7_p+x_l-1-2,
/** x2_8:2 */ x2_8_p+x_l-1-2, /* bit 100 */
/** x2_9:2 */ x2_9_p+x_l-1-2,
/** x2_10:2 */ x2_10_p+x_l-1-2,
/** x2_11:2 */ x2_11_p+x_l-1-2,
/** x2_12:2 */ x2_12_p+x_l-1-2,
/** x3_0:2 */ x3_0_p+x_l-1-2,
/** x3_1:2 */ x3_1_p+x_l-1-2,
/** x3_2:2 */ x3_2_p+x_l-1-2,
/** x3_3:2 */ x3_3_p+x_l-1-2,
/** x3_4:2 */ x3_4_p+x_l-1-2,
/** x3_5:2 */ x3_5_p+x_l-1-2, /* bit 110 */
/** x3_6:2 */ x3_6_p+x_l-1-2,
/** x3_7:2 */ x3_7_p+x_l-1-2,
/** x3_8:2 */ x3_8_p+x_l-1-2,
/** x3_9:2 */ x3_9_p+x_l-1-2,
/** x3_10:2 */ x3_10_p+x_l-1-2,
/** x3_11:2 */ x3_11_p+x_l-1-2,
/** x3_12:2 */ x3_12_p+x_l-1-2,
/** x4_0:2 */ x4_0_p+x_l-1-2,
/** x4_1:2 */ x4_1_p+x_l-1-2,
/** x4_2:2 */ x4_2_p+x_l-1-2, /* bit 120 */
/** x4_3:2 */ x4_3_p+x_l-1-2,
/** x4_4:2 */ x4_4_p+x_l-1-2,
/** x4_5:2 */ x4_5_p+x_l-1-2,
/** x4_6:2 */ x4_6_p+x_l-1-2,
/** x4_7:2 */ x4_7_p+x_l-1-2,
/** x4_8:2 */ x4_8_p+x_l-1-2,
/** x4_9:2 */ x4_9_p+x_l-1-2,
/** x4_10:2 */ x4_10_p+x_l-1-2,
/** x4_11:2 */ x4_11_p+x_l-1-2,
/** x4_12:2 */ x4_12_p+x_l-1-2, /* bit 130 */
/** M1:0 */ M1_p+M_l-1-0,
/** M2:0 */ M2_p+M_l-1-0,
/** M3:0 */ M3_p+M_l-1-0,
/** M4:0 */ M4_p+M_l-1-0,
/** Xmax1:1 */ Xmax1_p+Xmax_l-1-1,
/** Xmax2:1 */ Xmax2_p+Xmax_l-1-1,
/** Xmax3:1 */ Xmax3_p+Xmax_l-1-1,
/** Xmax4:1 */ Xmax4_p+Xmax_l-1-1,
/** x1_0:1 */ x1_0_p+x_l-1-1,
/** x1_1:1 */ x1_1_p+x_l-1-1, /* bit 140 */
/** x1_2:1 */ x1_2_p+x_l-1-1,
/** x1_3:1 */ x1_3_p+x_l-1-1,
/** x1_4:1 */ x1_4_p+x_l-1-1,
/** x1_5:1 */ x1_5_p+x_l-1-1,
/** x1_6:1 */ x1_6_p+x_l-1-1,
/** x1_7:1 */ x1_7_p+x_l-1-1,
/** x1_8:1 */ x1_8_p+x_l-1-1,
/** x1_9:1 */ x1_9_p+x_l-1-1,
/** x1_10:1 */ x1_10_p+x_l-1-1,
/** x1_11:1 */ x1_11_p+x_l-1-1, /* bit 150 */
/** x1_12:1 */ x1_12_p+x_l-1-1,
/** x2_0:1 */ x2_0_p+x_l-1-1,
/** x2_1:1 */ x2_1_p+x_l-1-1,
/** x2_2:1 */ x2_2_p+x_l-1-1,
/** x2_3:1 */ x2_3_p+x_l-1-1,
/** x2_4:1 */ x2_4_p+x_l-1-1,
/** x2_5:1 */ x2_5_p+x_l-1-1,
/** x2_6:1 */ x2_6_p+x_l-1-1,
/** x2_7:1 */ x2_7_p+x_l-1-1,
/** x2_8:1 */ x2_8_p+x_l-1-1, /* bit 160 */
/** x2_9:1 */ x2_9_p+x_l-1-1,
/** x2_10:1 */ x2_10_p+x_l-1-1,
/** x2_11:1 */ x2_11_p+x_l-1-1,
/** x2_12:1 */ x2_12_p+x_l-1-1,
/** x3_0:1 */ x3_0_p+x_l-1-1,
/** x3_1:1 */ x3_1_p+x_l-1-1,
/** x3_2:1 */ x3_2_p+x_l-1-1,
/** x3_3:1 */ x3_3_p+x_l-1-1,
/** x3_4:1 */ x3_4_p+x_l-1-1,
/** x3_5:1 */ x3_5_p+x_l-1-1, /* bit 170 */
/** x3_6:1 */ x3_6_p+x_l-1-1,
/** x3_7:1 */ x3_7_p+x_l-1-1,
/** x3_8:1 */ x3_8_p+x_l-1-1,
/** x3_9:1 */ x3_9_p+x_l-1-1,
/** x3_10:1 */ x3_10_p+x_l-1-1,
/** x3_11:1 */ x3_11_p+x_l-1-1,
/** x3_12:1 */ x3_12_p+x_l-1-1,
/** x4_0:1 */ x4_0_p+x_l-1-1,
/** x4_1:1 */ x4_1_p+x_l-1-1,
/** x4_2:1 */ x4_2_p+x_l-1-1, /* bit 180 */
/** x4_3:1 */ x4_3_p+x_l-1-1,
//@}
/**@name importance class 6 */
//@{
/** x4_4:1 */ x4_4_p+x_l-1-1,
/** x4_5:1 */ x4_5_p+x_l-1-1,
/** x4_6:1 */ x4_6_p+x_l-1-1,
/** x4_7:1 */ x4_7_p+x_l-1-1,
/** x4_8:1 */ x4_8_p+x_l-1-1,
/** x4_9:1 */ x4_9_p+x_l-1-1,
/** x4_10:1 */ x4_10_p+x_l-1-1,
/** x4_11:1 */ x4_11_p+x_l-1-1,
/** x4_12:1 */ x4_12_p+x_l-1-1, /* bit 190 */
/** LAR1:0 */ LAR1_p+LAR1_l-1-0,
/** LAR2:1 */ LAR2_p+LAR2_l-1-1,
/** LAR3:1 */ LAR3_p+LAR3_l-1-1,
/** LAR6:1 */ LAR6_p+LAR6_l-1-1,
/** LAR7:0 */ LAR7_p+LAR7_l-1-0,
/** LAR8:1 */ LAR8_p+LAR8_l-1-1,
/** LAR8:0 */ LAR8_p+LAR8_l-1-0,
/** LAR3:0 */ LAR3_p+LAR3_l-1-0,
/** LAR4:1 */ LAR4_p+LAR4_l-1-1,
/** LAR4:0 */ LAR4_p+LAR4_l-1-0,
/** LAR5:0 */ LAR5_p+LAR5_l-1-0,
/** Xmax1:0 */ Xmax1_p+Xmax_l-1-0,
/** Xmax2:0 */ Xmax2_p+Xmax_l-1-0,
/** Xmax3:0 */ Xmax3_p+Xmax_l-1-0,
/** Xmax4:0 */ Xmax4_p+Xmax_l-1-0,
/** x1_0:0 */ x1_0_p+x_l-1-0,
/** x1_1:0 */ x1_1_p+x_l-1-0,
/** x1_2:0 */ x1_2_p+x_l-1-0,
/** x1_3:0 */ x1_3_p+x_l-1-0,
/** x1_4:0 */ x1_4_p+x_l-1-0,
/** x1_5:0 */ x1_5_p+x_l-1-0,
/** x1_6:0 */ x1_6_p+x_l-1-0,
/** x1_7:0 */ x1_7_p+x_l-1-0,
/** x1_8:0 */ x1_8_p+x_l-1-0,
/** x1_9:0 */ x1_9_p+x_l-1-0,
/** x1_10:0 */ x1_10_p+x_l-1-0,
/** x1_11:0 */ x1_11_p+x_l-1-0,
/** x1_12:0 */ x1_12_p+x_l-1-0,
/** x2_0:0 */ x2_0_p+x_l-1-0,
/** x2_1:0 */ x2_1_p+x_l-1-0,
/** x2_2:0 */ x2_2_p+x_l-1-0,
/** x2_3:0 */ x2_3_p+x_l-1-0,
/** x2_4:0 */ x2_4_p+x_l-1-0,
/** x2_5:0 */ x2_5_p+x_l-1-0,
/** x2_6:0 */ x2_6_p+x_l-1-0,
/** x2_7:0 */ x2_7_p+x_l-1-0,
/** x2_8:0 */ x2_8_p+x_l-1-0,
/** x2_9:0 */ x2_9_p+x_l-1-0,
/** x2_10:0 */ x2_10_p+x_l-1-0,
/** x2_11:0 */ x2_11_p+x_l-1-0,
/** x2_12:0 */ x2_12_p+x_l-1-0,
/** x3_0:0 */ x3_0_p+x_l-1-0,
/** x3_1:0 */ x3_1_p+x_l-1-0,
/** x3_2:0 */ x3_2_p+x_l-1-0,
/** x3_3:0 */ x3_3_p+x_l-1-0,
/** x3_4:0 */ x3_4_p+x_l-1-0,
/** x3_5:0 */ x3_5_p+x_l-1-0,
/** x3_6:0 */ x3_6_p+x_l-1-0,
/** x3_7:0 */ x3_7_p+x_l-1-0,
/** x3_8:0 */ x3_8_p+x_l-1-0,
/** x3_9:0 */ x3_9_p+x_l-1-0,
/** x3_10:0 */ x3_10_p+x_l-1-0,
/** x3_11:0 */ x3_11_p+x_l-1-0,
/** x3_12:0 */ x3_12_p+x_l-1-0,
/** x4_0:0 */ x4_0_p+x_l-1-0,
/** x4_1:0 */ x4_1_p+x_l-1-0,
/** x4_2:0 */ x4_2_p+x_l-1-0,
/** x4_3:0 */ x4_3_p+x_l-1-0,
/** x4_4:0 */ x4_4_p+x_l-1-0,
/** x4_5:0 */ x4_5_p+x_l-1-0,
/** x4_6:0 */ x4_6_p+x_l-1-0,
/** x4_7:0 */ x4_7_p+x_l-1-0,
/** x4_8:0 */ x4_8_p+x_l-1-0,
/** x4_9:0 */ x4_9_p+x_l-1-0,
/** x4_10:0 */ x4_10_p+x_l-1-0,
/** x4_11:0 */ x4_11_p+x_l-1-0,
/** x4_12:0 */ x4_12_p+x_l-1-0,
/** LAR2:0 */ LAR2_p+LAR2_l-1-0,
/** LAR6:0 */ LAR6_p+LAR6_l-1-0
//@}
};

View File

@ -0,0 +1,37 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Public License.
* See the COPYING file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GSM610TABLES_H
#define GSM610TABLES_H
namespace GSM {
/** Table #2 from GSM 05.03 */
extern unsigned int g610BitOrder[260];
}
#endif

View File

@ -0,0 +1,315 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Public License.
* See the COPYING file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "GSMCommon.h"
using namespace GSM;
using namespace std;
ostream& GSM::operator<<(ostream& os, L3PD val)
{
switch (val) {
case L3CallControlPD: os << "Call Control"; break;
case L3MobilityManagementPD: os << "Mobility Management"; break;
case L3RadioResourcePD: os << "Radio Resource"; break;
default: os << hex << "0x" << (int)val << dec;
}
return os;
}
const BitVector GSM::gTrainingSequence[] = {
BitVector("00100101110000100010010111"),
BitVector("00101101110111100010110111"),
BitVector("01000011101110100100001110"),
BitVector("01000111101101000100011110"),
BitVector("00011010111001000001101011"),
BitVector("01001110101100000100111010"),
BitVector("10100111110110001010011111"),
BitVector("11101111000100101110111100"),
};
const BitVector GSM::gDummyBurst("0001111101101110110000010100100111000001001000100000001111100011100010111000101110001010111010010100011001100111001111010011111000100101111101010000");
const BitVector GSM::gRACHSynchSequence("01001011011111111001100110101010001111000");
char encodeGSMChar(char ascii)
{
// Given an ASCII char, return the corresponding GSM char.
static char reverseTable[256]={0};
static bool init = false;
if (!init) {
for (size_t i=0; i<sizeof(gGSMAlphabet); i++) {
reverseTable[(unsigned)gGSMAlphabet[i]]=i;
}
init=true;
}
return reverseTable[(unsigned)ascii];
}
char encodeBCDChar(char ascii)
{
// Given an ASCII char, return the corresponding BCD.
if ((ascii>='0') && (ascii<='9')) return ascii-'0';
switch (ascii) {
case '.': return 11;
case '*': return 11;
case '#': return 12;
case 'a': return 13;
case 'b': return 14;
case 'c': return 15;
default: return 15;
}
}
unsigned GSM::uplinkFreqKHz(GSMBand band, unsigned ARFCN)
{
switch (band) {
case GSM850:
assert((ARFCN<252)&&(ARFCN>129));
return 824200+200*(ARFCN-128);
case EGSM900:
if (ARFCN<=124) return 890000+200*ARFCN;
assert((ARFCN>974)&&(ARFCN<1024));
return 890000+200*(ARFCN-1024);
case DCS1800:
assert((ARFCN>511)&&(ARFCN<886));
return 1710200+200*(ARFCN-512);
case PCS1900:
assert((ARFCN>511)&&(ARFCN<811));
return 1850200+200*(ARFCN-512);
default:
abort();
}
}
unsigned GSM::downlinkFreqKHz(GSMBand band, unsigned ARFCN)
{
static unsigned uplinkOffset[] = {
45000, // 850
45000, // 900
95000, // 1800
80000 // 1900
};
return uplinkFreqKHz(band,ARFCN) + uplinkOffset[band];
}
int32_t GSM::FNDelta(int32_t v1, int32_t v2)
{
static const int64_t halfModulus = gHyperframe/2;
int32_t delta = v1-v2;
if (delta>halfModulus) delta -= gHyperframe;
else if (delta<-halfModulus) delta += gHyperframe;
return (int32_t) delta;
}
int GSM::FNCompare(int32_t v1, int32_t v2)
{
int32_t delta = FNDelta(v1,v2);
if (delta==0) return 0;
else if (delta>0) return 1;
else return -1;
}
ostream& GSM::operator<<(ostream& os, const Time& t)
{
os << t.TN() << ":" << t.FN();
return os;
}
void Clock::set(const Time& when)
{
mLock.lock();
mBaseTime = Timeval(0);
mBaseFN = when.FN();
mLock.unlock();
}
int32_t Clock::FN() const
{
mLock.lock();
Timeval now;
int deltaSec = now.sec() - mBaseTime.sec();
int deltaUSec = now.usec() - mBaseTime.usec();
int elapsedUSec = 1000000*deltaSec + deltaUSec;
int elapsedFrames = elapsedUSec / gFrameMicroseconds;
int32_t currentFN = (mBaseFN + elapsedFrames) % gHyperframe;
mLock.unlock();
return currentFN;
}
void Clock::wait(const Time& when) const
{
int32_t now = FN();
int32_t target = when.FN();
int32_t delta = FNDelta(target,now);
if (delta<1) return;
const int32_t maxSleep = 51*26;
if (delta>maxSleep) delta=maxSleep;
sleepFrames(delta);
}
ostream& GSM::operator<<(ostream& os, TypeOfNumber type)
{
switch (type) {
case UnknownTypeOfNumber: os << "unknown"; break;
case InternationalNumber: os << "international"; break;
case NationalNumber: os << "national"; break;
case NetworkSpecificNumber: os << "network-specific"; break;
case ShortCodeNumber: os << "short code"; break;
default: os << "?" << type << "?";
}
return os;
}
ostream& GSM::operator<<(ostream& os, NumberingPlan plan)
{
switch (plan) {
case UnknownPlan: os << "unknown"; break;
case E164Plan: os << "E.164/ISDN"; break;
case X121Plan: os << "X.121/data"; break;
case F69Plan: os << "F.69/Telex"; break;
case NationalPlan: os << "national"; break;
case PrivatePlan: os << "private"; break;
default: os << "?" << (int)plan << "?";
}
return os;
}
ostream& GSM::operator<<(ostream& os, MobileIDType wID)
{
switch (wID) {
case NoIDType: os << "None"; break;
case IMSIType: os << "IMSI"; break;
case IMEIType: os << "IMEI"; break;
case TMSIType: os << "TMSI"; break;
case IMEISVType: os << "IMEISV"; break;
default: os << "?" << (int)wID << "?";
}
return os;
}
ostream& GSM::operator<<(ostream& os, TypeAndOffset tao)
{
switch (tao) {
case TDMA_MISC: os << "(misc)"; break;
case TCHF_0: os << "TCH/F"; break;
case TCHH_0: os << "TCH/H-0"; break;
case TCHH_1: os << "TCH/H-1"; break;
case SDCCH_4_0: os << "SDCCH/4-0"; break;
case SDCCH_4_1: os << "SDCCH/4-1"; break;
case SDCCH_4_2: os << "SDCCH/4-2"; break;
case SDCCH_4_3: os << "SDCCH/4-3"; break;
case SDCCH_8_0: os << "SDCCH/8-0"; break;
case SDCCH_8_1: os << "SDCCH/8-1"; break;
case SDCCH_8_2: os << "SDCCH/8-2"; break;
case SDCCH_8_3: os << "SDCCH/8-3"; break;
case SDCCH_8_4: os << "SDCCH/8-4"; break;
case SDCCH_8_5: os << "SDCCH/8-5"; break;
case SDCCH_8_6: os << "SDCCH/8-6"; break;
case SDCCH_8_7: os << "SDCCH/8-7"; break;
case TDMA_BEACON: os << "(beacon)"; break;
default: os << "?" << (int)tao << "?";
}
return os;
}
ostream& GSM::operator<<(ostream& os, ChannelType val)
{
switch (val) {
case UndefinedCHType: os << "undefined"; return os;
case SCHType: os << "SCH"; break;
case FCCHType: os << "FCCH"; break;
case BCCHType: os << "BCCH"; break;
case RACHType: os << "RACH"; break;
case SDCCHType: os << "SDCCH"; break;
case FACCHType: os << "FACCH"; break;
case CCCHType: os << "CCCH"; break;
case SACCHType: os << "SACCH"; break;
case TCHFType: os << "TCH/F"; break;
case TCHHType: os << "TCH/H"; break;
case AnyTCHType: os << "any TCH"; break;
case LoopbackFullType: os << "Loopback Full"; break;
case LoopbackHalfType: os << "Loopback Half"; break;
case AnyDCCHType: os << "any DCCH"; break;
default: os << "?" << (int)val << "?";
}
return os;
}
bool Z100Timer::expired() const
{
// A non-active timer does not expire.
if (!mActive) return false;
return mEndTime.passed();
}
void Z100Timer::set()
{
mEndTime = Timeval(mLimitTime);
mActive=true;
}
long Z100Timer::remaining() const
{
if (!mActive) return 0;
long rem = mEndTime.remaining();
if (rem<0) rem=0;
return rem;
}
void Z100Timer::wait() const
{
while (!expired()) msleep(remaining());
}
// vim: ts=4 sw=4

View File

@ -0,0 +1,537 @@
/**@file Common-use GSM declarations, most from the GSM 04.xx and 05.xx series. */
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Public License.
* See the COPYING file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GSMCOMMON_H
#define GSMCOMMON_H
#include <stdlib.h>
#include <sys/time.h>
#include <ostream>
#include <vector>
#include <Threads.h>
#include <Timeval.h>
#include <BitVector.h>
namespace GSM {
/**@namespace GSM This namespace covers L1 FEC, L2 and L3 message translation. */
/* forward references */
class L1FEC;
class L2LAPDm;
class L3Processor;
class LogicalChannel;
class L2Header;
/** A base class for GSM exceptions. */
class GSMError {};
/** Duration ofa GSM frame, in microseconds. */
const unsigned gFrameMicroseconds = 4615;
/** Sleep for a given number of GSM frame periods. */
inline void sleepFrames(unsigned frames)
{ usleep(frames*gFrameMicroseconds); }
/** Sleep for 1 GSM frame period. */
inline void sleepFrame()
{ usleep(gFrameMicroseconds); }
/** GSM Training sequences from GSM 05.02 5.2.3. */
extern const BitVector gTrainingSequence[];
/** C0T0 filler burst, GSM 05.02, 5.2.6 */
extern const BitVector gDummyBurst;
/** Random access burst synch. sequence */
extern const BitVector gRACHSynchSequence;
/**@name Support for GSM 7-bit alphabet, GSM 03.38 6.2.1. */
//@{
/** Indexed by GSM 7-bit, returns ASCII. */
static const char gGSMAlphabet[] = "@\243$\245\350\351\371\354\362\347\n\330\370\r\305\345D_FGLOPCSTZ \306\346\337\311 !\"#\244%&\'()*+,-./0123456789:;<=>?\241ABCDEFGHIJKLMNOPQRSTUVWXYZ\304\326\321\334\247\277abcdefghijklmnopqrstuvwxyz\344\366\361\374\341";
char encodeGSMChar(char ascii);
inline char decodeGSMChar(char sms) { return gGSMAlphabet[(unsigned)sms]; }
//@}
/**@name BCD-ASCII mapping, GMS 04.08 Table 10.5.118. */
//@{
/** Indexed by BCD, returns ASCII. */
static const char gBCDAlphabet[] = "0123456789.#abc";
char encodeBCDChar(char ascii);
inline char decodeBCDChar(char bcd) { return gBCDAlphabet[(unsigned)bcd]; }
//@}
/**@name Globally-fixed GSM timeout values (all in ms). */
//@{
/**@name GSM LAPDm timeouts, GSM 04.06 5.8, ITU-T Q.921 5.9 */
//@{
const unsigned T200ms = 900; ///< LAPDm ACK timeout, set for typical turnaround time
//@}
/**@name GSM timeouts for radio resource management, GSM 04.08 11.1. */
//@{
const unsigned T3101ms = 4000; ///< L1 timeout for SDCCH assignment
const unsigned T3107ms = 3000; ///< L1 timeout for TCH/FACCH assignment
const unsigned T3109ms = 10000; ///< L1 timeout for an existing channel
const unsigned T3111ms = 2*T200ms; ///< L1 timeout for reassignment of a channel
const unsigned T3113ms = 10000; ///< timeout for paging response
const unsigned T3122ms = 2000; ///< RR access holdoff time (GSM 04.08 3.3.1.1.3.2)
//@}
/**@name GSM timeouts for mobility management, GSM 04.08 11.2. */
//@{
const unsigned T3212ms = 8*360000; ///< location updating period (in 6-min increments, 0-255)
//const unsigned T3212ms = 0; ///< location updating period (in 6-min increments, 0-255), 0 disables
//@}
//@}
/** GSM 04.08 Table 10.5.118 */
enum TypeOfNumber {
UnknownTypeOfNumber = 0,
InternationalNumber = 1,
NationalNumber = 2,
NetworkSpecificNumber = 3,
ShortCodeNumber = 4
};
std::ostream& operator<<(std::ostream&, TypeOfNumber);
/** GSM 04.08 Table 10.5.118 */
enum NumberingPlan {
UnknownPlan = 0,
E164Plan = 1,
X121Plan = 3,
F69Plan = 4,
NationalPlan = 8,
PrivatePlan = 9
};
std::ostream& operator<<(std::ostream&, NumberingPlan);
/** Codes for GSM band types, GSM 05.05 2. */
enum GSMBand {
GSM850=0, ///< US cellular
EGSM900, ///< extended GSM
DCS1800, ///< worldwide DCS band
PCS1900 ///< US PCS band
};
/**@name Actual radio carrier frequencies, in kHz, GSM 05.05 2 */
//@{
unsigned uplinkFreqKHz(GSMBand wBand, unsigned wARFCN);
unsigned downlinkFreqKHz(GSMBand wBand, unsigned wARFCN);
//@}
/**@name GSM Logical channel (LCH) types. */
//@{
/** Codes for logical channel types. */
enum ChannelType {
///@name Non-dedicated control channels.
//@{
SCHType, ///< sync
FCCHType, ///< frequency correction
BCCHType, ///< broadcast control
CCCHType, ///< common control, a combination of several sub-types
RACHType, ///< random access
SACCHType, ///< slow associated control (acutally dedicated, but...)
//@}
///@name Dedicated control channels (DCCHs).
//@{
SDCCHType, ///< standalone dedicated control
FACCHType, ///< fast associated control
//@}
///@name Traffic channels
//@{
TCHFType, ///< full-rate traffic
TCHHType, ///< half-rate traffic
AnyTCHType, ///< any TCH type
//@}
///@name Special internal channel types.
//@{
LoopbackFullType, ///< loopback testing
LoopbackHalfType, ///< loopback testing
AnyDCCHType, ///< any dedicated control channel
UndefinedCHType, ///< undefined
//@}
};
/** Print channel type name to a stream. */
std::ostream& operator<<(std::ostream& os, ChannelType val);
//@}
/** Mobile identity types, GSM 04.08 10.5.1.4 */
enum MobileIDType {
NoIDType = 0,
IMSIType = 1,
IMEIType = 2,
IMEISVType = 3,
TMSIType = 4
};
std::ostream& operator<<(std::ostream& os, MobileIDType);
/** Type and TDMA offset of a logical channel, from GSM 04.08 10.5.2.5 */
enum TypeAndOffset {
TDMA_MISC=0,
TCHF_0=1,
TCHH_0=2, TCHH_1=3,
SDCCH_4_0=4, SDCCH_4_1=5, SDCCH_4_2=6, SDCCH_4_3=7,
SDCCH_8_0=8, SDCCH_8_1=9, SDCCH_8_2=10, SDCCH_8_3=11,
SDCCH_8_4=12, SDCCH_8_5=13, SDCCH_8_6=14, SDCCH_8_7=15,
/// An extra one for our internal use.
TDMA_BEACON=255
};
std::ostream& operator<<(std::ostream& os, TypeAndOffset);
/**
L3 Protocol Discriminator, GSM 04.08 10.2, GSM 04.07 11.2.3.1.1.
*/
enum L3PD {
L3GroupCallControlPD=0x00,
L3BroadcastCallControlPD=0x01,
L3PDSS1PD=0x02,
L3CallControlPD=0x03,
L3PDSS2PD=0x04,
L3MobilityManagementPD=0x05,
L3RadioResourcePD=0x06,
L3MobilityManagementGPRSPD=0x08,
L3SMSPD=0x09,
L3GPRSSessionManagementPD=0x0a,
L3NonCallSSPD=0x0b,
L3LocationPD=0x0c,
L3ExtendedPD=0x0e,
L3TestProcedurePD=0x0f,
L3UndefinedPD=-1
};
std::ostream& operator<<(std::ostream& os, L3PD val);
/**@name Modulus operations for frame numbers. */
//@{
/** The GSM hyperframe is largest time period in the GSM system, GSM 05.02 4.3.3. */
const int32_t gHyperframe = 2048UL * 26UL * 51UL;
/** Get a clock difference, within the modulus. */
int32_t FNDelta(int32_t v1, int32_t v2);
/**
Compare two frame clock values.
@return 1 if v1>v2, -1 if v1<v2, 0 if v1==v2
*/
int FNCompare(int32_t v1, int32_t v2);
//@}
/**
GSM frame clock value.
No internal thread sync.
*/
class Time {
private:
int mFN; ///< frame number in the hyperframe
unsigned mTN; ///< timeslot number
public:
Time(int wFN=0, unsigned wTN=0)
:mFN(wFN),mTN(wTN)
{ }
/** Move the time forward to a given position in a given modulus. */
void rollForward(unsigned wFN, unsigned modulus)
{ while ((mFN % modulus) != wFN) mFN++; }
/**@name Accessors. */
//@{
int FN() const { return mFN; }
void FN(unsigned wFN) { mFN = wFN; }
unsigned TN() const { return mTN; }
void TN(unsigned wTN) { mTN=wTN; }
//@}
/**@name Arithmetic. */
//@{
Time& operator++()
{
mFN = (mFN+1) % gHyperframe;
return *this;
}
Time& decTN(int step=1)
{
if ((int)mTN<step) mFN = *this - Time(1,0);
if (mTN-step < 0) mTN = (mTN-step+8) % 8;
else mTN = (mTN-step) % 8;
return *this;
}
Time& incTN(int step=1)
{
mFN = mFN + (mTN + step)/8;
mTN = (mTN+step) % 8;
return *this;
}
Time& operator+=(int step)
{
mFN = (mFN+step) % gHyperframe;
return *this;
}
Time operator+(int step) const
{
Time newVal = *this;
newVal += step;
return newVal;
}
Time operator-(int step) const
{
return operator+(-step);
}
Time operator+(const Time& other) const
{
unsigned newTN = (mTN + other.mTN) % 8;
uint64_t newFN = (mFN+other.mFN + (mTN + other.mTN)/8) % gHyperframe;
return Time(newFN,newTN);
}
int operator-(const Time& other) const
{
return FNDelta(mFN,other.mFN);
}
//@}
/**@name Comparisons. */
//@{
bool operator<(const Time& other) const
{
if (mFN==other.mFN) return (mTN<other.mTN);
return FNCompare(mFN,other.mFN)<0;
}
bool operator>(const Time& other) const
{
if (mFN==other.mFN) return (mTN>other.mTN);
return FNCompare(mFN,other.mFN)>0;
}
bool operator<=(const Time& other) const
{
if (mFN==other.mFN) return (mTN<=other.mTN);
return FNCompare(mFN,other.mFN)<=0;
}
bool operator>=(const Time& other) const
{
if (mFN==other.mFN) return (mTN>=other.mTN);
return FNCompare(mFN,other.mFN)>=0;
}
bool operator==(const Time& other) const
{
return (mFN == other.mFN) && (mTN==other.mTN);
}
//@}
/**@name Standard derivations. */
//@{
unsigned SFN() const { return mFN / (26*51); }
unsigned T1() const { return SFN() % 2048; }
unsigned T2() const { return mFN % 26; }
unsigned T3() const { return mFN % 51; }
/** GSM 05.02 3.3.2.2.1. */
unsigned T3p() const { return (T3()-1)/10; }
/** GSM 05.02 6.3.1.3. */
unsigned TC() const { return (FN()/51) % 8; }
/** GSM 04.08 10.5.2.30. */
unsigned T1p() const { return SFN() % 32; }
/** GSM 05.02 6.2.3 */
unsigned T1R() const { return T1() % 64; }
//@}
};
std::ostream& operator<<(std::ostream& os, const Time& ts);
/**
A class for calculating the current GSM frame number.
*/
class Clock {
private:
mutable Mutex mLock;
int32_t mBaseFN;
Timeval mBaseTime;
public:
Clock(const Time& when = Time(0))
:mBaseFN(when.FN())
{}
/** Set the clock to a value. */
void set(const Time&);
/** Read the clock. */
int32_t FN() const;
/** Read the clock. */
Time get() const { return Time(FN()); }
/** Block until the clock passes a given time. */
void wait(const Time&) const;
};
/**
CCITT Z.100 activity timer, as described in GSM 04.06 5.1.
All times are in milliseconds.
*/
class Z100Timer {
private:
Timeval mEndTime; ///< the time at which this timer will expire
long mLimitTime; ///< timeout in milliseconds
bool mActive; ///< true if timer is active
public:
/** Create a timer with a given timeout in milliseconds. */
Z100Timer(long wLimitTime)
:mLimitTime(wLimitTime),
mActive(false)
{}
/** True if the timer is active and expired. */
bool expired() const;
/** Start or restart the timer. */
void set();
/** Stop the timer. */
void reset() { mActive = false; }
/** Returns true if the timer is active. */
bool active() const { return mActive; }
/**
Remaining time until expiration, in milliseconds.
Returns zero if the timer has expired.
*/
long remaining() const;
/**
Block until the timer expires.
Returns immediately if the timer is not running.
*/
void wait() const;
};
}; // namespace GSM
#endif
// vim: ts=4 sw=4

View File

@ -0,0 +1,256 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Public License.
* See the COPYING file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define NDEBUG
#include "GSML1FEC.h"
#include "GSMCommon.h"
#include "RxBurst.h"
//#include "GSMSAPMux.h"
//#include "GSMConfig.h"
#include "GSMTDMA.h"
#include "GSM610Tables.h"
#include "Assert.h"
using namespace std;
using namespace GSM;
/*
Compilation flags:
NOCONTROL Compile without referencing control layer functions.
*/
/*
Notes on reading the GSM specifications.
Every FEC section in GSM 05.03 uses standard names for the bits at
different stages of the encoding/decoding process.
This is all described formally in GSM 05.03 2.2.
"d" -- data bits. The actual payloads from L2 and the vocoders.
"p" -- parity bits. These are calculated from d.
"u" -- uncoded bits. A concatenation of d, p and inner tail bits.
"c" -- coded bits. These are the convolutionally encoded from u.
"i" -- interleaved bits. These are the output of the interleaver.
"e" -- "encrypted" bits. These are the channel bits in the radio bursts.
The "e" bits are call "encrypted" even when encryption is not used.
The encoding process is:
L2 -> d -> -> calc p -> u -> c -> i -> e -> radio bursts
The decoding process is:
radio bursts -> e -> i -> c -> u -> check p -> d -> L2
Bit ordering in d is LSB-first in each octet.
Bit ordering everywhere else in the OpenBTS code is MSB-first
in every field to give contiguous fields across byte boundaries.
We use the BitVector::LSB8MSB() method to translate.
*/
TCHFACCHL1Decoder::TCHFACCHL1Decoder(const TDMAMapping& wMapping)
: mTCHU(189), mTCHD(260), mC(456),
mClass1_c(mC.head(378)), mClass1A_d(mTCHD.head(50)), mClass2_c(mC.segment(378, 78)),
mTCHParity(0x0b, 3, 50), mMapping(wMapping)
{
for (int i = 0; i < 8; i++) {
mI[i] = SoftVector(114);
}
}
void TCHFACCHL1Decoder::writeLowSide(const RxBurst& inBurst)
{
OBJDCOUT("TCHFACCHL1Decoder::writeLowSide " << inBurst);
// If the channel is closed, ignore the burst.
// if (!active()) {
// OBJDCOUT("TCHFACCHL1Decoder::writeLowSide not active, ignoring input");
// return;
// }
processBurst(inBurst);
}
bool TCHFACCHL1Decoder::processBurst( const RxBurst& inBurst)
{
// Accept the burst into the deinterleaving buffer.
// Return true if we are ready to interleave.
// TODO -- One quick test of burst validity is to look at the tail bits.
// We could do that as a double-check against putting garbage into
// the interleaver or accepting bad parameters.
// Get the physical parameters of the burst.
// RSSI is dB wrt full scale.
// mRSSI = inBurst.RSSI();
// Timing error is a float in symbol intervals.
// mTimingError = inBurst.timingError();
// This flag is used as a half-ass semaphore.
// It is cleared when the new value is read.
// mPhyNew = true;
// The reverse index runs 0..3 as the bursts arrive.
// It is the "B" index of GSM 05.03 3.1.3 and 3.1.4.
int B = mMapping.reverseMapping(inBurst.time().FN()) % 8;
// A negative value means that the demux is misconfigured.
assert(B >= 0);
OBJDCOUT("TCHFACCHL1Decoder::processBurst B=" << B << " " << inBurst);
// Pull the data fields (e-bits) out of the burst and put them into i[B][].
// GSM 05.03 3.1.4
inBurst.data1().copyToSegment(mI[B], 0);
inBurst.data2().copyToSegment(mI[B], 57);
// Every 4th frame is the start of a new block.
// So if this isn't a "4th" frame, return now.
if (B % 4 != 3) return false;
// Deinterleave according to the diagonal "phase" of B.
// See GSM 05.03 3.1.3.
// Deinterleaves i[] to c[]
if (B == 3) deinterleave(4);
else deinterleave(0);
// See if this was the end of a stolen frame, GSM 05.03 4.2.5.
bool stolen = inBurst.Hl();
OBJDCOUT("TCHFACCHL!Decoder::processBurst Hl=" << inBurst.Hl() << " Hu=" << inBurst.Hu());
/* if (stolen) {
if (decode()) {
OBJDCOUT("TCHFACCHL1Decoder::processBurst good FACCH frame");
countGoodFrame();
handleGoodFrame();
} else {
OBJDCOUT("TCHFACCHL1Decoder::processBurst bad FACCH frame");
countBadFrame();
}
}*/
// Always feed the traffic channel, even on a stolen frame.
// decodeTCH will handle the GSM 06.11 bad frmae processing.
bool traffic = decodeTCH(stolen);
// if (traffic) {
OBJDCOUT("TCHFACCHL1Decoder::processBurst good TCH frame");
// countGoodFrame();
// Don't let the channel timeout.
// mLock.lock();
// mT3109.set();
// mLock.unlock();
// }
// else countBadFrame();
return traffic;
}
void TCHFACCHL1Decoder::deinterleave(int blockOffset )
{
OBJDCOUT("TCHFACCHL1Decoder::deinterleave blockOffset=" << blockOffset);
for (int k = 0; k < 456; k++) {
int B = ( k + blockOffset ) % 8;
int j = 2 * ((49 * k) % 57) + ((k % 8) / 4);
mC[k] = mI[B][j];
mI[B][j] = 0.5F;
//OBJDCOUT("deinterleave k="<<k<<" B="<<B<<" j="<<j);
}
}
bool TCHFACCHL1Decoder::decodeTCH(bool stolen)
{
// GSM 05.02 3.1.2, but backwards
// If the frame wasn't stolen, we'll update this with parity later.
bool good = !stolen;
// Good or bad, we will be sending *something* to the speech channel.
// Allocate it in this scope.
unsigned char * newFrame = new unsigned char[33];
if (!stolen) {
// 3.1.2.2
// decode from c[] to u[]
mClass1_c.decode(mVCoder, mTCHU);
//mC.head(378).decode(mVCoder,mTCHU);
// 3.1.2.2
// copy class 2 bits c[] to d[]
mClass2_c.sliced().copyToSegment(mTCHD, 182);
//mC.segment(378,78).sliced().copyToSegment(mTCHD,182);
// 3.1.2.1
// copy class 1 bits u[] to d[]
for (unsigned k = 0; k <= 90; k++) {
mTCHD[2*k] = mTCHU[k];
mTCHD[2*k+1] = mTCHU[184-k];
}
// 3.1.2.1
// check parity of class 1A
unsigned sentParity = (~mTCHU.peekField(91, 3)) & 0x07;
//unsigned calcParity = mTCHD.head(50).parity(mTCHParity) & 0x07;
unsigned calcParity = mClass1A_d.parity(mTCHParity) & 0x07;
// 3.1.2.2
// Check the tail bits, too.
unsigned tail = mTCHU.peekField(185, 4);
OBJDCOUT("TCHFACCHL1Decoder::decodeTCH c[]=" << mC);
//OBJDCOUT("TCHFACCHL1Decoder::decodeTCH u[]=" << mTCHU);
OBJDCOUT("TCHFACCHL1Decoder::decodeTCH d[]=" << mTCHD);
OBJDCOUT("TCHFACCHL1Decoder::decodeTCH sentParity=" << sentParity
<< " calcParity=" << calcParity << " tail=" << tail);
good = (sentParity == calcParity) && (tail == 0);
if (good) {
// Undo Um's importance-sorted bit ordering.
// See GSM 05.03 3.1 and Tablee 2.
BitVector payload = mVFrame.payload();
mTCHD.unmap(g610BitOrder, 260, payload);
mVFrame.pack(newFrame);
// Save a copy for bad frame processing.
memcpy(mPrevGoodFrame, newFrame, 33);
return true;
}
}
if (!good) {
// TODO -- Bad frame processing, GSM 06.11.
// For now, just repeat the last good frame.
// TODO -- Need to apply attenuation and randomization of grid positions.
memcpy(newFrame, mPrevGoodFrame, 33);
//d_gsm_file.write((char *)newFrame, 33);
}
// Good or bad, we must feed the speech channel.
// mSpeechQ.write(newFrame);
return false;
}
// vim: ts=4 sw=4

View File

@ -0,0 +1,146 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This software is distributed under the terms of the GNU Public License.
* See the COPYING file in the main directory for details.
*/
#ifndef GSML1FEC_H
#define GSML1FEC_H
//#include "Threads.h"
#include "Assert.h"
#include "BitVector.h"
#include "GSMCommon.h"
//#include "GSMTransfer.h"
#include "GSMTDMA.h"
#include "VocoderFrame.h"
#include "RxBurst.h"
//#include "GSM610Tables.h"
#include <stdio.h>
namespace GSM
{
//class SAPMux;
class L1FEC;
class L1Decoder;
/*
Naming convention for bit vectors follows GSM 05.03 Section 2.2.
d[k] data
u[k] data bits after first encoding step
c[k] data bits after second encoding step
i[B][k] interleaved data bits
e[B][k] bits in a burst
*/
/** L1 decoder used for full rate TCH and FACCH -- mostly from GSM 05.03 3.1 and 4.2 */
//: public XCCHL1Decoder
class TCHFACCHL1Decoder
{
protected:
SoftVector mI[8]; ///< deinterleaving history, 8 blocks instead of 4
SoftVector mC; ///< c[], as per GSM 05.03 2.2
BitVector mTCHU; ///< u[] (uncoded) in the spec
BitVector mTCHD; ///< d[] (data) in the spec
SoftVector mClass1_c; ///< the class 1 part of c[]
BitVector mClass1A_d; ///< the class 1A part of d[]
SoftVector mClass2_c; ///< the class 2 part of c[]
ViterbiR2O4 mVCoder;
VocoderFrame mVFrame; ///< unpacking buffer for vocoder frame
unsigned char mPrevGoodFrame[33]; ///< previous good frame.
Parity mTCHParity;
const TDMAMapping& mMapping; ///< multiplexing description
// InterthreadQueue<unsigned char> mSpeechQ; ///< output queue for speech frames
static const unsigned mMaxQSize = 3;
public:
TCHFACCHL1Decoder( const TDMAMapping& wMapping );
ChannelType channelType() const {
return FACCHType;
}
/** TCH/FACCH has a special-case writeLowSide. */
void writeLowSide(const RxBurst& inBurst);
/**
Unlike other DCCHs, TCH/FACCH process burst calls
deinterleave, decode, handleGoodFrame.
*/
bool processBurst( const RxBurst& );
/** Deinterleave i[] to c[]. */
void deinterleave(int blockOffset );
void replaceFACCH( int blockOffset );
/**
Decode a traffic frame from TCHI[] and enqueue it.
Return true if there's a good frame.
*/
bool decodeTCH(bool stolen);
unsigned char * get_voice_frame(){
return mPrevGoodFrame;
}
/**
Receive a traffic frame.
Non-blocking. Returns NULL if queue is dry.
Caller is responsible for deleting the returned array.
*/
// unsigned char *recvTCH() { return mSpeechQ.read(0); }
/** Return count of internally-queued traffic frames. */
// unsigned queueSize() const { return mSpeechQ.size(); }
};
}; // namespace GSM
#endif
// vim: ts=4 sw=4

View File

@ -0,0 +1,337 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Public License.
* See the COPYING file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "GSMTDMA.h"
using namespace GSM;
TDMAMapping::TDMAMapping(TypeAndOffset
wTypeAndOffset, bool wDownlink, bool wUplink, char wAllowedSlots, bool wC0Only,
unsigned wRepeatLength, unsigned wNumFrames, const unsigned *wFrameMapping)
:mTypeAndOffset(wTypeAndOffset),
mDownlink(wDownlink),mUplink(wUplink),mAllowedSlots(wAllowedSlots),mC0Only(wC0Only),
mRepeatLength(wRepeatLength),mNumFrames(wNumFrames),mFrameMapping(wFrameMapping)
{
// Sanity check.
assert(mRepeatLength<=mMaxRepeatLength);
// Default, -1, means a non-occupied position.
for (unsigned i=0; i<mMaxRepeatLength; i++) mReverseMapping[i]=-1;
// Fill in the reverse map, precomputed for speed.
for (unsigned i=0; i<mNumFrames; i++) {
unsigned mapping = mFrameMapping[i];
assert(mapping<mRepeatLength);
mReverseMapping[mapping] = i;
}
}
/** A macro to save some typing when we set up TDMA maps. */
#define MAKE_TDMA_MAPPING(NAME,TYPEANDOFFSET,DOWNLINK,UPLINK,ALLOWEDSLOTS,C0ONLY,REPEAT) \
const TDMAMapping GSM::g##NAME##Mapping(TYPEANDOFFSET,DOWNLINK,UPLINK,ALLOWEDSLOTS,C0ONLY, \
REPEAT,sizeof(NAME##Frames)/sizeof(unsigned),NAME##Frames)
const unsigned LoopbackTestFullFrames[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47};
MAKE_TDMA_MAPPING(LoopbackTestFull,TDMA_MISC,true,true,0xff,false,51);
const unsigned FCCHFrames[] = {0,10,20,30,40};
MAKE_TDMA_MAPPING(FCCH,TDMA_BEACON,true,false,0x01,true,51);
const unsigned SCHFrames[] = {1,11,21,31,41};
MAKE_TDMA_MAPPING(SCH,TDMA_BEACON,true,false,0x01,true,51);
const unsigned BCCHFrames[] = {2,3,4,5};
MAKE_TDMA_MAPPING(BCCH,TDMA_BEACON,true,false,0x55,true,51);
// Note that we removed frames for the SDCCH components of the Combination-V C0T0.
const unsigned RACHC5Frames[] = {4,5,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,45,46};
MAKE_TDMA_MAPPING(RACHC5,TDMA_BEACON,false,true,0x55,true,51);
// CCCH 0-2 are used in C-IV and C-V. The others are used in C-IV only.
const unsigned CCCH_0Frames[] = {6,7,8,9};
MAKE_TDMA_MAPPING(CCCH_0,TDMA_BEACON,true,false,0x55,true,51);
const unsigned CCCH_1Frames[] = {12,13,14,15};
MAKE_TDMA_MAPPING(CCCH_1,TDMA_BEACON,true,false,0x55,true,51);
const unsigned CCCH_2Frames[] = {16,17,18,19};
MAKE_TDMA_MAPPING(CCCH_2,TDMA_BEACON,true,false,0x55,true,51);
const unsigned CCCH_3Frames[] = {22,23,24,25};
MAKE_TDMA_MAPPING(CCCH_3,TDMA_BEACON,true,false,0x55,true,51);
// TODO -- Other CCCH subchannels 4-8 for support of C-IV.
const unsigned SDCCH_4_0DFrames[] = {22,23,24,25};
MAKE_TDMA_MAPPING(SDCCH_4_0D,SDCCH_4_0,true,false,0x01,true,51);
const unsigned SDCCH_4_0UFrames[] = {37,38,39,40};
MAKE_TDMA_MAPPING(SDCCH_4_0U,SDCCH_4_0,false,true,0x01,true,51);
const unsigned SDCCH_4_1DFrames[] = {26,27,28,29};
MAKE_TDMA_MAPPING(SDCCH_4_1D,SDCCH_4_1,true,false,0x01,true,51);
const unsigned SDCCH_4_1UFrames[] = {41,42,43,44};
MAKE_TDMA_MAPPING(SDCCH_4_1U,SDCCH_4_1,false,true,0x01,true,51);
const unsigned SDCCH_4_2DFrames[] = {32,33,34,35};
MAKE_TDMA_MAPPING(SDCCH_4_2D,SDCCH_4_2,true,false,0x01,true,51);
const unsigned SDCCH_4_2UFrames[] = {47,48,49,50};
MAKE_TDMA_MAPPING(SDCCH_4_2U,SDCCH_4_2,false,true,0x01,true,51);
const unsigned SDCCH_4_3DFrames[] = {36,37,38,39};
MAKE_TDMA_MAPPING(SDCCH_4_3D,SDCCH_4_3,true,false,0x01,true,51);
const unsigned SDCCH_4_3UFrames[] = {0,1,2,3};
MAKE_TDMA_MAPPING(SDCCH_4_3U,SDCCH_4_3,false,true,0x01,true,51);
const unsigned SACCH_C4_0DFrames[] = {42,43,44,45};
MAKE_TDMA_MAPPING(SACCH_C4_0D,SDCCH_4_0,true,false,0x01,true,102);
const unsigned SACCH_C4_0UFrames[] = {57,58,59,60};
MAKE_TDMA_MAPPING(SACCH_C4_0U,SDCCH_4_0,false,true,0x01,true,102);
const unsigned SACCH_C4_1DFrames[] = {46,47,48,49};
MAKE_TDMA_MAPPING(SACCH_C4_1D,SDCCH_4_1,true,false,0x01,true,102);
const unsigned SACCH_C4_1UFrames[] = {61,62,63,64};
MAKE_TDMA_MAPPING(SACCH_C4_1U,SDCCH_4_1,false,true,0x01,true,102);
const unsigned SACCH_C4_2DFrames[] = {93,94,95,96};
MAKE_TDMA_MAPPING(SACCH_C4_2D,SDCCH_4_2,true,false,0x01,true,102);
const unsigned SACCH_C4_2UFrames[] = {6,7,8,9};
MAKE_TDMA_MAPPING(SACCH_C4_2U,SDCCH_4_2,false,true,0x01,true,102);
const unsigned SACCH_C4_3DFrames[] = {97,98,99,100};
MAKE_TDMA_MAPPING(SACCH_C4_3D,SDCCH_4_3,true,false,0x01,true,102);
const unsigned SACCH_C4_3UFrames[] = {10,11,12,13};
MAKE_TDMA_MAPPING(SACCH_C4_3U,SDCCH_4_3,false,true,0x01,true,102);
const unsigned SDCCH_8_0DFrames[] = {0,1,2,3};
MAKE_TDMA_MAPPING(SDCCH_8_0D,SDCCH_8_0,true,false,0xFF,true,51);
const unsigned SDCCH_8_0UFrames[] = {15,16,17,18};
MAKE_TDMA_MAPPING(SDCCH_8_0U,SDCCH_8_0,false,true,0xFF,true,51);
const unsigned SDCCH_8_1DFrames[] = {4,5,6,7};
MAKE_TDMA_MAPPING(SDCCH_8_1D,SDCCH_8_1,true,false,0xFF,true,51);
const unsigned SDCCH_8_1UFrames[] = {19,20,21,22};
MAKE_TDMA_MAPPING(SDCCH_8_1U,SDCCH_8_1,false,true,0xFF,true,51);
const unsigned SDCCH_8_2DFrames[] = {8,9,10,11};
MAKE_TDMA_MAPPING(SDCCH_8_2D,SDCCH_8_2,true,false,0xFF,true,51);
const unsigned SDCCH_8_2UFrames[] = {23,24,25,26};
MAKE_TDMA_MAPPING(SDCCH_8_2U,SDCCH_8_2,false,true,0xFF,true,51);
const unsigned SDCCH_8_3DFrames[] = {12,13,14,15};
MAKE_TDMA_MAPPING(SDCCH_8_3D,SDCCH_8_3,true,false,0xFF,true,51);
const unsigned SDCCH_8_3UFrames[] = {27,28,29,30};
MAKE_TDMA_MAPPING(SDCCH_8_3U,SDCCH_8_3,false,true,0xFF,true,51);
const unsigned SDCCH_8_4DFrames[] = {16,17,18,19};
MAKE_TDMA_MAPPING(SDCCH_8_4D,SDCCH_8_4,true,false,0xFF,true,51);
const unsigned SDCCH_8_4UFrames[] = {31,32,33,34};
MAKE_TDMA_MAPPING(SDCCH_8_4U,SDCCH_8_4,false,true,0xFF,true,51);
const unsigned SDCCH_8_5DFrames[] = {20,21,22,23};
MAKE_TDMA_MAPPING(SDCCH_8_5D,SDCCH_8_5,true,false,0xFF,true,51);
const unsigned SDCCH_8_5UFrames[] = {35,36,37,38};
MAKE_TDMA_MAPPING(SDCCH_8_5U,SDCCH_8_5,false,true,0xFF,true,51);
const unsigned SDCCH_8_6DFrames[] = {24,25,26,27};
MAKE_TDMA_MAPPING(SDCCH_8_6D,SDCCH_8_6,true,false,0xFF,true,51);
const unsigned SDCCH_8_6UFrames[] = {39,40,41,42};
MAKE_TDMA_MAPPING(SDCCH_8_6U,SDCCH_8_6,false,true,0xFF,true,51);
const unsigned SDCCH_8_7DFrames[] = {28,29,30,31};
MAKE_TDMA_MAPPING(SDCCH_8_7D,SDCCH_8_7,true,false,0xFF,true,51);
const unsigned SDCCH_8_7UFrames[] = {43,44,45,46};
MAKE_TDMA_MAPPING(SDCCH_8_7U,SDCCH_8_7,false,true,0xFF,true,51);
const unsigned SACCH_C8_0DFrames[] = {32,33,34,35};
MAKE_TDMA_MAPPING(SACCH_C8_0D,SDCCH_8_0,true,false,0xFF,true,102);
const unsigned SACCH_C8_0UFrames[] = {47,48,49,50};
MAKE_TDMA_MAPPING(SACCH_C8_0U,SDCCH_8_0,false,true,0xFF,true,102);
const unsigned SACCH_C8_1DFrames[] = {36,37,38,39};
MAKE_TDMA_MAPPING(SACCH_C8_1D,SDCCH_8_1,true,false,0xFF,true,102);
const unsigned SACCH_C8_1UFrames[] = {51,52,53,54};
MAKE_TDMA_MAPPING(SACCH_C8_1U,SDCCH_8_1,false,true,0xFF,true,102);
const unsigned SACCH_C8_2DFrames[] = {40,41,42,43};
MAKE_TDMA_MAPPING(SACCH_C8_2D,SDCCH_8_2,true,false,0xFF,true,102);
const unsigned SACCH_C8_2UFrames[] = {55,56,57,58};
MAKE_TDMA_MAPPING(SACCH_C8_2U,SDCCH_8_2,false,true,0xFF,true,102);
const unsigned SACCH_C8_3DFrames[] = {44,45,46,47};
MAKE_TDMA_MAPPING(SACCH_C8_3D,SDCCH_8_3,true,false,0xFF,true,102);
const unsigned SACCH_C8_3UFrames[] = {59,60,61,62};
MAKE_TDMA_MAPPING(SACCH_C8_3U,SDCCH_8_3,false,true,0xFF,true,102);
const unsigned SACCH_C8_4DFrames[] = {82,84,85,86};
MAKE_TDMA_MAPPING(SACCH_C8_4D,SDCCH_8_4,true,false,0xFF,true,102);
const unsigned SACCH_C8_4UFrames[] = {98,99,100,101};
MAKE_TDMA_MAPPING(SACCH_C8_4U,SDCCH_8_4,false,true,0xFF,true,102);
const unsigned SACCH_C8_5DFrames[] = {87,88,89,90};
MAKE_TDMA_MAPPING(SACCH_C8_5D,SDCCH_8_5,true,false,0xFF,true,102);
const unsigned SACCH_C8_5UFrames[] = {0,1,2,3};
MAKE_TDMA_MAPPING(SACCH_C8_5U,SDCCH_8_5,false,true,0xFF,true,102);
const unsigned SACCH_C8_6DFrames[] = {91,92,93,94};
MAKE_TDMA_MAPPING(SACCH_C8_6D,SDCCH_8_6,true,false,0xFF,true,102);
const unsigned SACCH_C8_6UFrames[] = {4,5,6,7};
MAKE_TDMA_MAPPING(SACCH_C8_6U,SDCCH_8_6,false,true,0xFF,true,102);
const unsigned SACCH_C8_7DFrames[] = {95,96,97,98};
MAKE_TDMA_MAPPING(SACCH_C8_7D,SDCCH_8_7,true,false,0xFF,true,102);
const unsigned SACCH_C8_7UFrames[] = {8,9,10,11};
MAKE_TDMA_MAPPING(SACCH_C8_7U,SDCCH_8_7,false,true,0xFF,true,102);
const unsigned SACCH_TF_T0Frames[] = {12,38,64,90};
MAKE_TDMA_MAPPING(SACCH_TF_T0,TCHF_0,true,true,0x01,true,104);
const unsigned SACCH_TF_T1Frames[] = {25,51,77,103};
MAKE_TDMA_MAPPING(SACCH_TF_T1,TCHF_0,true,true,0x02,true,104);
const unsigned SACCH_TF_T2Frames[] = {38,64,90,12};
MAKE_TDMA_MAPPING(SACCH_TF_T2,TCHF_0,true,true,0x04,true,104);
const unsigned SACCH_TF_T3Frames[] = {51,77,103,25};
MAKE_TDMA_MAPPING(SACCH_TF_T3,TCHF_0,true,true,0x08,true,104);
const unsigned SACCH_TF_T4Frames[] = {64,90,12,38};
MAKE_TDMA_MAPPING(SACCH_TF_T4,TCHF_0,true,true,0x10,true,104);
const unsigned SACCH_TF_T5Frames[] = {77,103,25,51};
MAKE_TDMA_MAPPING(SACCH_TF_T5,TCHF_0,true,true,0x20,true,104);
const unsigned SACCH_TF_T6Frames[] = {90,12,38,64};
MAKE_TDMA_MAPPING(SACCH_TF_T6,TCHF_0,true,true,0x40,true,104);
const unsigned SACCH_TF_T7Frames[] = {103,25,51,77};
MAKE_TDMA_MAPPING(SACCH_TF_T7,TCHF_0,true,true,0x80,true,104);
const unsigned FACCH_TCHFFrames[] = {0,1,2,3,4,5,6,7,8,9,10,11,13,14,15,16,17,18,19,20,21,22,23,24};
MAKE_TDMA_MAPPING(FACCH_TCHF,TCHF_0,true,true,0xff,true,26);
const MappingPair GSM::gSDCCH_4_0Pair(gSDCCH_4_0DMapping,gSDCCH_4_0UMapping);
const MappingPair GSM::gSDCCH_4_1Pair(gSDCCH_4_1DMapping,gSDCCH_4_1UMapping);
const MappingPair GSM::gSDCCH_4_2Pair(gSDCCH_4_2DMapping,gSDCCH_4_2UMapping);
const MappingPair GSM::gSDCCH_4_3Pair(gSDCCH_4_3DMapping,gSDCCH_4_3UMapping);
const MappingPair GSM::gSDCCH_8_0Pair(gSDCCH_8_0DMapping,gSDCCH_8_0UMapping);
const MappingPair GSM::gSDCCH_8_1Pair(gSDCCH_8_1DMapping,gSDCCH_8_1UMapping);
const MappingPair GSM::gSDCCH_8_2Pair(gSDCCH_8_2DMapping,gSDCCH_8_2UMapping);
const MappingPair GSM::gSDCCH_8_3Pair(gSDCCH_8_3DMapping,gSDCCH_8_3UMapping);
const MappingPair GSM::gSDCCH_8_4Pair(gSDCCH_8_4DMapping,gSDCCH_8_4UMapping);
const MappingPair GSM::gSDCCH_8_5Pair(gSDCCH_8_5DMapping,gSDCCH_8_5UMapping);
const MappingPair GSM::gSDCCH_8_6Pair(gSDCCH_8_6DMapping,gSDCCH_8_6UMapping);
const MappingPair GSM::gSDCCH_8_7Pair(gSDCCH_8_7DMapping,gSDCCH_8_7UMapping);
const MappingPair GSM::gSACCH_C4_0Pair(gSACCH_C4_0DMapping,gSACCH_C4_0UMapping);
const MappingPair GSM::gSACCH_C4_1Pair(gSACCH_C4_1DMapping,gSACCH_C4_1UMapping);
const MappingPair GSM::gSACCH_C4_2Pair(gSACCH_C4_2DMapping,gSACCH_C4_2UMapping);
const MappingPair GSM::gSACCH_C4_3Pair(gSACCH_C4_3DMapping,gSACCH_C4_3UMapping);
const MappingPair GSM::gSACCH_C8_0Pair(gSACCH_C8_0DMapping,gSACCH_C8_0UMapping);
const MappingPair GSM::gSACCH_C8_1Pair(gSACCH_C8_1DMapping,gSACCH_C8_1UMapping);
const MappingPair GSM::gSACCH_C8_2Pair(gSACCH_C8_2DMapping,gSACCH_C8_2UMapping);
const MappingPair GSM::gSACCH_C8_3Pair(gSACCH_C8_3DMapping,gSACCH_C8_3UMapping);
const MappingPair GSM::gSACCH_C8_4Pair(gSACCH_C8_4DMapping,gSACCH_C8_4UMapping);
const MappingPair GSM::gSACCH_C8_5Pair(gSACCH_C8_5DMapping,gSACCH_C8_5UMapping);
const MappingPair GSM::gSACCH_C8_6Pair(gSACCH_C8_6DMapping,gSACCH_C8_6UMapping);
const MappingPair GSM::gSACCH_C8_7Pair(gSACCH_C8_7DMapping,gSACCH_C8_7UMapping);
const MappingPair GSM::gFACCH_TCHFPair(gFACCH_TCHFMapping,gFACCH_TCHFMapping);
const MappingPair GSM::gSACCH_FT_T0Pair(gSACCH_TF_T0Mapping, gSACCH_TF_T0Mapping);
const MappingPair GSM::gSACCH_FT_T1Pair(gSACCH_TF_T1Mapping, gSACCH_TF_T1Mapping);
const MappingPair GSM::gSACCH_FT_T2Pair(gSACCH_TF_T2Mapping, gSACCH_TF_T2Mapping);
const MappingPair GSM::gSACCH_FT_T3Pair(gSACCH_TF_T3Mapping, gSACCH_TF_T3Mapping);
const MappingPair GSM::gSACCH_FT_T4Pair(gSACCH_TF_T4Mapping, gSACCH_TF_T4Mapping);
const MappingPair GSM::gSACCH_FT_T5Pair(gSACCH_TF_T5Mapping, gSACCH_TF_T5Mapping);
const MappingPair GSM::gSACCH_FT_T6Pair(gSACCH_TF_T6Mapping, gSACCH_TF_T6Mapping);
const MappingPair GSM::gSACCH_FT_T7Pair(gSACCH_TF_T7Mapping, gSACCH_TF_T7Mapping);
const CompleteMapping GSM::gSDCCH_4_0(gSDCCH_4_0Pair,gSACCH_C4_0Pair);
const CompleteMapping GSM::gSDCCH_4_1(gSDCCH_4_1Pair,gSACCH_C4_1Pair);
const CompleteMapping GSM::gSDCCH_4_2(gSDCCH_4_2Pair,gSACCH_C4_2Pair);
const CompleteMapping GSM::gSDCCH_4_3(gSDCCH_4_3Pair,gSACCH_C4_3Pair);
const CompleteMapping GSM::gSDCCH_8_0(gSDCCH_8_0Pair,gSACCH_C8_0Pair);
const CompleteMapping GSM::gSDCCH_8_1(gSDCCH_8_1Pair,gSACCH_C8_1Pair);
const CompleteMapping GSM::gSDCCH_8_2(gSDCCH_8_2Pair,gSACCH_C8_2Pair);
const CompleteMapping GSM::gSDCCH_8_3(gSDCCH_8_3Pair,gSACCH_C8_3Pair);
const CompleteMapping GSM::gSDCCH_8_4(gSDCCH_8_4Pair,gSACCH_C8_4Pair);
const CompleteMapping GSM::gSDCCH_8_5(gSDCCH_8_5Pair,gSACCH_C8_5Pair);
const CompleteMapping GSM::gSDCCH_8_6(gSDCCH_8_6Pair,gSACCH_C8_6Pair);
const CompleteMapping GSM::gSDCCH_8_7(gSDCCH_8_7Pair,gSACCH_C8_7Pair);
const CompleteMapping GSM::gTCHF_T0(gFACCH_TCHFPair,gSACCH_FT_T0Pair);
const CompleteMapping GSM::gTCHF_T1(gFACCH_TCHFPair,gSACCH_FT_T1Pair);
const CompleteMapping GSM::gTCHF_T2(gFACCH_TCHFPair,gSACCH_FT_T2Pair);
const CompleteMapping GSM::gTCHF_T3(gFACCH_TCHFPair,gSACCH_FT_T3Pair);
const CompleteMapping GSM::gTCHF_T4(gFACCH_TCHFPair,gSACCH_FT_T4Pair);
const CompleteMapping GSM::gTCHF_T5(gFACCH_TCHFPair,gSACCH_FT_T5Pair);
const CompleteMapping GSM::gTCHF_T6(gFACCH_TCHFPair,gSACCH_FT_T6Pair);
const CompleteMapping GSM::gTCHF_T7(gFACCH_TCHFPair,gSACCH_FT_T7Pair);

View File

@ -0,0 +1,358 @@
/**@file Common-use GSM declarations, most from the GSM 04.xx and 05.xx series. */
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Public License.
* See the COPYING file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GSMTDMA_H
#define GSMTDMA_H
#include "GSMCommon.h"
namespace GSM {
/**
A description of a channel's multiplexing pattern.
From GSM 05.02 Clause 7.
This object encodes a line from tables 1-4 in the spec.
The columns of interest in this encoding are:
- 1, Channel Designation
- 2, Subchannel
- 3, Direction
- 4, Allowable Time Slot Assignments
- 5, Allowable RF Channel Assignments
- 7, Repeat Length in TDMA Frames
- 8, Interleaved Block TDMA Frame Mapping
Col 6, Burst Type, is implied by 1 & 2 and encoded into the transcevier source code.
*/
class TDMAMapping {
public:
/// The longest "repeat length" of any channel we support is 104 for the SACCH/TF.
static const unsigned mMaxRepeatLength = 104;
private:
TypeAndOffset mTypeAndOffset; ///< col 1, 2, encoded as per GSM 04.08 10.5.2.5
bool mDownlink; ///< col 3, true for downlink channels
bool mUplink; ///< col 3, true for uplink channels
char mAllowedSlots; ///< col 4, an 8-bit mask
bool mC0Only; ///< col 5, true if channel is limited to C0
unsigned mRepeatLength; ///< col 7
unsigned mNumFrames; ///< number of occupied frames in col 8
const unsigned *mFrameMapping; ///< col 8
unsigned mReverseMapping[mMaxRepeatLength]; ///< index reversal of mapping, -1 means unused
public:
/**
Construct a TDMAMapping, encoding one line of GSM 05.02 Clause 7 Tables 1-4.
@param wTypeAndOffset Encoding of "Channel designnation". See GSM 04.08 10.5.2.5.
@param wDownlink True for downlink and bidirectional hannels
@param wUplink True for uplink and bidirectional channels
@param wRepeatLength "Repeat Length in TDMA Frames"
@param wNumFrames Number of occupied TDMA frames in frame mapping.
@param wFrameMapping "Interleaved Block TDMA Frame Mapping" -- MUST PERSIST!!
*/
TDMAMapping(TypeAndOffset wTypeAndOffset,
bool wDownlink, bool wUplink, char wAllowedSlots, bool wC0Only,
unsigned wRepeatLength, unsigned wNumFrames, const unsigned *wFrameMapping);
/** Given a count of frames sent, return the corresponding frame number. */
unsigned frameMapping(unsigned count) const
{ return mFrameMapping[count % mNumFrames]; }
/** Given a frame number, return the corresponding count, modulo patten length. */
int reverseMapping(unsigned FN) const
{ return mReverseMapping[FN % mRepeatLength]; }
/**@name Simple accessors. */
//@{
unsigned numFrames() const { return mNumFrames; }
unsigned repeatLength() const { return mRepeatLength; }
TypeAndOffset typeAndOffset() const { return mTypeAndOffset; }
bool uplink() const { return mUplink; }
bool downlink() const { return mDownlink; }
bool C0Only() const { return mC0Only; }
//@}
///< Return true if this channel is allowed on this slot.
bool allowedSlot(unsigned slot) const
{ return mAllowedSlots & (1<<slot); }
};
/**@name Mux parameters for standard channels, from GSM 05.03 Clause 7 Tables 1-4. */
//@{
/**@name Beacon channels */
//@{
extern const TDMAMapping gFCCHMapping; ///< GSM 05.02 Clause 7 Table 3 Line 1 B0-B4
extern const TDMAMapping gSCHMapping; ///< GSM 05.02 Clause 7 Table 3 Line 2 B0-B4
extern const TDMAMapping gBCCHMapping; ///< GSM 05.02 Clause 7 Table 3 Line 3
/// GSM 05.02 Clause 7 Table 3 Line 7 B0-B50, excluding C-V SDCCH parts (SDCCH/4 and SCCH/C4)
extern const TDMAMapping gRACHC5Mapping;
extern const TDMAMapping gCCCH_0Mapping; ///< GSM 05.02 Clause 7 Table 3 Line 5 B0
extern const TDMAMapping gCCCH_1Mapping; ///< GSM 05.02 Clause 7 Table 3 Line 5 B1
extern const TDMAMapping gCCCH_2Mapping; ///< GSM 05.02 Clause 7 Table 3 Line 5 B2
extern const TDMAMapping gCCCH_3Mapping; ///< GSM 05.02 Clause 7 Table 3 Line 5 B3
extern const TDMAMapping gCCCH_4Mapping; ///< GSM 05.02 Clause 7 Table 3 Line 5 B4
extern const TDMAMapping gCCCH_5Mapping; ///< GSM 05.02 Clause 7 Table 3 Line 5 B5
extern const TDMAMapping gCCCH_6Mapping; ///< GSM 05.02 Clause 7 Table 3 Line 5 B6
extern const TDMAMapping gCCCH_7Mapping; ///< GSM 05.02 Clause 7 Table 3 Line 5 B7
extern const TDMAMapping gCCCH_8Mapping; ///< GSM 05.02 Clause 7 Table 3 Line 5 B8
//@}
/**@name SDCCH */
//@{
///@name For Combination V
//@{
extern const TDMAMapping gSDCCH_4_0DMapping; ///< GSM 05.02 Clause 7 Table 3 Line 10/0D
extern const TDMAMapping gSDCCH_4_0UMapping; ///< GSM 05.02 Clause 7 Table 3 Line 10/0U
extern const TDMAMapping gSDCCH_4_1DMapping;
extern const TDMAMapping gSDCCH_4_1UMapping;
extern const TDMAMapping gSDCCH_4_2DMapping;
extern const TDMAMapping gSDCCH_4_2UMapping;
extern const TDMAMapping gSDCCH_4_3DMapping;
extern const TDMAMapping gSDCCH_4_3UMapping;
//@}
///@name For Combination VII
//@{
extern const TDMAMapping gSDCCH_8_0DMapping;
extern const TDMAMapping gSDCCH_8_0UMapping;
extern const TDMAMapping gSDCCH_8_1DMapping;
extern const TDMAMapping gSDCCH_8_1UMapping;
extern const TDMAMapping gSDCCH_8_2DMapping;
extern const TDMAMapping gSDCCH_8_2UMapping;
extern const TDMAMapping gSDCCH_8_3DMapping;
extern const TDMAMapping gSDCCH_8_3UMapping;
extern const TDMAMapping gSDCCH_8_4DMapping;
extern const TDMAMapping gSDCCH_8_4UMapping;
extern const TDMAMapping gSDCCH_8_5DMapping;
extern const TDMAMapping gSDCCH_8_5UMapping;
extern const TDMAMapping gSDCCH_8_6DMapping;
extern const TDMAMapping gSDCCH_8_6UMapping;
extern const TDMAMapping gSDCCH_8_7DMapping;
extern const TDMAMapping gSDCCH_8_7UMapping;
//@}
//@}
/**@name SACCH */
//@{
/**name SACCH for SDCCH */
//@{
///@name For Combination V
//@{
extern const TDMAMapping gSACCH_C4_0DMapping;
extern const TDMAMapping gSACCH_C4_0UMapping;
extern const TDMAMapping gSACCH_C4_1DMapping;
extern const TDMAMapping gSACCH_C4_1UMapping;
extern const TDMAMapping gSACCH_C4_2DMapping;
extern const TDMAMapping gSACCH_C4_2UMapping;
extern const TDMAMapping gSACCH_C4_3DMapping;
extern const TDMAMapping gSACCH_C4_3UMapping;
//@}
///@name For Combination VII
//@{
extern const TDMAMapping gSACCH_C8_0DMapping;
extern const TDMAMapping gSACCH_C8_0UMapping;
extern const TDMAMapping gSACCH_C8_1DMapping;
extern const TDMAMapping gSACCH_C8_1UMapping;
extern const TDMAMapping gSACCH_C8_2DMapping;
extern const TDMAMapping gSACCH_C8_2UMapping;
extern const TDMAMapping gSACCH_C8_3DMapping;
extern const TDMAMapping gSACCH_C8_3UMapping;
extern const TDMAMapping gSACCH_C8_4DMapping;
extern const TDMAMapping gSACCH_C8_4UMapping;
extern const TDMAMapping gSACCH_C8_5DMapping;
extern const TDMAMapping gSACCH_C8_5UMapping;
extern const TDMAMapping gSACCH_C8_6DMapping;
extern const TDMAMapping gSACCH_C8_6UMapping;
extern const TDMAMapping gSACCH_C8_7DMapping;
extern const TDMAMapping gSACCH_C8_7UMapping;
//@}
//@}
/**@name SACCH for TCH/F on different timeslots. */
//@{
extern const TDMAMapping gSACCH_TF_T0Mapping;
extern const TDMAMapping gSACCH_TF_T1Mapping;
extern const TDMAMapping gSACCH_TF_T2Mapping;
extern const TDMAMapping gSACCH_TF_T3Mapping;
extern const TDMAMapping gSACCH_TF_T4Mapping;
extern const TDMAMapping gSACCH_TF_T5Mapping;
extern const TDMAMapping gSACCH_TF_T6Mapping;
extern const TDMAMapping gSACCH_TF_T7Mapping;
//@}
//@}
/**name FACCH+TCH/F placement */
//@{
extern const TDMAMapping gFACCH_TCHFMapping;
//@}
/**@name Test fixtures. */
extern const TDMAMapping gLoopbackTestFullMapping;
extern const TDMAMapping gLoopbackTestHalfUMapping;
extern const TDMAMapping gLoopbackTestHalfDMapping;
//@}
/** Combined uplink/downlink information. */
class MappingPair {
private:
const TDMAMapping& mDownlink;
const TDMAMapping& mUplink;
public:
MappingPair(const TDMAMapping& wDownlink, const TDMAMapping& wUplink)
:mDownlink(wDownlink), mUplink(wUplink)
{}
MappingPair(const TDMAMapping& wMapping)
:mDownlink(wMapping), mUplink(wMapping)
{}
const TDMAMapping& downlink() const { return mDownlink; }
const TDMAMapping& uplink() const { return mUplink; }
};
/**@name Common placement pairs. */
//@{
/**@ SDCCH placement pairs. */
//@{
extern const MappingPair gSDCCH_4_0Pair;
extern const MappingPair gSDCCH_4_1Pair;
extern const MappingPair gSDCCH_4_2Pair;
extern const MappingPair gSDCCH_4_3Pair;
extern const MappingPair gSDCCH_8_0Pair;
extern const MappingPair gSDCCH_8_1Pair;
extern const MappingPair gSDCCH_8_2Pair;
extern const MappingPair gSDCCH_8_3Pair;
extern const MappingPair gSDCCH_8_4Pair;
extern const MappingPair gSDCCH_8_5Pair;
extern const MappingPair gSDCCH_8_6Pair;
extern const MappingPair gSDCCH_8_7Pair;
//@}
/**@ SACCH-for-SDCCH placement pairs. */
//@{
extern const MappingPair gSACCH_C4_0Pair;
extern const MappingPair gSACCH_C4_1Pair;
extern const MappingPair gSACCH_C4_2Pair;
extern const MappingPair gSACCH_C4_3Pair;
extern const MappingPair gSACCH_C8_0Pair;
extern const MappingPair gSACCH_C8_1Pair;
extern const MappingPair gSACCH_C8_2Pair;
extern const MappingPair gSACCH_C8_3Pair;
extern const MappingPair gSACCH_C8_4Pair;
extern const MappingPair gSACCH_C8_5Pair;
extern const MappingPair gSACCH_C8_6Pair;
extern const MappingPair gSACCH_C8_7Pair;
//@}
/**@name Traffic channels. */
//@{
extern const MappingPair gFACCH_TCHFPair;
extern const MappingPair gSACCH_FT_T0Pair;
extern const MappingPair gSACCH_FT_T1Pair;
extern const MappingPair gSACCH_FT_T2Pair;
extern const MappingPair gSACCH_FT_T3Pair;
extern const MappingPair gSACCH_FT_T4Pair;
extern const MappingPair gSACCH_FT_T5Pair;
extern const MappingPair gSACCH_FT_T6Pair;
extern const MappingPair gSACCH_FT_T7Pair;
//@}
//@}
/** A CompleteMapping includes uplink, downlink and the SACCH. */
class CompleteMapping {
private:
const MappingPair& mLCH;
const MappingPair& mSACCH;
public:
CompleteMapping(const MappingPair& wLCH, const MappingPair& wSACCH)
:mLCH(wLCH), mSACCH(wSACCH)
{}
const MappingPair& LCH() const { return mLCH; }
const MappingPair& SACCH() const { return mSACCH; }
};
/**@name Complete placements for common channel types. */
//@{
/**@name SDCCH/4 */
//@{
extern const CompleteMapping gSDCCH_4_0;
extern const CompleteMapping gSDCCH_4_1;
extern const CompleteMapping gSDCCH_4_2;
extern const CompleteMapping gSDCCH_4_3;
//@}
/**@name SDCCH/8 */
//@{
extern const CompleteMapping gSDCCH_8_0;
extern const CompleteMapping gSDCCH_8_1;
extern const CompleteMapping gSDCCH_8_2;
extern const CompleteMapping gSDCCH_8_3;
extern const CompleteMapping gSDCCH_8_4;
extern const CompleteMapping gSDCCH_8_5;
extern const CompleteMapping gSDCCH_8_6;
extern const CompleteMapping gSDCCH_8_7;
//@}
/**@name TCH/F on different slots. */
//@{
extern const CompleteMapping gTCHF_T0;
extern const CompleteMapping gTCHF_T1;
extern const CompleteMapping gTCHF_T2;
extern const CompleteMapping gTCHF_T3;
extern const CompleteMapping gTCHF_T4;
extern const CompleteMapping gTCHF_T5;
extern const CompleteMapping gTCHF_T6;
extern const CompleteMapping gTCHF_T7;
//@}
//@}
}; // namespace GSM
#endif
// vim: ts=4 sw=4

View File

@ -0,0 +1,49 @@
#
# Copyright 2001,2002,2004,2005,2006,2007,2008 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
include $(top_srcdir)/Makefile.common
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
noinst_LTLIBRARIES = libopenbtsdecoder.la
libopenbtsdecoder_la_SOURCES = \
BitVector.cpp \
GSM610Tables.cpp \
GSMCommon.cpp \
GSML1FEC.cpp \
GSMTDMA.cpp \
Threads.cpp \
Timeval.cpp
noinst_HEADERS = \
Assert.h \
BitVector.h \
GSM610Tables.h \
GSMCommon.h \
GSML1FEC.h \
GSMTDMA.h \
RxBurst.h \
Threads.h \
Timeval.h \
Vector.h \
VocoderFrame.h

View File

@ -0,0 +1,69 @@
#ifndef _RXBURST_H
#define _RXBURST_H
#include "GSMCommon.h"
#include "BitVector.h"
namespace GSM {
/**@name Positions of stealing bits within a normal burst, GSM 05.03 3.1.4. */
//@{
static const unsigned gHlIndex = 60; ///< index of first stealing bit, GSM 05.03 3.1.4
static const unsigned gHuIndex = 87; ///< index of second stealing bit, GSM 05.03 3.1.4
//@}
static const unsigned gSlotLen = 148; ///< number of symbols per slot, not counting guard periods
/**
Class to represent one timeslot of channel bits with soft encoding.
*/
class RxBurst : public SoftVector {
private:
Time mTime; ///< timeslot and frame on which this was received
// float mTimingError; ///< Timing error in symbol steps, <0 means early.
// float mRSSI; ///< RSSI estimate associated with the slot, dB wrt full scale.
public:
/** Wrap an RxBurst around an existing float array. */
RxBurst(float* wData, const Time &wTime)
:SoftVector(wData,gSlotLen),mTime(wTime)
// mTimingError(wTimingError),mRSSI(wRSSI)
{ }
Time time() const { return mTime; }
void time(const Time& wTime) { mTime = wTime; }
// float RSSI() const { return mRSSI; }
// float timingError() const { return mTimingError; }
/** Return a SoftVector alias to the first data field. */
const SoftVector data1() const { return segment(3, 57); }
/** Return a SoftVector alias to the second data field. */
const SoftVector data2() const { return segment(88, 57); }
/** Return upper stealing bit. */
bool Hu() const { return bit(gHuIndex); }
/** Return lower stealing bit. */
bool Hl() const { return bit(gHlIndex); }
// friend std::ostream& operator<<(std::ostream& os, const RxBurst& ts);
};
// std::ostream& operator<<(std::ostream& os, const RxBurst& ts){
// os << "time=" << ts.time();
// os << " data=(" << (const SoftVector&)ts << ")" ;
// return os;
// }
}
#endif

View File

@ -0,0 +1,106 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Public License.
* See the COPYING file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Threads.h"
#include "Timeval.h"
using namespace std;
Mutex gStreamLock; ///< Global lock to control access to cout and cerr.
void lockCout()
{
gStreamLock.lock();
Timeval entryTime;
cout << entryTime << " " << pthread_self() << ": ";
}
void unlockCout()
{
cout << dec << endl << flush;
gStreamLock.unlock();
}
void lockCerr()
{
gStreamLock.lock();
Timeval entryTime;
cerr << entryTime << " " << pthread_self() << ": ";
}
void unlockCerr()
{
cerr << dec << endl << flush;
gStreamLock.unlock();
}
Mutex::Mutex()
{
assert(!pthread_mutexattr_init(&mAttribs));
assert(!pthread_mutexattr_settype(&mAttribs,PTHREAD_MUTEX_RECURSIVE));
assert(!pthread_mutex_init(&mMutex,&mAttribs));
}
Mutex::~Mutex()
{
pthread_mutex_destroy(&mMutex);
assert(!pthread_mutexattr_destroy(&mAttribs));
}
/** Block for the signal up to the cancellation timeout. */
void Signal::wait(Mutex& wMutex, unsigned timeout) const
{
struct timespec waitTime = Timeval(timeout).timespec();
// FIXME -- With -O3 optimzation in OS X this doesn't block. See bug #320.
pthread_cond_timedwait(&mSignal,&wMutex.mMutex,&waitTime);
}
void Thread::start(void *(*task)(void*), void *arg)
{
assert(mThread==((pthread_t)0));
assert(!pthread_attr_init(&mAttrib));
assert(!pthread_attr_setstacksize(&mAttrib, mStackSize));
assert(!pthread_create(&mThread, &mAttrib, task, arg));
}
// vim: ts=4 sw=4

View File

@ -0,0 +1,150 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Public License.
* See the COPYING file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef THREADS_H
#define THREADS_H
#include <pthread.h>
#include <iostream>
#include "Assert.h"
class Mutex;
/**@name Multithreaded access for standard streams. */
//@{
/**@name Functions for gStreamLock. */
//@{
extern Mutex gStreamLock; ///< global lock for cout and cerr
void lockCerr(); ///< call prior to writing cerr
void unlockCerr(); ///< call after writing cerr
void lockCout(); ///< call prior to writing cout
void unlockCout(); ///< call after writing cout
//@}
/**@name Macros for standard messages. */
//@{
#define COUT(text) { lockCout(); std::cout << text; unlockCout(); }
#define CERR(text) { lockCerr(); std::cerr << __FILE__ << ":" << __LINE__ << ": " << text; unlockCerr(); }
#ifdef NDEBUG
#define DCOUT(text) {}
#define OBJDCOUT(text) {}
#else
#define DCOUT(text) { COUT(__FILE__ << ":" << __LINE__ << " " << text); }
#define OBJDCOUT(text) { DCOUT(this << " " << text); }
#endif
//@}
//@}
/**@defgroup C++ wrappers for pthread mechanisms. */
//@{
/** A class for recursive mutexes based on pthread_mutex. */
class Mutex {
private:
pthread_mutex_t mMutex;
pthread_mutexattr_t mAttribs;
public:
Mutex();
~Mutex();
void lock() { pthread_mutex_lock(&mMutex); }
void unlock() { pthread_mutex_unlock(&mMutex); }
friend class Signal;
};
/** A C++ interthread signal based on pthread condition variables. */
class Signal {
private:
mutable pthread_cond_t mSignal;
public:
Signal() { assert(!pthread_cond_init(&mSignal,NULL)); }
~Signal() { pthread_cond_destroy(&mSignal); }
/** Block for the signal up to the cancellation timeout. */
void wait(Mutex& wMutex, unsigned timeout=1000000000) const;
void signal() { pthread_cond_signal(&mSignal); }
void broadcast() { pthread_cond_broadcast(&mSignal); }
};
#define START_THREAD(thread,function,argument) \
thread.start((void *(*)(void*))function, (void*)argument);
/** A C++ wrapper for pthread threads. */
class Thread {
private:
pthread_t mThread;
pthread_attr_t mAttrib;
const static size_t mStackSize=4*65536;
public:
/** Create a thread in a non-running state. */
Thread():mThread((pthread_t)0) { }
/**
Destroy the Thread.
It should be stopped and joined.
*/
~Thread() { assert(!pthread_attr_destroy(&mAttrib)); }
/** Start the thread on a task. */
void start(void *(*task)(void*), void *arg);
/** Join a thread that will stop on its own. */
void join() { assert(!pthread_join(mThread,NULL)); }
};
#endif
// vim: ts=4 sw=4

View File

@ -0,0 +1,93 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Public License.
* See the COPYING file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Timeval.h"
using namespace std;
void Timeval::future(unsigned offset)
{
now();
unsigned sec = offset/1000;
unsigned msec = offset%1000;
mTimeval.tv_usec += msec*1000;
mTimeval.tv_sec += sec;
if (mTimeval.tv_usec>1000000) {
mTimeval.tv_usec -= 1000000;
mTimeval.tv_sec += 1;
}
}
struct timespec Timeval::timespec() const
{
struct timespec retVal;
retVal.tv_sec = mTimeval.tv_sec;
retVal.tv_nsec = 1000 * (long)mTimeval.tv_usec;
return retVal;
}
bool Timeval::passed() const
{
Timeval nowTime;
if (nowTime.mTimeval.tv_sec < mTimeval.tv_sec) return false;
if (nowTime.mTimeval.tv_sec > mTimeval.tv_sec) return true;
if (nowTime.mTimeval.tv_usec > mTimeval.tv_usec) return true;
return false;
}
double Timeval::seconds() const
{
return ((double)mTimeval.tv_sec) + 1e-6*((double)mTimeval.tv_usec);
}
long Timeval::delta(const Timeval& other) const
{
long deltaS = other.sec() - sec();
long deltaUs = other.usec() - usec();
return 1000*deltaS + deltaUs/1000;
}
ostream& operator<<(ostream& os, const Timeval& tv)
{
os.setf( ios::fixed, ios::floatfield );
os << tv.seconds();
return os;
}
ostream& operator<<(ostream& os, const struct timespec& ts)
{
os << ts.tv_sec << "," << ts.tv_nsec;
return os;
}
// vim: ts=4 sw=4

View File

@ -0,0 +1,96 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Public License.
* See the COPYING file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TIMEVAL_H
#define TIMEVAL_H
#include "sys/time.h"
#include <iostream>
inline void msleep(long v) { usleep((v+500)/1000); }
/** A C++ wrapper for struct timeval. */
class Timeval {
private:
struct timeval mTimeval;
public:
/** Set the value to gettimeofday. */
void now() { gettimeofday(&mTimeval,NULL); }
/** Set the value to gettimeofday plus an offset. */
void future(unsigned offset);
//@{
Timeval(unsigned sec, unsigned usec)
{
mTimeval.tv_sec = sec;
mTimeval.tv_usec = usec;
}
Timeval(const struct timeval& wTimeval)
:mTimeval(wTimeval)
{}
/**
Create a Timeval offset into the future.
@param offset milliseconds
*/
Timeval(unsigned offset=0) { future(offset); }
//@}
/** Convert to a struct timespec. */
struct timespec timespec() const;
/** Return total seconds. */
double seconds() const;
uint32_t sec() const { return mTimeval.tv_sec; }
uint32_t usec() const { return mTimeval.tv_usec; }
/** Return differnce from other (other-self), in ms. */
long delta(const Timeval& other) const;
/** Elapsed time in ms. */
long elapsed() const { return delta(Timeval()); }
/** Remaining time in ms. */
long remaining() const { return -elapsed(); }
/** Return true if the time has passed, as per gettimeofday. */
bool passed() const;
};
std::ostream& operator<<(std::ostream& os, const Timeval&);
std::ostream& operator<<(std::ostream& os, const struct timespec&);
#endif
// vim: ts=4 sw=4

View File

@ -0,0 +1,257 @@
/**@file Simplified Vector template with aliases. */
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Public License.
* See the COPYING file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef VECTOR_H
#define VECTOR_H
#include <string.h>
#include <iostream>
#include "Assert.h"
/**
A simplified Vector template with aliases.
Unlike std::vector, this class does not support dynamic resizing.
Unlike std::vector, this class does support "aliases" and subvectors.
*/
template <class T> class Vector {
// TODO -- Replace memcpy calls with for-loops.
public:
/**@name Iterator types. */
//@{
typedef T* iterator;
typedef const T* const_iterator;
//@}
protected:
T* mData; ///< allocated data block, if any
T* mStart; ///< start of useful data
T* mEnd; ///< end of useful data + 1
public:
/** Return the size of the Vector. */
size_t size() const
{
assert(mStart>=mData);
assert(mEnd>=mStart);
return mEnd - mStart;
}
/** Return size in bytes. */
size_t bytes() const { return size()*sizeof(T); }
/** Change the size of the Vector, discarding content. */
void resize(size_t newSize)
{
if (mData!=NULL) delete[] mData;
if (newSize==0) mData=NULL;
else mData = new T[newSize];
mStart = mData;
mEnd = mStart + newSize;
}
/** Release memory and clear pointers. */
void clear() { resize(0); }
/** Copy data from another vector. */
void clone(const Vector<T>& other)
{
resize(other.size());
memcpy(mData,other.mStart,other.bytes());
}
//@{
/** Build an empty Vector of a given size. */
Vector(size_t wSize=0):mData(NULL) { resize(wSize); }
/** Build a Vector by shifting the data block. */
Vector(Vector<T>& other)
:mData(other.mData),mStart(other.mStart),mEnd(other.mEnd)
{ other.mData=NULL; }
/** Build a Vector by copying another. */
Vector(const Vector<T>& other):mData(NULL) { clone(other); }
/** Build a Vector with explicit values. */
Vector(T* wData, T* wStart, T* wEnd)
:mData(wData),mStart(wStart),mEnd(wEnd)
{ }
/** Build a vector from an existing block, NOT to be deleted upon destruction. */
Vector(T* wStart, size_t span)
:mData(NULL),mStart(wStart),mEnd(wStart+span)
{ }
/** Build a Vector by concatenation. */
Vector(const Vector<T>& other1, const Vector<T>& other2)
:mData(NULL)
{
resize(other1.size()+other2.size());
memcpy(mStart, other1.mStart, other1.bytes());
memcpy(mStart+other1.size(), other2.mStart, other2.bytes());
}
//@}
/** Destroy a Vector, deleting held memory. */
~Vector() { clear(); }
//@{
/** Assign from another Vector, shifting ownership. */
void operator=(Vector<T>& other)
{
clear();
mData=other.mData;
mStart=other.mStart;
mEnd=other.mEnd;
other.mData=NULL;
}
/** Assign from another Vector, copying. */
void operator=(const Vector<T>& other) { clone(other); }
//@}
//@{
/** Return an alias to a segment of this Vector. */
Vector<T> segment(size_t start, size_t span)
{
T* wStart = mStart + start;
T* wEnd = wStart + span;
assert(wEnd<=mEnd);
return Vector<T>(NULL,wStart,wEnd);
}
/** Return an alias to a segment of this Vector. */
const Vector<T> segment(size_t start, size_t span) const
{
T* wStart = mStart + start;
T* wEnd = wStart + span;
assert(wEnd<=mEnd);
return Vector<T>(NULL,wStart,wEnd);
}
Vector<T> head(size_t span) { return segment(0,span); }
const Vector<T> head(size_t span) const { return segment(0,span); }
Vector<T> tail(size_t start) { return segment(start,size()-start); }
const Vector<T> tail(size_t start) const { return segment(start,size()-start); }
/**
Copy part of this Vector to a segment of another Vector.
@param other The other vector.
@param start The start point in the other vector.
@param span The number of elements to copy.
*/
void copyToSegment(Vector<T>& other, size_t start, size_t span) const
{
T* base = other.mStart + start;
assert(base+span<=other.mEnd);
assert(mStart+span<=mEnd);
memcpy(base,mStart,span*sizeof(T));
}
/** Copy all of this Vector to a segment of another Vector. */
void copyToSegment(Vector<T>& other, size_t start=0) const { copyToSegment(other,start,size()); }
void copyTo(Vector<T>& other) const { copyToSegment(other,0,size()); }
/**
Copy a segment of this vector into another.
@param other The other vector (to copt into starting at 0.)
@param start The start point in this vector.
@param span The number of elements to copy.
*/
void segmentCopyTo(Vector<T>& other, size_t start, size_t span)
{
T* base = mStart + start;
assert(base+span<=mEnd);
assert(other.mStart+span<=other.mEnd);
memcpy(other.mStart,base,span*sizeof(T));
}
void fill(const T& val)
{
T* dp=mStart;
while (dp<mEnd) *dp++=val;
}
//@}
//@{
T& operator[](size_t index)
{
assert(mStart+index<mEnd);
return mStart[index];
}
const T& operator[](size_t index) const
{
assert(mStart+index<mEnd);
return mStart[index];
}
const T* begin() const { return mStart; }
T* begin() { return mStart; }
const T* end() const { return mEnd; }
T* end() { return mEnd; }
//@}
};
/** Basic print operator for Vector objects. */
template <class T>
std::ostream& operator<<(std::ostream& os, const Vector<T>& v)
{
for (unsigned i=0; i<v.size(); i++) os << v[i] << " ";
return os;
}
#endif
// vim: ts=4 sw=4

View File

@ -0,0 +1,25 @@
#ifndef _VOCODERFRAME_H
#define _VOCODERFRAME_H
#include "BitVector.h"
//#include "GSMCommon.h"
class VocoderFrame : public BitVector {
public:
VocoderFrame()
:BitVector(264)
{ fillField(0,0x0d,4); }
/** Construct by unpacking a char[33]. */
VocoderFrame(const unsigned char *src)
:BitVector(264)
{ unpack(src); }
BitVector payload() { return tail(4); }
const BitVector payload() const { return tail(4); }
};
#endif