From 8d2bc49fb9e0c9a5fbd75aa3cad207608e72bf99 Mon Sep 17 00:00:00 2001
From: Piotr Krysik <perper@o2.pl>
Date: Tue, 30 Jun 2009 23:03:33 +0200
Subject: moved gsm-receiver into directory - preparation to move to airprobe

---
 gsm-receiver/src/lib/decoder/openbtsstuff/AUTHORS  | 173 +++++++
 gsm-receiver/src/lib/decoder/openbtsstuff/Assert.h |  49 ++
 .../src/lib/decoder/openbtsstuff/BitVector.cpp     | 513 ++++++++++++++++++++
 .../src/lib/decoder/openbtsstuff/BitVector.h       | 427 ++++++++++++++++
 .../src/lib/decoder/openbtsstuff/GSM610Tables.cpp  | 492 +++++++++++++++++++
 .../src/lib/decoder/openbtsstuff/GSM610Tables.h    |  37 ++
 .../src/lib/decoder/openbtsstuff/GSMCommon.cpp     | 315 ++++++++++++
 .../src/lib/decoder/openbtsstuff/GSMCommon.h       | 537 +++++++++++++++++++++
 .../src/lib/decoder/openbtsstuff/GSML1FEC.cpp      | 256 ++++++++++
 .../src/lib/decoder/openbtsstuff/GSML1FEC.h        | 146 ++++++
 .../src/lib/decoder/openbtsstuff/GSMTDMA.cpp       | 337 +++++++++++++
 .../src/lib/decoder/openbtsstuff/GSMTDMA.h         | 358 ++++++++++++++
 .../src/lib/decoder/openbtsstuff/Makefile.am       |  49 ++
 .../src/lib/decoder/openbtsstuff/RxBurst.h         |  69 +++
 .../src/lib/decoder/openbtsstuff/Threads.cpp       | 106 ++++
 .../src/lib/decoder/openbtsstuff/Threads.h         | 150 ++++++
 .../src/lib/decoder/openbtsstuff/Timeval.cpp       |  93 ++++
 .../src/lib/decoder/openbtsstuff/Timeval.h         |  96 ++++
 gsm-receiver/src/lib/decoder/openbtsstuff/Vector.h | 257 ++++++++++
 .../src/lib/decoder/openbtsstuff/VocoderFrame.h    |  25 +
 20 files changed, 4485 insertions(+)
 create mode 100644 gsm-receiver/src/lib/decoder/openbtsstuff/AUTHORS
 create mode 100644 gsm-receiver/src/lib/decoder/openbtsstuff/Assert.h
 create mode 100644 gsm-receiver/src/lib/decoder/openbtsstuff/BitVector.cpp
 create mode 100644 gsm-receiver/src/lib/decoder/openbtsstuff/BitVector.h
 create mode 100644 gsm-receiver/src/lib/decoder/openbtsstuff/GSM610Tables.cpp
 create mode 100644 gsm-receiver/src/lib/decoder/openbtsstuff/GSM610Tables.h
 create mode 100644 gsm-receiver/src/lib/decoder/openbtsstuff/GSMCommon.cpp
 create mode 100644 gsm-receiver/src/lib/decoder/openbtsstuff/GSMCommon.h
 create mode 100644 gsm-receiver/src/lib/decoder/openbtsstuff/GSML1FEC.cpp
 create mode 100644 gsm-receiver/src/lib/decoder/openbtsstuff/GSML1FEC.h
 create mode 100644 gsm-receiver/src/lib/decoder/openbtsstuff/GSMTDMA.cpp
 create mode 100644 gsm-receiver/src/lib/decoder/openbtsstuff/GSMTDMA.h
 create mode 100644 gsm-receiver/src/lib/decoder/openbtsstuff/Makefile.am
 create mode 100644 gsm-receiver/src/lib/decoder/openbtsstuff/RxBurst.h
 create mode 100644 gsm-receiver/src/lib/decoder/openbtsstuff/Threads.cpp
 create mode 100644 gsm-receiver/src/lib/decoder/openbtsstuff/Threads.h
 create mode 100644 gsm-receiver/src/lib/decoder/openbtsstuff/Timeval.cpp
 create mode 100644 gsm-receiver/src/lib/decoder/openbtsstuff/Timeval.h
 create mode 100644 gsm-receiver/src/lib/decoder/openbtsstuff/Vector.h
 create mode 100644 gsm-receiver/src/lib/decoder/openbtsstuff/VocoderFrame.h

(limited to 'gsm-receiver/src/lib/decoder/openbtsstuff')

diff --git a/gsm-receiver/src/lib/decoder/openbtsstuff/AUTHORS b/gsm-receiver/src/lib/decoder/openbtsstuff/AUTHORS
new file mode 100644
index 0000000..8075492
--- /dev/null
+++ b/gsm-receiver/src/lib/decoder/openbtsstuff/AUTHORS
@@ -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
diff --git a/gsm-receiver/src/lib/decoder/openbtsstuff/Assert.h b/gsm-receiver/src/lib/decoder/openbtsstuff/Assert.h
new file mode 100644
index 0000000..00ad07d
--- /dev/null
+++ b/gsm-receiver/src/lib/decoder/openbtsstuff/Assert.h
@@ -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
diff --git a/gsm-receiver/src/lib/decoder/openbtsstuff/BitVector.cpp b/gsm-receiver/src/lib/decoder/openbtsstuff/BitVector.cpp
new file mode 100644
index 0000000..89d8d19
--- /dev/null
+++ b/gsm-receiver/src/lib/decoder/openbtsstuff/BitVector.cpp
@@ -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
diff --git a/gsm-receiver/src/lib/decoder/openbtsstuff/BitVector.h b/gsm-receiver/src/lib/decoder/openbtsstuff/BitVector.h
new file mode 100644
index 0000000..3019c2c
--- /dev/null
+++ b/gsm-receiver/src/lib/decoder/openbtsstuff/BitVector.h
@@ -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
diff --git a/gsm-receiver/src/lib/decoder/openbtsstuff/GSM610Tables.cpp b/gsm-receiver/src/lib/decoder/openbtsstuff/GSM610Tables.cpp
new file mode 100644
index 0000000..38f643f
--- /dev/null
+++ b/gsm-receiver/src/lib/decoder/openbtsstuff/GSM610Tables.cpp
@@ -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
+//@}
+};
+
diff --git a/gsm-receiver/src/lib/decoder/openbtsstuff/GSM610Tables.h b/gsm-receiver/src/lib/decoder/openbtsstuff/GSM610Tables.h
new file mode 100644
index 0000000..53a8e1c
--- /dev/null
+++ b/gsm-receiver/src/lib/decoder/openbtsstuff/GSM610Tables.h
@@ -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
diff --git a/gsm-receiver/src/lib/decoder/openbtsstuff/GSMCommon.cpp b/gsm-receiver/src/lib/decoder/openbtsstuff/GSMCommon.cpp
new file mode 100644
index 0000000..0bec812
--- /dev/null
+++ b/gsm-receiver/src/lib/decoder/openbtsstuff/GSMCommon.cpp
@@ -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
diff --git a/gsm-receiver/src/lib/decoder/openbtsstuff/GSMCommon.h b/gsm-receiver/src/lib/decoder/openbtsstuff/GSMCommon.h
new file mode 100644
index 0000000..9dc1c95
--- /dev/null
+++ b/gsm-receiver/src/lib/decoder/openbtsstuff/GSMCommon.h
@@ -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
diff --git a/gsm-receiver/src/lib/decoder/openbtsstuff/GSML1FEC.cpp b/gsm-receiver/src/lib/decoder/openbtsstuff/GSML1FEC.cpp
new file mode 100644
index 0000000..1c99a0f
--- /dev/null
+++ b/gsm-receiver/src/lib/decoder/openbtsstuff/GSML1FEC.cpp
@@ -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
diff --git a/gsm-receiver/src/lib/decoder/openbtsstuff/GSML1FEC.h b/gsm-receiver/src/lib/decoder/openbtsstuff/GSML1FEC.h
new file mode 100644
index 0000000..c367681
--- /dev/null
+++ b/gsm-receiver/src/lib/decoder/openbtsstuff/GSML1FEC.h
@@ -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
diff --git a/gsm-receiver/src/lib/decoder/openbtsstuff/GSMTDMA.cpp b/gsm-receiver/src/lib/decoder/openbtsstuff/GSMTDMA.cpp
new file mode 100644
index 0000000..27ebe0e
--- /dev/null
+++ b/gsm-receiver/src/lib/decoder/openbtsstuff/GSMTDMA.cpp
@@ -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);
+
+
+
diff --git a/gsm-receiver/src/lib/decoder/openbtsstuff/GSMTDMA.h b/gsm-receiver/src/lib/decoder/openbtsstuff/GSMTDMA.h
new file mode 100644
index 0000000..3b55b94
--- /dev/null
+++ b/gsm-receiver/src/lib/decoder/openbtsstuff/GSMTDMA.h
@@ -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
diff --git a/gsm-receiver/src/lib/decoder/openbtsstuff/Makefile.am b/gsm-receiver/src/lib/decoder/openbtsstuff/Makefile.am
new file mode 100644
index 0000000..5a14202
--- /dev/null
+++ b/gsm-receiver/src/lib/decoder/openbtsstuff/Makefile.am
@@ -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
diff --git a/gsm-receiver/src/lib/decoder/openbtsstuff/RxBurst.h b/gsm-receiver/src/lib/decoder/openbtsstuff/RxBurst.h
new file mode 100644
index 0000000..4348fb8
--- /dev/null
+++ b/gsm-receiver/src/lib/decoder/openbtsstuff/RxBurst.h
@@ -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
diff --git a/gsm-receiver/src/lib/decoder/openbtsstuff/Threads.cpp b/gsm-receiver/src/lib/decoder/openbtsstuff/Threads.cpp
new file mode 100644
index 0000000..b97f3fe
--- /dev/null
+++ b/gsm-receiver/src/lib/decoder/openbtsstuff/Threads.cpp
@@ -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
diff --git a/gsm-receiver/src/lib/decoder/openbtsstuff/Threads.h b/gsm-receiver/src/lib/decoder/openbtsstuff/Threads.h
new file mode 100644
index 0000000..14cff04
--- /dev/null
+++ b/gsm-receiver/src/lib/decoder/openbtsstuff/Threads.h
@@ -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
diff --git a/gsm-receiver/src/lib/decoder/openbtsstuff/Timeval.cpp b/gsm-receiver/src/lib/decoder/openbtsstuff/Timeval.cpp
new file mode 100644
index 0000000..e7590cb
--- /dev/null
+++ b/gsm-receiver/src/lib/decoder/openbtsstuff/Timeval.cpp
@@ -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
diff --git a/gsm-receiver/src/lib/decoder/openbtsstuff/Timeval.h b/gsm-receiver/src/lib/decoder/openbtsstuff/Timeval.h
new file mode 100644
index 0000000..44618bc
--- /dev/null
+++ b/gsm-receiver/src/lib/decoder/openbtsstuff/Timeval.h
@@ -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
diff --git a/gsm-receiver/src/lib/decoder/openbtsstuff/Vector.h b/gsm-receiver/src/lib/decoder/openbtsstuff/Vector.h
new file mode 100644
index 0000000..cec278a
--- /dev/null
+++ b/gsm-receiver/src/lib/decoder/openbtsstuff/Vector.h
@@ -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
diff --git a/gsm-receiver/src/lib/decoder/openbtsstuff/VocoderFrame.h b/gsm-receiver/src/lib/decoder/openbtsstuff/VocoderFrame.h
new file mode 100644
index 0000000..c0e51c0
--- /dev/null
+++ b/gsm-receiver/src/lib/decoder/openbtsstuff/VocoderFrame.h
@@ -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
-- 
cgit v1.2.3