aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordburgess <dburgess@19bc5d8c-e614-43d4-8b26-e1612bc8e597>2011-10-12 07:44:40 +0000
committerdburgess <dburgess@19bc5d8c-e614-43d4-8b26-e1612bc8e597>2011-10-12 07:44:40 +0000
commitb3a0ca42db0bd08c58b9370a1398528016e6953f (patch)
tree1e81558498b765f0faac4c8588c18fbc4bfc8dfb
parentec3d77d0eaa12c102893490766557dd4d4efd029 (diff)
Adding in the missing Transceiver52M directory
git-svn-id: http://wush.net/svn/range/software/public/openbts/trunk@2307 19bc5d8c-e614-43d4-8b26-e1612bc8e597
-rw-r--r--Transceiver52M/Complex.h267
-rw-r--r--Transceiver52M/DummyLoad.cpp146
-rw-r--r--Transceiver52M/DummyLoad.h132
-rw-r--r--Transceiver52M/Makefile661
-rw-r--r--Transceiver52M/Makefile.am88
-rw-r--r--Transceiver52M/README35
-rw-r--r--Transceiver52M/README.DFEsymbolspaced14
-rw-r--r--Transceiver52M/README.Talgorithm15
-rw-r--r--Transceiver52M/Transceiver.cpp798
-rw-r--r--Transceiver52M/Transceiver.h207
-rw-r--r--Transceiver52M/USRPDevice.cpp631
-rw-r--r--Transceiver52M/USRPDevice.h261
-rw-r--r--Transceiver52M/USRPping.cpp96
-rw-r--r--Transceiver52M/inband-signaling-usb314
-rw-r--r--Transceiver52M/pulseApproximate.m15
-rw-r--r--Transceiver52M/radioDevice.h115
-rw-r--r--Transceiver52M/radioInterface.cpp315
-rw-r--r--Transceiver52M/radioInterface.h243
-rw-r--r--Transceiver52M/runTransceiver.cpp123
-rw-r--r--Transceiver52M/sigProcLib.cpp1486
-rw-r--r--Transceiver52M/sigProcLib.h386
-rw-r--r--Transceiver52M/sigProcLibTest.cpp168
-rwxr-xr-xTransceiver52M/std_inband.rbfbin0 -> 176507 bytes
23 files changed, 6516 insertions, 0 deletions
diff --git a/Transceiver52M/Complex.h b/Transceiver52M/Complex.h
new file mode 100644
index 0000000..32eb18f
--- /dev/null
+++ b/Transceiver52M/Complex.h
@@ -0,0 +1,267 @@
+/**@file templates for Complex classes
+unlike the built-in complex<> templates, these inline most operations for speed
+*/
+
+/*
+* Copyright 2008 Free Software Foundation, Inc.
+*
+* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
+*
+* This use of this software may be subject to additional restrictions.
+* See the LEGAL file in the main directory for details.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+*/
+
+
+
+
+#ifndef COMPLEXCPP_H
+#define COMPLEXCPP_H
+
+#include <math.h>
+#include <ostream>
+
+
+template<class Real> class Complex {
+
+public:
+
+ Real r, i;
+
+ /**@name constructors */
+ //@{
+ /**@name from real */
+ //@{
+ Complex(Real real, Real imag) {r=real; i=imag;} // x=complex(a,b)
+ Complex(Real real) {r=real; i=0;} // x=complex(a)
+ //@}
+ /**@name from nothing */
+ //@{
+ Complex() {r=(Real)0; i=(Real)0;} // x=complex()
+ //@}
+ /**@name from other complex */
+ //@{
+ Complex(const Complex<float>& z) {r=z.r; i=z.i;} // x=complex(z)
+ Complex(const Complex<double>& z) {r=z.r; i=z.i;} // x=complex(z)
+ Complex(const Complex<long double>& z) {r=z.r; i=z.i;} // x=complex(z)
+ //@}
+ //@}
+
+ /**@name casting up from basic numeric types */
+ //@{
+ Complex& operator=(char a) { r=(Real)a; i=(Real)0; return *this; }
+ Complex& operator=(int a) { r=(Real)a; i=(Real)0; return *this; }
+ Complex& operator=(long int a) { r=(Real)a; i=(Real)0; return *this; }
+ Complex& operator=(short a) { r=(Real)a; i=(Real)0; return *this; }
+ Complex& operator=(float a) { r=(Real)a; i=(Real)0; return *this; }
+ Complex& operator=(double a) { r=(Real)a; i=(Real)0; return *this; }
+ Complex& operator=(long double a) { r=(Real)a; i=(Real)0; return *this; }
+ //@}
+
+ /**@name arithmetic */
+ //@{
+ /**@ binary operators */
+ //@{
+ Complex operator+(const Complex<Real>& a) const { return Complex<Real>(r+a.r, i+a.i); }
+ Complex operator+(Real a) const { return Complex<Real>(r+a,i); }
+ Complex operator-(const Complex<Real>& a) const { return Complex<Real>(r-a.r, i-a.i); }
+ Complex operator-(Real a) const { return Complex<Real>(r-a,i); }
+ Complex operator*(const Complex<Real>& a) const { return Complex<Real>(r*a.r-i*a.i, r*a.i+i*a.r); }
+ Complex operator*(Real a) const { return Complex<Real>(r*a, i*a); }
+ Complex operator/(const Complex<Real>& a) const { return operator*(a.inv()); }
+ Complex operator/(Real a) const { return Complex<Real>(r/a, i/a); }
+ //@}
+ /*@name component-wise product */
+ //@{
+ Complex operator&(const Complex<Real>& a) const { return Complex<Real>(r*a.r, i*a.i); }
+ //@}
+ /*@name inplace operations */
+ //@{
+ Complex& operator+=(const Complex<Real>&);
+ Complex& operator-=(const Complex<Real>&);
+ Complex& operator*=(const Complex<Real>&);
+ Complex& operator/=(const Complex<Real>&);
+ Complex& operator+=(Real);
+ Complex& operator-=(Real);
+ Complex& operator*=(Real);
+ Complex& operator/=(Real);
+ //@}
+ //@}
+
+ /**@name comparisons */
+ //@{
+ bool operator==(const Complex<Real>& a) const { return ((i==a.i)&&(r==a.r)); }
+ bool operator!=(const Complex<Real>& a) const { return ((i!=a.i)||(r!=a.r)); }
+ bool operator<(const Complex<Real>& a) const { return norm2()<a.norm2(); }
+ bool operator>(const Complex<Real>& a) const { return norm2()>a.norm2(); }
+ //@}
+
+ /// reciprocation
+ Complex inv() const;
+
+ // unary functions -- inlined
+ /**@name unary functions */
+ //@{
+ /**@name inlined */
+ //@{
+ Complex conj() const { return Complex<Real>(r,-i); }
+ Real norm2() const { return i*i+r*r; }
+ Complex flip() const { return Complex<Real>(i,r); }
+ Real real() const { return r;}
+ Real imag() const { return i;}
+ Complex neg() const { return Complex<Real>(-r, -i); }
+ bool isZero() const { return ((r==(Real)0) && (i==(Real)0)); }
+ //@}
+ /**@name not inlined due to outside calls */
+ //@{
+ Real abs() const { return ::sqrt(norm2()); }
+ Real arg() const { return ::atan2(i,r); }
+ float dB() const { return 10.0*log10(norm2()); }
+ Complex exp() const { return expj(i)*(::exp(r)); }
+ Complex unit() const; ///< unit phasor with same angle
+ Complex log() const { return Complex(::log(abs()),arg()); }
+ Complex pow(double n) const { return expj(arg()*n)*(::pow(abs(),n)); }
+ Complex sqrt() const { return pow(0.5); }
+ //@}
+ //@}
+
+};
+
+
+/**@name standard Complex manifestations */
+//@{
+typedef Complex<float> complex;
+typedef Complex<double> dcomplex;
+typedef Complex<short> complex16;
+typedef Complex<long> complex32;
+//@}
+
+
+template<class Real> inline Complex<Real> Complex<Real>::inv() const
+{
+ Real nVal;
+
+ nVal = norm2();
+ return Complex<Real>(r/nVal, -i/nVal);
+}
+
+template<class Real> Complex<Real>& Complex<Real>::operator+=(const Complex<Real>& a)
+{
+ r += a.r;
+ i += a.i;
+ return *this;
+}
+
+template<class Real> Complex<Real>& Complex<Real>::operator*=(const Complex<Real>& a)
+{
+ operator*(a);
+ return *this;
+}
+
+template<class Real> Complex<Real>& Complex<Real>::operator-=(const Complex<Real>& a)
+{
+ r -= a.r;
+ i -= a.i;
+ return *this;
+}
+
+template<class Real> Complex<Real>& Complex<Real>::operator/=(const Complex<Real>& a)
+{
+ operator/(a);
+ return *this;
+}
+
+
+/* op= style operations with reals */
+
+template<class Real> Complex<Real>& Complex<Real>::operator+=(Real a)
+{
+ r += a;
+ return *this;
+}
+
+template<class Real> Complex<Real>& Complex<Real>::operator*=(Real a)
+{
+ r *=a;
+ i *=a;
+ return *this;
+}
+
+template<class Real> Complex<Real>& Complex<Real>::operator-=(Real a)
+{
+ r -= a;
+ return *this;
+}
+
+template<class Real> Complex<Real>& Complex<Real>::operator/=(Real a)
+{
+ r /= a;
+ i /= a;
+ return *this;
+}
+
+
+template<class Real> Complex<Real> Complex<Real>::unit() const
+{
+ Real absVal = abs();
+ return (Complex<Real>(r/absVal, i/absVal));
+}
+
+
+
+/**@name complex functions outside of the Complex<> class. */
+//@{
+
+/** this allows type-commutative multiplication */
+template<class Real> Complex<Real> operator*(Real a, const Complex<Real>& z)
+{
+ return Complex<Real>(z.r*a, z.i*a);
+}
+
+
+/** this allows type-commutative addition */
+template<class Real> Complex<Real> operator+(Real a, const Complex<Real>& z)
+{
+ return Complex<Real>(z.r+a, z.i);
+}
+
+
+/** this allows type-commutative subtraction */
+template<class Real> Complex<Real> operator-(Real a, const Complex<Real>& z)
+{
+ return Complex<Real>(z.r-a, z.i);
+}
+
+
+
+/// e^jphi
+template<class Real> Complex<Real> expj(Real phi)
+{
+ return Complex<Real>(cos(phi),sin(phi));
+}
+
+/// phasor expression of a complex number
+template<class Real> Complex<Real> phasor(Real C, Real phi)
+{
+ return (expj(phi)*C);
+}
+
+/// formatted stream output
+template<class Real> std::ostream& operator<<(std::ostream& os, const Complex<Real>& z)
+{
+ os << z.r << ' ';
+ //os << z.r << ", ";
+ //if (z.i>=0) { os << "+"; }
+ os << z.i << "j";
+ os << "\n";
+ return os;
+}
+
+//@}
+
+
+#endif
diff --git a/Transceiver52M/DummyLoad.cpp b/Transceiver52M/DummyLoad.cpp
new file mode 100644
index 0000000..d11226e
--- /dev/null
+++ b/Transceiver52M/DummyLoad.cpp
@@ -0,0 +1,146 @@
+/*
+* Copyright 2008, 2009 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 use of this software may be subject to additional restrictions.
+* See the LEGAL 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/>.
+
+*/
+
+
+/*
+ Compilation Flags
+
+ SWLOOPBACK compile for software loopback testing
+*/
+
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include "Threads.h"
+#include "DummyLoad.h"
+
+#include <Logger.h>
+
+
+using namespace std;
+
+
+
+int DummyLoad::loadBurst(short *wDummyBurst, int len) {
+ dummyBurst = wDummyBurst;
+ dummyBurstSz = len;
+}
+
+
+DummyLoad::DummyLoad (double _desiredSampleRate)
+{
+ LOG(INFO) << "creating USRP device...";
+ sampleRate = _desiredSampleRate;
+}
+
+void DummyLoad::updateTime(void) {
+ gettimeofday(&currTime,NULL);
+ double timeElapsed = (currTime.tv_sec - startTime.tv_sec)*1.0e6 +
+ (currTime.tv_usec - startTime.tv_usec);
+ currstamp = (TIMESTAMP) floor(timeElapsed/(1.0e6/sampleRate));
+}
+
+bool DummyLoad::make(bool wSkipRx)
+{
+
+ samplesRead = 0;
+ samplesWritten = 0;
+ return true;
+}
+
+bool DummyLoad::start()
+{
+ LOG(INFO) << "starting USRP...";
+ underrun = false;
+ gettimeofday(&startTime,NULL);
+ dummyBurstCursor = 0;
+ return true;
+}
+
+bool DummyLoad::stop()
+{
+ return true;
+}
+
+
+// NOTE: Assumes sequential reads
+int DummyLoad::readSamples(short *buf, int len, bool *overrun,
+ TIMESTAMP timestamp,
+ bool *wUnderrun,
+ unsigned *RSSI)
+{
+ updateTime();
+ underrunLock.lock();
+ *wUnderrun = underrun;
+ underrunLock.unlock();
+ if (currstamp+len < timestamp) {
+ usleep(100);
+ return NULL;
+ }
+ else if (currstamp < timestamp) {
+ usleep(100);
+ return NULL;
+ }
+ else if (timestamp+len < currstamp) {
+ memcpy(buf,dummyBurst+dummyBurstCursor*2,sizeof(short)*2*(dummyBurstSz-dummyBurstCursor));
+ int retVal = dummyBurstSz-dummyBurstCursor;
+ dummyBurstCursor = 0;
+ return retVal;
+ }
+ else if (timestamp + len > currstamp) {
+ int amount = timestamp + len - currstamp;
+ if (amount < dummyBurstSz-dummyBurstCursor) {
+ memcpy(buf,dummyBurst+dummyBurstCursor*2,sizeof(short)*2*amount);
+ dummyBurstCursor += amount;
+ return amount;
+ }
+ else {
+ memcpy(buf,dummyBurst+dummyBurstCursor*2,sizeof(short)*2*(dummyBurstSz-dummyBurstCursor));
+ int retVal = dummyBurstSz-dummyBurstCursor;
+ dummyBurstCursor = 0;
+ return retVal;
+ }
+ }
+ return 0;
+}
+
+int DummyLoad::writeSamples(short *buf, int len, bool *wUnderrun,
+ unsigned long long timestamp,
+ bool isControl)
+{
+ updateTime();
+ underrunLock.lock();
+ underrun |= (currstamp+len < timestamp);
+ underrunLock.unlock();
+ return len;
+}
+
+bool DummyLoad::updateAlignment(TIMESTAMP timestamp)
+{
+ return true;
+}
+
+bool DummyLoad::setTxFreq(double wFreq) { return true;};
+bool DummyLoad::setRxFreq(double wFreq) { return true;};
diff --git a/Transceiver52M/DummyLoad.h b/Transceiver52M/DummyLoad.h
new file mode 100644
index 0000000..74a962d
--- /dev/null
+++ b/Transceiver52M/DummyLoad.h
@@ -0,0 +1,132 @@
+/*
+* 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 use of this software may be subject to additional restrictions.
+* See the LEGAL 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/>.
+
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "radioDevice.h"
+
+
+#include <sys/time.h>
+#include <math.h>
+#include <string>
+#include <iostream>
+
+
+/** A class to handle a USRP rev 4, with a two RFX900 daughterboards */
+class DummyLoad: public RadioDevice {
+
+private:
+
+ double sampleRate; ///< the desired sampling rate
+ unsigned long long samplesRead; ///< number of samples read from USRP
+ unsigned long long samplesWritten; ///< number of samples sent to USRP
+
+ Mutex underrunLock;
+
+ struct timeval startTime, currTime;
+
+ TIMESTAMP currstamp;
+ short *dummyBurst;
+ int dummyBurstSz;
+ int dummyBurstCursor;
+ bool underrun;
+
+ void updateTime(void);
+
+ public:
+
+ /** Object constructor */
+ DummyLoad (double _desiredSampleRate);
+
+ int loadBurst(short *wDummyBurst, int len);
+
+ /** Instantiate the USRP */
+ bool make(bool skipRx = false);
+
+ /** Start the USRP */
+ bool start();
+
+ /** Stop the USRP */
+ bool stop();
+
+ /**
+ Read samples from the USRP.
+ @param buf preallocated buf to contain read result
+ @param len number of samples desired
+ @param overrun Set if read buffer has been overrun, e.g. data not being read fast enough
+ @param timestamp The timestamp of the first samples to be read
+ @param underrun Set if USRP does not have data to transmit, e.g. data not being sent fast enough
+ @param RSSI The received signal strength of the read result
+ @return The number of samples actually read
+ */
+ int readSamples(short *buf, int len, bool *overrun,
+ TIMESTAMP timestamp = 0xffffffff,
+ bool *underrun = NULL,
+ unsigned *RSSI = NULL);
+ /**
+ Write samples to the USRP.
+ @param buf Contains the data to be written.
+ @param len number of samples to write.
+ @param underrun Set if USRP does not have data to transmit, e.g. data not being sent fast enough
+ @param timestamp The timestamp of the first sample of the data buffer.
+ @param isControl Set if data is a control packet, e.g. a ping command
+ @return The number of samples actually written
+ */
+ int writeSamples(short *buf, int len, bool *underrun,
+ TIMESTAMP timestamp = 0xffffffff,
+ bool isControl = false);
+
+ /** Update the alignment between the read and write timestamps */
+ bool updateAlignment(TIMESTAMP timestamp);
+
+ /** Set the transmitter frequency */
+ bool setTxFreq(double wFreq);
+
+ /** Set the receiver frequency */
+ bool setRxFreq(double wFreq);
+
+ /** Returns the starting write Timestamp*/
+ TIMESTAMP initialWriteTimestamp(void) { return 20000;}
+
+ /** Returns the starting read Timestamp*/
+ TIMESTAMP initialReadTimestamp(void) { return 20000;}
+
+ /** returns the full-scale transmit amplitude **/
+ double fullScaleInputValue() {return 13500.0;}
+
+ /** returns the full-scale receive amplitude **/
+ double fullScaleOutputValue() {return 9450.0;}
+
+ /** Return internal status values */
+ inline double getTxFreq() { return 0;}
+ inline double getRxFreq() { return 0;}
+ inline double getSampleRate() {return sampleRate;}
+ inline double numberRead() { return samplesRead; }
+ inline double numberWritten() { return samplesWritten;}
+
+};
+
diff --git a/Transceiver52M/Makefile b/Transceiver52M/Makefile
new file mode 100644
index 0000000..3f58e50
--- /dev/null
+++ b/Transceiver52M/Makefile
@@ -0,0 +1,661 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# Transceiver52M/Makefile. Generated from Makefile.in by configure.
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+#
+# Copyright 2008 Free Software Foundation, Inc.
+# Copyright 2010 Range Networks, 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/>.
+#
+
+#
+# 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/>.
+#
+
+
+
+
+pkgdatadir = $(datadir)/openbts
+pkgincludedir = $(includedir)/openbts
+pkglibdir = $(libdir)/openbts
+pkglibexecdir = $(libexecdir)/openbts
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = i686-pc-linux-gnu
+host_triplet = i686-pc-linux-gnu
+target_triplet = i686-pc-linux-gnu
+DIST_COMMON = README $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(top_srcdir)/Makefile.common
+noinst_PROGRAMS = USRPping$(EXEEXT) transceiver$(EXEEXT) \
+ sigProcLibTest$(EXEEXT)
+subdir = Transceiver52M
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libtransceiver_la_LIBADD =
+am_libtransceiver_la_OBJECTS = radioInterface.lo sigProcLib.lo \
+ Transceiver.lo USRPDevice.lo DummyLoad.lo
+libtransceiver_la_OBJECTS = $(am_libtransceiver_la_OBJECTS)
+PROGRAMS = $(noinst_PROGRAMS)
+am_USRPping_OBJECTS = USRPping.$(OBJEXT)
+USRPping_OBJECTS = $(am_USRPping_OBJECTS)
+USRPping_DEPENDENCIES = libtransceiver.la $(COMMON_LA) $(SQLITE_LA)
+am_sigProcLibTest_OBJECTS = sigProcLibTest.$(OBJEXT)
+sigProcLibTest_OBJECTS = $(am_sigProcLibTest_OBJECTS)
+sigProcLibTest_DEPENDENCIES = libtransceiver.la $(GSM_LA) $(COMMON_LA) \
+ $(SQLITE_LA)
+am_transceiver_OBJECTS = runTransceiver.$(OBJEXT)
+transceiver_OBJECTS = $(am_transceiver_OBJECTS)
+transceiver_DEPENDENCIES = libtransceiver.la $(GSM_LA) $(COMMON_LA) \
+ $(SQLITE_LA)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libtransceiver_la_SOURCES) $(USRPping_SOURCES) \
+ $(sigProcLibTest_SOURCES) $(transceiver_SOURCES)
+DIST_SOURCES = $(libtransceiver_la_SOURCES) $(USRPping_SOURCES) \
+ $(sigProcLibTest_SOURCES) $(transceiver_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = ${SHELL} /home/openbts/range/software/public/openbts/trunk/missing --run aclocal-1.9
+AMTAR = ${SHELL} /home/openbts/range/software/public/openbts/trunk/missing --run tar
+AR = ar
+AS = as
+AUTOCONF = ${SHELL} /home/openbts/range/software/public/openbts/trunk/missing --run autoconf
+AUTOHEADER = ${SHELL} /home/openbts/range/software/public/openbts/trunk/missing --run autoheader
+AUTOMAKE = ${SHELL} /home/openbts/range/software/public/openbts/trunk/missing --run automake-1.9
+AWK = mawk
+CC = gcc
+CCAS = gcc
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = -g -O2
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CPP = gcc -E
+CPPFLAGS =
+CXX = g++
+CXXCPP = g++ -E
+CXXDEPMODE = depmode=gcc3
+CXXFLAGS = -g -O2
+CYGPATH_W = echo
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+DLLTOOL = dlltool
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C =
+ECHO_N = -n
+ECHO_T =
+EGREP = /bin/grep -E
+EXEEXT =
+FGREP = @FGREP@
+GREP = /bin/grep
+INSTALL = /usr/bin/install -c
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = ${SHELL} $(install_sh) -c -s
+LD = @LD@
+LDFLAGS =
+LIBOBJS =
+LIBS =
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LIBUSB_CFLAGS = -I/usr/local/include/libusb-1.0
+LIBUSB_LIBS = -L/usr/local/lib -lusb-1.0
+LIPO = @LIPO@
+LN_S = ln -s
+LTLIBOBJS =
+MAKEINFO = ${SHELL} /home/openbts/range/software/public/openbts/trunk/missing --run makeinfo
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = objdump
+OBJEXT = o
+ORTP_CFLAGS = -D_REENTRANT -DORTP_INET6 -I/usr/local/include
+ORTP_LIBS = -L/usr/local/lib -lortp -lpthread
+OSIP_CFLAGS = -DOSIP_MT -I/usr/local/include
+OSIP_LIBS = -L/usr/local/lib -losipparser2 -losip2
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = openbts
+PACKAGE_BUGREPORT =
+PACKAGE_NAME = openbts
+PACKAGE_STRING = openbts P2.8TRUNK
+PACKAGE_TARNAME = openbts
+PACKAGE_URL =
+PACKAGE_VERSION = P2.8TRUNK
+PATH_SEPARATOR = :
+PKG_CONFIG = /usr/bin/pkg-config
+RANLIB = ranlib
+RM_PROG = /bin/rm
+SED = @SED@
+SET_MAKE =
+SHELL = /bin/bash
+STRIP = strip
+VERSION = P2.8TRUNK
+abs_builddir = /home/openbts/range/software/public/openbts/trunk/Transceiver52M
+abs_srcdir = /home/openbts/range/software/public/openbts/trunk/Transceiver52M
+abs_top_builddir = /home/openbts/range/software/public/openbts/trunk
+abs_top_srcdir = /home/openbts/range/software/public/openbts/trunk
+ac_ct_CC = gcc
+ac_ct_CXX = g++
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = include
+am__leading_dot = .
+am__quote =
+am__tar = ${AMTAR} chof - "$$tardir"
+am__untar = ${AMTAR} xf -
+bindir = ${exec_prefix}/bin
+build = i686-pc-linux-gnu
+build_alias =
+build_cpu = i686
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+host = i686-pc-linux-gnu
+host_alias =
+host_cpu = i686
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = /home/openbts/range/software/public/openbts/trunk/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+lt_ECHO = @lt_ECHO@
+mandir = ${datarootdir}/man
+mkdir_p = mkdir -p --
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+sysconfdir = ${prefix}/etc
+target = i686-pc-linux-gnu
+target_alias =
+target_cpu = i686
+target_os = linux-gnu
+target_vendor = pc
+top_build_prefix = ../
+top_builddir = ..
+top_srcdir = ..
+COMMON_INCLUDEDIR = $(top_srcdir)/CommonLibs
+CONTROL_INCLUDEDIR = $(top_srcdir)/Control
+GSM_INCLUDEDIR = $(top_srcdir)/GSM
+SIP_INCLUDEDIR = $(top_srcdir)/SIP
+SMS_INCLUDEDIR = $(top_srcdir)/SMS
+TRX_INCLUDEDIR = $(top_srcdir)/TRXManager
+GLOBALS_INCLUDEDIR = $(top_srcdir)/Globals
+CLI_INCLUDEDIR = $(top_srcdir)/CLI
+SQLITE_INCLUDEDIR = $(top_srcdir)/sqlite3
+SR_INCLUDEDIR = $(top_srcdir)/SR
+STD_DEFINES_AND_INCLUDES = \
+ -I$(COMMON_INCLUDEDIR) \
+ -I$(CONTROL_INCLUDEDIR) \
+ -I$(GSM_INCLUDEDIR) \
+ -I$(SIP_INCLUDEDIR) \
+ -I$(SMS_INCLUDEDIR) \
+ -I$(TRX_INCLUDEDIR) \
+ -I$(GLOBALS_INCLUDEDIR) \
+ -I$(CLI_INCLUDEDIR) \
+ -I$(SR_INCLUDEDIR) \
+ -I$(SQLITE_INCLUDEDIR)
+
+COMMON_LA = $(top_builddir)/CommonLibs/libcommon.la
+GSM_LA = $(top_builddir)/GSM/libGSM.la
+SIP_LA = $(top_builddir)/SIP/libSIP.la
+SMS_LA = $(top_builddir)/SMS/libSMS.la
+TRX_LA = $(top_builddir)/TRXManager/libtrxmanager.la
+CONTROL_LA = $(top_builddir)/Control/libcontrol.la
+GLOBALS_LA = $(top_builddir)/Globals/libglobals.la
+CLI_LA = $(top_builddir)/CLI/libcli.la
+SR_LA = $(top_builddir)/SR/libSR.la
+SQLITE_LA = $(top_builddir)/sqlite3/libsqlite.la
+MOSTLYCLEANFILES = *~
+AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(USRP_CFLAGS)
+AM_CXXFLAGS = -ldl -lpthread
+
+#rev2dir = $(datadir)/usrp/rev2
+#rev4dir = $(datadir)/usrp/rev4
+
+#dist_rev2_DATA = std_inband.rbf
+#dist_rev4_DATA = std_inband.rbf
+EXTRA_DIST = \
+ README \
+ README.Talgorithm
+
+noinst_LTLIBRARIES = libtransceiver.la
+libtransceiver_la_SOURCES = \
+ radioInterface.cpp \
+ sigProcLib.cpp \
+ Transceiver.cpp \
+ USRPDevice.cpp \
+ DummyLoad.cpp
+
+noinst_HEADERS = \
+ Complex.h \
+ radioInterface.h \
+ radioDevice.h \
+ sigProcLib.h \
+ Transceiver.h \
+ USRPDevice.h \
+ DummyLoad.h
+
+USRPping_SOURCES = USRPping.cpp
+USRPping_LDADD = \
+ libtransceiver.la \
+ $(COMMON_LA) $(SQLITE_LA) \
+ $(USRP_LIBS)
+
+transceiver_SOURCES = runTransceiver.cpp
+transceiver_LDADD = \
+ libtransceiver.la \
+ $(GSM_LA) \
+ $(COMMON_LA) $(SQLITE_LA) \
+ $(USRP_LIBS)
+
+sigProcLibTest_SOURCES = sigProcLibTest.cpp
+sigProcLibTest_LDADD = \
+ libtransceiver.la \
+ $(GSM_LA) \
+ $(COMMON_LA) $(SQLITE_LA) \
+ $(USRP_LIBS)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/Makefile.common $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Transceiver52M/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu Transceiver52M/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libtransceiver.la: $(libtransceiver_la_OBJECTS) $(libtransceiver_la_DEPENDENCIES)
+ $(CXXLINK) $(libtransceiver_la_OBJECTS) $(libtransceiver_la_LIBADD) $(LIBS)
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+USRPping$(EXEEXT): $(USRPping_OBJECTS) $(USRPping_DEPENDENCIES)
+ @rm -f USRPping$(EXEEXT)
+ $(CXXLINK) $(USRPping_OBJECTS) $(USRPping_LDADD) $(LIBS)
+sigProcLibTest$(EXEEXT): $(sigProcLibTest_OBJECTS) $(sigProcLibTest_DEPENDENCIES)
+ @rm -f sigProcLibTest$(EXEEXT)
+ $(CXXLINK) $(sigProcLibTest_OBJECTS) $(sigProcLibTest_LDADD) $(LIBS)
+transceiver$(EXEEXT): $(transceiver_OBJECTS) $(transceiver_DEPENDENCIES)
+ @rm -f transceiver$(EXEEXT)
+ $(CXXLINK) $(transceiver_OBJECTS) $(transceiver_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+include ./$(DEPDIR)/DummyLoad.Plo
+include ./$(DEPDIR)/Transceiver.Plo
+include ./$(DEPDIR)/USRPDevice.Plo
+include ./$(DEPDIR)/USRPping.Po
+include ./$(DEPDIR)/radioInterface.Plo
+include ./$(DEPDIR)/runTransceiver.Po
+include ./$(DEPDIR)/sigProcLib.Plo
+include ./$(DEPDIR)/sigProcLibTest.Po
+
+.cpp.o:
+ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+# source='$<' object='$@' libtool=no \
+# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \
+# $(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+# source='$<' object='$@' libtool=no \
+# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \
+# $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+# source='$<' object='$@' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \
+# $(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+ -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES clean-noinstPROGRAMS \
+ ctags distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am
+
+
+#radioInterface.cpp
+#ComplexTest.cpp
+#sigProcLibTest.cpp
+#sweepGenerator.cpp
+#testRadio.cpp
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/Transceiver52M/Makefile.am b/Transceiver52M/Makefile.am
new file mode 100644
index 0000000..4669b99
--- /dev/null
+++ b/Transceiver52M/Makefile.am
@@ -0,0 +1,88 @@
+#
+# Copyright 2008 Free Software Foundation, Inc.
+# Copyright 2010 Range Networks, 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 $(top_srcdir)/Makefile.common
+
+AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(USRP_CFLAGS)
+AM_CXXFLAGS = -ldl -lpthread
+
+#rev2dir = $(datadir)/usrp/rev2
+#rev4dir = $(datadir)/usrp/rev4
+
+#dist_rev2_DATA = std_inband.rbf
+#dist_rev4_DATA = std_inband.rbf
+
+EXTRA_DIST = \
+ README \
+ README.Talgorithm
+
+noinst_LTLIBRARIES = libtransceiver.la
+
+libtransceiver_la_SOURCES = \
+ radioInterface.cpp \
+ sigProcLib.cpp \
+ Transceiver.cpp \
+ USRPDevice.cpp \
+ DummyLoad.cpp
+
+noinst_PROGRAMS = \
+ USRPping \
+ transceiver \
+ sigProcLibTest
+
+noinst_HEADERS = \
+ Complex.h \
+ radioInterface.h \
+ radioDevice.h \
+ sigProcLib.h \
+ Transceiver.h \
+ USRPDevice.h \
+ DummyLoad.h
+
+USRPping_SOURCES = USRPping.cpp
+USRPping_LDADD = \
+ libtransceiver.la \
+ $(COMMON_LA) $(SQLITE_LA) \
+ $(USRP_LIBS)
+
+transceiver_SOURCES = runTransceiver.cpp
+transceiver_LDADD = \
+ libtransceiver.la \
+ $(GSM_LA) \
+ $(COMMON_LA) $(SQLITE_LA) \
+ $(USRP_LIBS)
+
+sigProcLibTest_SOURCES = sigProcLibTest.cpp
+sigProcLibTest_LDADD = \
+ libtransceiver.la \
+ $(GSM_LA) \
+ $(COMMON_LA) $(SQLITE_LA) \
+ $(USRP_LIBS)
+
+
+MOSTLYCLEANFILES +=
+
+#radioInterface.cpp
+#ComplexTest.cpp
+#sigProcLibTest.cpp
+#sweepGenerator.cpp
+#testRadio.cpp
+
diff --git a/Transceiver52M/README b/Transceiver52M/README
new file mode 100644
index 0000000..491693c
--- /dev/null
+++ b/Transceiver52M/README
@@ -0,0 +1,35 @@
+The Transceiver
+
+The transceiver consists of three modules:
+ --- transceiver
+ --- radioInterface
+ --- USRPDevice
+
+The USRPDevice module is basically a driver that reads/writes
+packets to a USRP with two RFX900 daughterboards, board
+A is the Tx chain and board B is the Rx chain.
+
+The radioInterface module is basically an interface b/w the
+transceiver and the USRP. It operates the basestation clock
+based upon the sample count of received USRP samples. Packets
+from the USRP are queued and segmented into GSM bursts that are
+passed up to the transceiver; bursts from the transceiver are
+passed down to the USRP.
+
+The transceiver basically operates "layer 0" of the GSM stack,
+performing the modulation, detection, and demodulation of GSM
+bursts. It communicates with the GSM stack via three UDP sockets,
+one socket for data, one for control messages, and one socket to
+pass clocking information. The transceiver contains a priority
+queue to sort to-be-transmitted bursts, and a filler table to fill
+in timeslots that do not have bursts in the priority queue. The
+transceiver tries to stay ahead of the basestation clock, adapting
+its latency when underruns are reported by the radioInterface/USRP.
+Received bursts (from the radioInterface) pass through a simple
+energy detector, a RACH or midamble correlator, and a DFE-based demodulator.
+
+NOTE: There's a SWLOOPBACK #define statement, where the USRP is replaced
+with a memory buffer. In this mode, data written to the USRP is actually stored
+in a buffer, and read commands to the USRP simply pull data from this buffer.
+This was very useful in early testing, and still may be useful in testing basic
+Transceiver and radioInterface functionality.
diff --git a/Transceiver52M/README.DFEsymbolspaced b/Transceiver52M/README.DFEsymbolspaced
new file mode 100644
index 0000000..f1ab479
--- /dev/null
+++ b/Transceiver52M/README.DFEsymbolspaced
@@ -0,0 +1,14 @@
+signalVectors G0, G1. i.e. G0(D) = 1 +2D + 3D^2 = [1 2 3]
+G0(D) = 1/sqrt(SNR).
+G1(D) = [h0 h1D .. h_(N-1)D^(N-1)]
+for i = 0,1,...,N_f-1,
+ d = |G0(0)|^2+|G1(0)|^2
+ l_i(D) = D^i ( G0(D)*G0'(0) + G1(D)*G1'(0) )/d
+ k = G1(0)/G0(0)
+ G0n(D) = G0(D)+k'*G1(D)
+ G1n(D) = (-G0(D)*k+G1(D))/D
+ G0(D) = G0n(D)/sqrt(1+k*k')
+ G1(D) = G1n(D)/sqrt(1+k*k')
+end
+
+
diff --git a/Transceiver52M/README.Talgorithm b/Transceiver52M/README.Talgorithm
new file mode 100644
index 0000000..037d613
--- /dev/null
+++ b/Transceiver52M/README.Talgorithm
@@ -0,0 +1,15 @@
+Basic model:
+
+Have channel H = {h_0, h_1, ..., h_{K-1}}.
+Have received sequence Y = {y_0, ..., y_{K+N}}.
+Have transmitted sequence X = {x_0, ..., x_{N-1}}.
+Denote state S_n = {x_n, x_{n-1}, ..., x_{n-L}}.
+
+Define a bag as an unordered collection with two operations, add and take.
+We have three bags:
+ S: a bag of survivors.
+ F: a bag of available data structures.
+
+At time n, start with a non-empty bag S of survivors from time n-1.
+Take a member out of S, and create all possible branches and their corresponding metrics. If metric ratio is above T, discard branch. Otherwise, check branch against entry in pruning table P. If branch metric is smaller than the existing entry's metric in P, then replace entry with branch. Otherwise, discard branch.
+Once all possible branches of S have been created and pruned, S should be empty.Empty pruning table back into S, thus P is now empty. Repeat.
diff --git a/Transceiver52M/Transceiver.cpp b/Transceiver52M/Transceiver.cpp
new file mode 100644
index 0000000..7cb2128
--- /dev/null
+++ b/Transceiver52M/Transceiver.cpp
@@ -0,0 +1,798 @@
+/*
+* Copyright 2008, 2009, 2010 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 use of this software may be subject to additional restrictions.
+* See the LEGAL 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/>.
+*/
+
+
+/*
+ Compilation switches
+ TRANSMIT_LOGGING write every burst on the given slot to a log
+*/
+
+
+#include <stdio.h>
+#include "Transceiver.h"
+#include <Logger.h>
+
+
+
+Transceiver::Transceiver(int wBasePort,
+ const char *TRXAddress,
+ int wSamplesPerSymbol,
+ GSM::Time wTransmitLatency,
+ RadioInterface *wRadioInterface)
+ :mDataSocket(wBasePort+2,TRXAddress,wBasePort+102),
+ mControlSocket(wBasePort+1,TRXAddress,wBasePort+101),
+ mClockSocket(wBasePort,TRXAddress,wBasePort+100)
+{
+ //GSM::Time startTime(0,0);
+ //GSM::Time startTime(gHyperframe/2 - 4*216*60,0);
+ GSM::Time startTime(random() % gHyperframe,0);
+
+ mFIFOServiceLoopThread = new Thread(32768); ///< thread to push bursts into transmit FIFO
+ mControlServiceLoopThread = new Thread(32768); ///< thread to process control messages from GSM core
+ mTransmitPriorityQueueServiceLoopThread = new Thread(32768);///< thread to process transmit bursts from GSM core
+
+
+ mSamplesPerSymbol = wSamplesPerSymbol;
+ mRadioInterface = wRadioInterface;
+ mTransmitLatency = wTransmitLatency;
+ mTransmitDeadlineClock = startTime;
+ mLastClockUpdateTime = startTime;
+ mLatencyUpdateTime = startTime;
+ mRadioInterface->getClock()->set(startTime);
+ mMaxExpectedDelay = 0;
+
+ // generate pulse and setup up signal processing library
+ gsmPulse = generateGSMPulse(2,mSamplesPerSymbol);
+ LOG(DEBUG) << "gsmPulse: " << *gsmPulse;
+ sigProcLibSetup(mSamplesPerSymbol);
+
+ txFullScale = mRadioInterface->fullScaleInputValue();
+ rxFullScale = mRadioInterface->fullScaleOutputValue();
+
+ // initialize filler tables with dummy bursts, initialize other per-timeslot variables
+ for (int i = 0; i < 8; i++) {
+ signalVector* modBurst = modulateBurst(gDummyBurst,*gsmPulse,
+ 8 + (i % 4 == 0),
+ mSamplesPerSymbol);
+ scaleVector(*modBurst,txFullScale);
+ fillerModulus[i]=26;
+ for (int j = 0; j < 102; j++) {
+ fillerTable[j][i] = new signalVector(*modBurst);
+ }
+ delete modBurst;
+ mChanType[i] = NONE;
+ channelResponse[i] = NULL;
+ DFEForward[i] = NULL;
+ DFEFeedback[i] = NULL;
+ channelEstimateTime[i] = startTime;
+ }
+
+ mOn = false;
+ mTxFreq = 0.0;
+ mRxFreq = 0.0;
+ mPower = -10;
+ mEnergyThreshold = 5.0; // based on empirical data
+ prevFalseDetectionTime = startTime;
+}
+
+Transceiver::~Transceiver()
+{
+ delete gsmPulse;
+ sigProcLibDestroy();
+ mTransmitPriorityQueue.clear();
+}
+
+
+void Transceiver::addRadioVector(BitVector &burst,
+ int RSSI,
+ GSM::Time &wTime)
+{
+ // modulate and stick into queue
+ signalVector* modBurst = modulateBurst(burst,*gsmPulse,
+ 8 + (wTime.TN() % 4 == 0),
+ mSamplesPerSymbol);
+ scaleVector(*modBurst,txFullScale * pow(10,-RSSI/10));
+ radioVector *newVec = new radioVector(*modBurst,wTime);
+ mTransmitPriorityQueue.write(newVec);
+
+ delete modBurst;
+}
+
+#ifdef TRANSMIT_LOGGING
+void Transceiver::unModulateVector(signalVector wVector)
+{
+ SoftVector *burst = demodulateBurst(wVector,
+ *gsmPulse,
+ mSamplesPerSymbol,
+ 1.0,0.0);
+ LOG(DEBUG) << "LOGGED BURST: " << *burst;
+
+/*
+ unsigned char burstStr[gSlotLen+1];
+ SoftVector::iterator burstItr = burst->begin();
+ for (int i = 0; i < gSlotLen; i++) {
+ // FIXME: Demod bits are inverted!
+ burstStr[i] = (unsigned char) ((*burstItr++)*255.0);
+ }
+ burstStr[gSlotLen]='\0';
+ LOG(DEBUG) << "LOGGED BURST: " << burstStr;
+*/
+ delete burst;
+}
+#endif
+
+void Transceiver::pushRadioVector(GSM::Time &nowTime)
+{
+
+ // dump stale bursts, if any
+ while (radioVector* staleBurst = mTransmitPriorityQueue.getStaleBurst(nowTime)) {
+ // Even if the burst is stale, put it in the fillter table.
+ // (It might be an idle pattern.)
+ LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
+ const GSM::Time& nextTime = staleBurst->time();
+ int TN = nextTime.TN();
+ int modFN = nextTime.FN() % fillerModulus[TN];
+ delete fillerTable[modFN][TN];
+ fillerTable[modFN][TN] = staleBurst;
+ }
+
+ int TN = nowTime.TN();
+ int modFN = nowTime.FN() % fillerModulus[nowTime.TN()];
+
+ // if queue contains data at the desired timestamp, stick it into FIFO
+ if (radioVector *next = (radioVector*) mTransmitPriorityQueue.getCurrentBurst(nowTime)) {
+ LOG(DEBUG) << "transmitFIFO: wrote burst " << next << " at time: " << nowTime;
+ delete fillerTable[modFN][TN];
+ fillerTable[modFN][TN] = new signalVector(*(next));
+ mRadioInterface->driveTransmitRadio(*(next),(mChanType[TN]==NONE)); //fillerTable[modFN][TN]));
+ delete next;
+#ifdef TRANSMIT_LOGGING
+ if (nowTime.TN()==TRANSMIT_LOGGING) {
+ unModulateVector(*(fillerTable[modFN][TN]));
+ }
+#endif
+ return;
+ }
+
+ // otherwise, pull filler data, and push to radio FIFO
+ mRadioInterface->driveTransmitRadio(*(fillerTable[modFN][TN]),(mChanType[TN]==NONE));
+#ifdef TRANSMIT_LOGGING
+ if (nowTime.TN()==TRANSMIT_LOGGING)
+ unModulateVector(*fillerTable[modFN][TN]);
+#endif
+
+}
+
+void Transceiver::setModulus(int timeslot)
+{
+ switch (mChanType[timeslot]) {
+ case NONE:
+ case I:
+ case II:
+ case III:
+ case FILL:
+ fillerModulus[timeslot] = 26;
+ break;
+ case IV:
+ case VI:
+ case V:
+ fillerModulus[timeslot] = 51;
+ break;
+ //case V:
+ case VII:
+ fillerModulus[timeslot] = 102;
+ break;
+ default:
+ break;
+ }
+}
+
+
+Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime)
+{
+
+ unsigned burstTN = currTime.TN();
+ unsigned burstFN = currTime.FN();
+
+ switch (mChanType[burstTN]) {
+ case NONE:
+ return OFF;
+ break;
+ case FILL:
+ return IDLE;
+ break;
+ case I:
+ return TSC;
+ /*if (burstFN % 26 == 25)
+ return IDLE;
+ else
+ return TSC;*/
+ break;
+ case II:
+ if (burstFN % 2 == 1)
+ return IDLE;
+ else
+ return TSC;
+ break;
+ case III:
+ return TSC;
+ break;
+ case IV:
+ case VI:
+ return RACH;
+ break;
+ case V: {
+ int mod51 = burstFN % 51;
+ if ((mod51 <= 36) && (mod51 >= 14))
+ return RACH;
+ else if ((mod51 == 4) || (mod51 == 5))
+ return RACH;
+ else if ((mod51 == 45) || (mod51 == 46))
+ return RACH;
+ else
+ return TSC;
+ break;
+ }
+ case VII:
+ if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
+ return IDLE;
+ else
+ return TSC;
+ break;
+ case LOOPBACK:
+ if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
+ return IDLE;
+ else
+ return TSC;
+ break;
+ default:
+ return OFF;
+ break;
+ }
+
+}
+
+SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
+ int &RSSI,
+ int &timingOffset)
+{
+ bool needDFE = (mMaxExpectedDelay > 1);
+
+ radioVector *rxBurst = (radioVector *) mReceiveFIFO->get();
+
+ if (!rxBurst) return NULL;
+
+ LOG(DEBUG) << "receiveFIFO: read radio vector at time: " << rxBurst->time() << ", new size: " << mReceiveFIFO->size();
+
+ int timeslot = rxBurst->time().TN();
+
+ CorrType corrType = expectedCorrType(rxBurst->time());
+
+ if ((corrType==OFF) || (corrType==IDLE)) {
+ delete rxBurst;
+ return NULL;
+ }
+
+ // check to see if received burst has sufficient
+ signalVector *vectorBurst = rxBurst;
+ complex amplitude = 0.0;
+ float TOA = 0.0;
+ float avgPwr = 0.0;
+ if (!energyDetect(*vectorBurst,20*mSamplesPerSymbol,mEnergyThreshold,&avgPwr)) {
+ LOG(DEBUG) << "Estimated Energy: " << sqrt(avgPwr) << ", at time " << rxBurst->time();
+ double framesElapsed = rxBurst->time()-prevFalseDetectionTime;
+ if (framesElapsed > 50) { // if we haven't had any false detections for a while, lower threshold
+ mEnergyThreshold -= 10.0/10.0;
+ prevFalseDetectionTime = rxBurst->time();
+ }
+ delete rxBurst;
+ return NULL;
+ }
+ LOG(DEBUG) << "Estimated Energy: " << sqrt(avgPwr) << ", at time " << rxBurst->time();
+
+ // run the proper correlator
+ bool success = false;
+ if (corrType==TSC) {
+ LOG(DEBUG) << "looking for TSC at time: " << rxBurst->time();
+ signalVector *channelResp;
+ double framesElapsed = rxBurst->time()-channelEstimateTime[timeslot];
+ bool estimateChannel = false;
+ if ((framesElapsed > 50) || (channelResponse[timeslot]==NULL)) {
+ if (channelResponse[timeslot]) delete channelResponse[timeslot];
+ if (DFEForward[timeslot]) delete DFEForward[timeslot];
+ if (DFEFeedback[timeslot]) delete DFEFeedback[timeslot];
+ channelResponse[timeslot] = NULL;
+ DFEForward[timeslot] = NULL;
+ DFEFeedback[timeslot] = NULL;
+ estimateChannel = true;
+ }
+ if (!needDFE) estimateChannel = false;
+ float chanOffset;
+ success = analyzeTrafficBurst(*vectorBurst,
+ mTSC,
+ 3.0,
+ mSamplesPerSymbol,
+ &amplitude,
+ &TOA,
+ mMaxExpectedDelay,
+ estimateChannel,
+ &channelResp,
+ &chanOffset);
+ if (success) {
+ LOG(DEBUG) << "FOUND TSC!!!!!! " << amplitude << " " << TOA;
+ mEnergyThreshold -= 1.0F/10.0F;
+ if (mEnergyThreshold < 0.0) mEnergyThreshold = 0.0;
+ SNRestimate[timeslot] = amplitude.norm2()/(mEnergyThreshold*mEnergyThreshold+1.0); // this is not highly accurate
+ if (estimateChannel) {
+ LOG(DEBUG) << "estimating channel...";
+ channelResponse[timeslot] = channelResp;
+ chanRespOffset[timeslot] = chanOffset;
+ chanRespAmplitude[timeslot] = amplitude;
+ scaleVector(*channelResp, complex(1.0,0.0)/amplitude);
+ designDFE(*channelResp, SNRestimate[timeslot], 7, &DFEForward[timeslot], &DFEFeedback[timeslot]);
+ channelEstimateTime[timeslot] = rxBurst->time();
+ LOG(DEBUG) << "SNR: " << SNRestimate[timeslot] << ", DFE forward: " << *DFEForward[timeslot] << ", DFE backward: " << *DFEFeedback[timeslot];
+ }
+ }
+ else {
+ double framesElapsed = rxBurst->time()-prevFalseDetectionTime;
+ LOG(DEBUG) << "wTime: " << rxBurst->time() << ", pTime: " << prevFalseDetectionTime << ", fElapsed: " << framesElapsed;
+ mEnergyThreshold += 10.0F/10.0F*exp(-framesElapsed);
+ prevFalseDetectionTime = rxBurst->time();
+ channelResponse[timeslot] = NULL;
+ }
+ }
+ else {
+ // RACH burst
+ success = detectRACHBurst(*vectorBurst,
+ 5.0, // detection threshold
+ mSamplesPerSymbol,
+ &amplitude,
+ &TOA);
+ if (success) {
+ LOG(DEBUG) << "FOUND RACH!!!!!! " << amplitude << " " << TOA;
+ mEnergyThreshold -= (1.0F/10.0F);
+ if (mEnergyThreshold < 0.0) mEnergyThreshold = 0.0;
+ channelResponse[timeslot] = NULL;
+ }
+ else {
+ double framesElapsed = rxBurst->time()-prevFalseDetectionTime;
+ mEnergyThreshold += (1.0F/10.0F)*exp(-framesElapsed);
+ prevFalseDetectionTime = rxBurst->time();
+ }
+ }
+ LOG(DEBUG) << "energy Threshold = " << mEnergyThreshold;
+
+ // demodulate burst
+ SoftVector *burst = NULL;
+ if ((rxBurst) && (success)) {
+ if ((corrType==RACH) || (!needDFE)) {
+ burst = demodulateBurst(*vectorBurst,
+ *gsmPulse,
+ mSamplesPerSymbol,
+ amplitude,TOA);
+ }
+ else { // TSC
+ scaleVector(*vectorBurst,complex(1.0,0.0)/amplitude);
+ burst = equalizeBurst(*vectorBurst,
+ TOA-chanRespOffset[timeslot],
+ mSamplesPerSymbol,
+ *DFEForward[timeslot],
+ *DFEFeedback[timeslot]);
+ }
+ wTime = rxBurst->time();
+ // FIXME: what is full scale for the USRP? we get more that 12 bits of resolution...
+ RSSI = (int) floor(20.0*log10(rxFullScale/amplitude.abs()));
+ LOG(DEBUG) << "RSSI: " << RSSI;
+ timingOffset = (int) round(TOA*256.0/mSamplesPerSymbol);
+ }
+
+ //if (burst) LOG(DEBUG) << "burst: " << *burst << '\n';
+
+ delete rxBurst;
+
+ return burst;
+}
+
+void Transceiver::start()
+{
+ mControlServiceLoopThread->start((void * (*)(void*))ControlServiceLoopAdapter,(void*) this);
+}
+
+void Transceiver::reset()
+{
+ mTransmitPriorityQueue.clear();
+ //mTransmitFIFO->clear();
+ //mReceiveFIFO->clear();
+}
+
+
+void Transceiver::driveControl()
+{
+
+ int MAX_PACKET_LENGTH = 100;
+
+ // check control socket
+ char buffer[MAX_PACKET_LENGTH];
+ int msgLen = -1;
+ buffer[0] = '\0';
+
+ msgLen = mControlSocket.read(buffer);
+
+ if (msgLen < 1) {
+ return;
+ }
+
+ char cmdcheck[4];
+ char command[MAX_PACKET_LENGTH];
+ char response[MAX_PACKET_LENGTH];
+
+ sscanf(buffer,"%3s %s",cmdcheck,command);
+
+ writeClockInterface();
+
+ if (strcmp(cmdcheck,"CMD")!=0) {
+ LOG(WARNING) << "bogus message on control interface";
+ return;
+ }
+ LOG(INFO) << "command is " << buffer;
+
+ if (strcmp(command,"POWEROFF")==0) {
+ // turn off transmitter/demod
+ sprintf(response,"RSP POWEROFF 0");
+ }
+ else if (strcmp(command,"POWERON")==0) {
+ // turn on transmitter/demod
+ if (!mTxFreq || !mRxFreq)
+ sprintf(response,"RSP POWERON 1");
+ else {
+ sprintf(response,"RSP POWERON 0");
+ if (!mOn) {
+ // Prepare for thread start
+ mPower = -20;
+ mRadioInterface->start();
+ generateRACHSequence(*gsmPulse,mSamplesPerSymbol);
+
+ // Start radio interface threads.
+ mFIFOServiceLoopThread->start((void * (*)(void*))FIFOServiceLoopAdapter,(void*) this);
+ mTransmitPriorityQueueServiceLoopThread->start((void * (*)(void*))TransmitPriorityQueueServiceLoopAdapter,(void*) this);
+ writeClockInterface();
+
+ mOn = true;
+ }
+ }
+ }
+ else if (strcmp(command,"SETMAXDLY")==0) {
+ //set expected maximum time-of-arrival
+ int maxDelay;
+ sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
+ mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
+ sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
+ }
+ else if (strcmp(command,"SETRXGAIN")==0) {
+ //set expected maximum time-of-arrival
+ int newGain;
+ sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
+ newGain = mRadioInterface->setRxGain(newGain);
+ sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
+ }
+ else if (strcmp(command,"NOISELEV")==0) {
+ if (mOn) {
+ sprintf(response,"RSP NOISELEV 0 %d",
+ (int) round(20.0*log10(rxFullScale/mEnergyThreshold)));
+ }
+ else {
+ sprintf(response,"RSP NOISELEV 1 0");
+ }
+ }
+ else if (strcmp(command,"SETPOWER")==0) {
+ // set output power in dB
+ int dbPwr;
+ sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbPwr);
+ if (!mOn)
+ sprintf(response,"RSP SETPOWER 1 %d",dbPwr);
+ else {
+ mPower = dbPwr;
+ mRadioInterface->setPowerAttenuation(pow(10.0,dbPwr/10.0));
+ sprintf(response,"RSP SETPOWER 0 %d",dbPwr);
+ }
+ }
+ else if (strcmp(command,"ADJPOWER")==0) {
+ // adjust power in dB steps
+ int dbStep;
+ sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbStep);
+ if (!mOn)
+ sprintf(response,"RSP ADJPOWER 1 %d",mPower);
+ else {
+ mPower += dbStep;
+ sprintf(response,"RSP ADJPOWER 0 %d",mPower);
+ }
+ }
+#define FREQOFFSET 0//11.2e3
+ else if (strcmp(command,"RXTUNE")==0) {
+ // tune receiver
+ int freqKhz;
+ sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
+ mRxFreq = freqKhz*1.0e3+FREQOFFSET;
+ if (!mRadioInterface->tuneRx(mRxFreq)) {
+ LOG(ALERT) << "RX failed to tune";
+ sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
+ }
+ else
+ sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
+ }
+ else if (strcmp(command,"TXTUNE")==0) {
+ // tune txmtr
+ int freqKhz;
+ sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
+ //freqKhz = 890e3;
+ mTxFreq = freqKhz*1.0e3+FREQOFFSET;
+ if (!mRadioInterface->tuneTx(mTxFreq)) {
+ LOG(ALERT) << "TX failed to tune";
+ sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
+ }
+ else
+ sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
+ }
+ else if (strcmp(command,"SETTSC")==0) {
+ // set TSC
+ int TSC;
+ sscanf(buffer,"%3s %s %d",cmdcheck,command,&TSC);
+ if (mOn)
+ sprintf(response,"RSP SETTSC 1 %d",TSC);
+ else {
+ mTSC = TSC;
+ generateMidamble(*gsmPulse,mSamplesPerSymbol,TSC);
+ sprintf(response,"RSP SETTSC 0 %d",TSC);
+ }
+ }
+ else if (strcmp(command,"SETSLOT")==0) {
+ // set TSC
+ int corrCode;
+ int timeslot;
+ sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
+ if ((timeslot < 0) || (timeslot > 7)) {
+ LOG(WARNING) << "bogus message on control interface";
+ sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
+ return;
+ }
+ mChanType[timeslot] = (ChannelCombination) corrCode;
+ setModulus(timeslot);
+ sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
+
+ }
+ else {
+ LOG(WARNING) << "bogus command " << command << " on control interface.";
+ }
+
+ mControlSocket.write(response,strlen(response)+1);
+
+}
+
+bool Transceiver::driveTransmitPriorityQueue()
+{
+
+ char buffer[gSlotLen+50];
+
+ // check data socket
+ size_t msgLen = mDataSocket.read(buffer);
+
+ if (msgLen!=gSlotLen+1+4+1) {
+ LOG(ERR) << "badly formatted packet on GSM->TRX interface";
+ return false;
+ }
+
+ int timeSlot = (int) buffer[0];
+ uint64_t frameNum = 0;
+ for (int i = 0; i < 4; i++)
+ frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
+
+ /*
+ if (GSM::Time(frameNum,timeSlot) > mTransmitDeadlineClock + GSM::Time(51,0)) {
+ // stale burst
+ //LOG(DEBUG) << "FAST! "<< GSM::Time(frameNum,timeSlot);
+ //writeClockInterface();
+ }*/
+
+/*
+ DAB -- Just let these go through the demod.
+ if (GSM::Time(frameNum,timeSlot) < mTransmitDeadlineClock) {
+ // stale burst from GSM core
+ LOG(NOTICE) << "STALE packet on GSM->TRX interface at time "<< GSM::Time(frameNum,timeSlot);
+ return false;
+ }
+*/
+
+ // periodically update GSM core clock
+ LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock
+ << " mLastClockUpdateTime " << mLastClockUpdateTime;
+ if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
+ writeClockInterface();
+
+
+ LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
+
+ int RSSI = (int) buffer[5];
+ static BitVector newBurst(gSlotLen);
+ BitVector::iterator itr = newBurst.begin();
+ char *bufferItr = buffer+6;
+ while (itr < newBurst.end())
+ *itr++ = *bufferItr++;
+
+ GSM::Time currTime = GSM::Time(frameNum,timeSlot);
+
+ addRadioVector(newBurst,RSSI,currTime);
+
+ LOG(DEBUG) "added burst - time: " << currTime << ", RSSI: " << RSSI; // << ", data: " << newBurst;
+
+ return true;
+
+
+}
+
+void Transceiver::driveReceiveFIFO()
+{
+
+ SoftVector *rxBurst = NULL;
+ int RSSI;
+ int TOA; // in 1/256 of a symbol
+ GSM::Time burstTime;
+
+ mRadioInterface->driveReceiveRadio();
+
+ rxBurst = pullRadioVector(burstTime,RSSI,TOA);
+
+ if (rxBurst) {
+
+ LOG(DEBUG) << "burst parameters: "
+ << " time: " << burstTime
+ << " RSSI: " << RSSI
+ << " TOA: " << TOA
+ << " bits: " << *rxBurst;
+
+ char burstString[gSlotLen+10];
+ burstString[0] = burstTime.TN();
+ for (int i = 0; i < 4; i++)
+ burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
+ burstString[5] = RSSI;
+ burstString[6] = (TOA >> 8) & 0x0ff;
+ burstString[7] = TOA & 0x0ff;
+ SoftVector::iterator burstItr = rxBurst->begin();
+
+ for (unsigned int i = 0; i < gSlotLen; i++) {
+ burstString[8+i] =(char) round((*burstItr++)*255.0);
+ }
+ burstString[gSlotLen+9] = '\0';
+ delete rxBurst;
+
+ mDataSocket.write(burstString,gSlotLen+10);
+ }
+
+}
+
+void Transceiver::driveTransmitFIFO()
+{
+
+ /**
+ Features a carefully controlled latency mechanism, to
+ assure that transmit packets arrive at the radio/USRP
+ before they need to be transmitted.
+
+ Deadline clock indicates the burst that needs to be
+ pushed into the FIFO right NOW. If transmit queue does
+ not have a burst, stick in filler data.
+ */
+
+
+ RadioClock *radioClock = (mRadioInterface->getClock());
+
+ if (mOn) {
+ //radioClock->wait(); // wait until clock updates
+ LOG(DEBUG) << "radio clock " << radioClock->get();
+ while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
+ // if underrun, then we're not providing bursts to radio/USRP fast
+ // enough. Need to increase latency by one GSM frame.
+ if (mRadioInterface->isUnderrun()) {
+ // only do latency update every 10 frames, so we don't over update
+ if (radioClock->get() > mLatencyUpdateTime + GSM::Time(10,0)) {
+ mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
+ LOG(INFO) << "new latency: " << mTransmitLatency;
+ mLatencyUpdateTime = radioClock->get();
+ }
+ }
+ else {
+ // if underrun hasn't occurred in the last sec (216 frames) drop
+ // transmit latency by a timeslot
+ if (mTransmitLatency > GSM::Time(1,1)) {
+ if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
+ mTransmitLatency.decTN();
+ LOG(INFO) << "reduced latency: " << mTransmitLatency;
+ mLatencyUpdateTime = radioClock->get();
+ }
+ }
+ }
+ // time to push burst to transmit FIFO
+ pushRadioVector(mTransmitDeadlineClock);
+ mTransmitDeadlineClock.incTN();
+ }
+
+ }
+ // FIXME -- This should not be a hard spin.
+ // But any delay here causes us to throw omni_thread_fatal.
+ //else radioClock->wait();
+}
+
+
+
+void Transceiver::writeClockInterface()
+{
+ char command[50];
+ // FIXME -- This should be adaptive.
+ sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
+
+ LOG(INFO) << "ClockInterface: sending " << command;
+
+ mClockSocket.write(command,strlen(command)+1);
+
+ mLastClockUpdateTime = mTransmitDeadlineClock;
+
+}
+
+
+
+
+void *FIFOServiceLoopAdapter(Transceiver *transceiver)
+{
+ while (1) {
+ transceiver->driveReceiveFIFO();
+ transceiver->driveTransmitFIFO();
+ pthread_testcancel();
+ }
+ return NULL;
+}
+
+void *ControlServiceLoopAdapter(Transceiver *transceiver)
+{
+ while (1) {
+ transceiver->driveControl();
+ pthread_testcancel();
+ }
+ return NULL;
+}
+
+void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *transceiver)
+{
+ while (1) {
+ bool stale = false;
+ // Flush the UDP packets until a successful transfer.
+ while (!transceiver->driveTransmitPriorityQueue()) {
+ stale = true;
+ }
+ if (stale) {
+ // If a packet was stale, remind the GSM stack of the clock.
+ transceiver->writeClockInterface();
+ }
+ pthread_testcancel();
+ }
+ return NULL;
+}
diff --git a/Transceiver52M/Transceiver.h b/Transceiver52M/Transceiver.h
new file mode 100644
index 0000000..e724c03
--- /dev/null
+++ b/Transceiver52M/Transceiver.h
@@ -0,0 +1,207 @@
+/*
+* 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 use of this software may be subject to additional restrictions.
+* See the LEGAL 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/>.
+
+*/
+
+
+
+/*
+ Compilation switches
+ TRANSMIT_LOGGING write every burst on the given slot to a log
+*/
+
+#include "radioInterface.h"
+#include "Interthread.h"
+#include "GSMCommon.h"
+#include "Sockets.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+/** Define this to be the slot number to be logged. */
+//#define TRANSMIT_LOGGING 1
+
+/** The Transceiver class, responsible for physical layer of basestation */
+class Transceiver {
+
+private:
+
+ GSM::Time mTransmitLatency; ///< latency between basestation clock and transmit deadline clock
+ GSM::Time mLatencyUpdateTime; ///< last time latency was updated
+
+ UDPSocket mDataSocket; ///< socket for writing to/reading from GSM core
+ UDPSocket mControlSocket; ///< socket for writing/reading control commands from GSM core
+ UDPSocket mClockSocket; ///< socket for writing clock updates to GSM core
+
+ VectorQueue mTransmitPriorityQueue; ///< priority queue of transmit bursts received from GSM core
+ VectorFIFO* mTransmitFIFO; ///< radioInterface FIFO of transmit bursts
+ VectorFIFO* mReceiveFIFO; ///< radioInterface FIFO of receive bursts
+
+ Thread *mFIFOServiceLoopThread; ///< thread to push/pull bursts into transmit/receive FIFO
+ Thread *mControlServiceLoopThread; ///< thread to process control messages from GSM core
+ Thread *mTransmitPriorityQueueServiceLoopThread;///< thread to process transmit bursts from GSM core
+
+ GSM::Time mTransmitDeadlineClock; ///< deadline for pushing bursts into transmit FIFO
+ GSM::Time mLastClockUpdateTime; ///< last time clock update was sent up to core
+
+ RadioInterface *mRadioInterface; ///< associated radioInterface object
+ double txFullScale; ///< full scale input to radio
+ double rxFullScale; ///< full scale output to radio
+
+ /** Codes for burst types of received bursts*/
+ typedef enum {
+ OFF, ///< timeslot is off
+ TSC, ///< timeslot should contain a normal burst
+ RACH, ///< timeslot should contain an access burst
+ IDLE ///< timeslot is an idle (or dummy) burst
+ } CorrType;
+
+
+ /** Codes for channel combinations */
+ typedef enum {
+ FILL, ///< Channel is transmitted, but unused
+ I, ///< TCH/FS
+ II, ///< TCH/HS, idle every other slot
+ III, ///< TCH/HS
+ IV, ///< FCCH+SCH+CCCH+BCCH, uplink RACH
+ V, ///< FCCH+SCH+CCCH+BCCH+SDCCH/4+SACCH/4, uplink RACH+SDCCH/4
+ VI, ///< CCCH+BCCH, uplink RACH
+ VII, ///< SDCCH/8 + SACCH/8
+ NONE, ///< Channel is inactive, default
+ LOOPBACK ///< similar go VII, used in loopback testing
+ } ChannelCombination;
+
+
+ /** unmodulate a modulated burst */
+#ifdef TRANSMIT_LOGGING
+ void unModulateVector(signalVector wVector);
+#endif
+
+ /** modulate and add a burst to the transmit queue */
+ void addRadioVector(BitVector &burst,
+ int RSSI,
+ GSM::Time &wTime);
+
+ /** Push modulated burst into transmit FIFO corresponding to a particular timestamp */
+ void pushRadioVector(GSM::Time &nowTime);
+
+ /** Pull and demodulate a burst from the receive FIFO */
+ SoftVector *pullRadioVector(GSM::Time &wTime,
+ int &RSSI,
+ int &timingOffset);
+
+ /** Set modulus for specific timeslot */
+ void setModulus(int timeslot);
+
+ /** return the expected burst type for the specified timestamp */
+ CorrType expectedCorrType(GSM::Time currTime);
+
+ /** send messages over the clock socket */
+ void writeClockInterface(void);
+
+ signalVector *gsmPulse; ///< the GSM shaping pulse for modulation
+
+ int mSamplesPerSymbol; ///< number of samples per GSM symbol
+
+ bool mOn; ///< flag to indicate that transceiver is powered on
+ ChannelCombination mChanType[8]; ///< channel types for all timeslots
+ double mTxFreq; ///< the transmit frequency
+ double mRxFreq; ///< the receive frequency
+ int mPower; ///< the transmit power in dB
+ unsigned mTSC; ///< the midamble sequence code
+ double mEnergyThreshold; ///< threshold to determine if received data is potentially a GSM burst
+ GSM::Time prevFalseDetectionTime; ///< last timestamp of a false energy detection
+ int fillerModulus[8]; ///< modulus values of all timeslots, in frames
+ signalVector *fillerTable[102][8]; ///< table of modulated filler waveforms for all timeslots
+ unsigned mMaxExpectedDelay; ///< maximum expected time-of-arrival offset in GSM symbols
+
+ GSM::Time channelEstimateTime[8]; ///< last timestamp of each timeslot's channel estimate
+ signalVector *channelResponse[8]; ///< most recent channel estimate of all timeslots
+ float SNRestimate[8]; ///< most recent SNR estimate of all timeslots
+ signalVector *DFEForward[8]; ///< most recent DFE feedforward filter of all timeslots
+ signalVector *DFEFeedback[8]; ///< most recent DFE feedback filter of all timeslots
+ float chanRespOffset[8]; ///< most recent timing offset, e.g. TOA, of all timeslots
+ complex chanRespAmplitude[8]; ///< most recent channel amplitude of all timeslots
+
+public:
+
+ /** Transceiver constructor
+ @param wBasePort base port number of UDP sockets
+ @param TRXAddress IP address of the TRX manager, as a string
+ @param wSamplesPerSymbol number of samples per GSM symbol
+ @param wTransmitLatency initial setting of transmit latency
+ @param radioInterface associated radioInterface object
+ */
+ Transceiver(int wBasePort,
+ const char *TRXAddress,
+ int wSamplesPerSymbol,
+ GSM::Time wTransmitLatency,
+ RadioInterface *wRadioInterface);
+
+ /** Destructor */
+ ~Transceiver();
+
+ /** start the Transceiver */
+ void start();
+
+ /** attach the radioInterface receive FIFO */
+ void receiveFIFO(VectorFIFO *wFIFO) { mReceiveFIFO = wFIFO;}
+
+ /** attach the radioInterface transmit FIFO */
+ void transmitFIFO(VectorFIFO *wFIFO) { mTransmitFIFO = wFIFO;}
+
+
+protected:
+
+ /** drive reception and demodulation of GSM bursts */
+ void driveReceiveFIFO();
+
+ /** drive transmission of GSM bursts */
+ void driveTransmitFIFO();
+
+ /** drive handling of control messages from GSM core */
+ void driveControl();
+
+ /**
+ drive modulation and sorting of GSM bursts from GSM core
+ @return true if a burst was transferred successfully
+ */
+ bool driveTransmitPriorityQueue();
+
+ friend void *FIFOServiceLoopAdapter(Transceiver *);
+
+ friend void *ControlServiceLoopAdapter(Transceiver *);
+
+ friend void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *);
+
+ void reset();
+};
+
+/** FIFO thread loop */
+void *FIFOServiceLoopAdapter(Transceiver *);
+
+/** control message handler thread loop */
+void *ControlServiceLoopAdapter(Transceiver *);
+
+/** transmit queueing thread loop */
+void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *);
+
diff --git a/Transceiver52M/USRPDevice.cpp b/Transceiver52M/USRPDevice.cpp
new file mode 100644
index 0000000..7644cc7
--- /dev/null
+++ b/Transceiver52M/USRPDevice.cpp
@@ -0,0 +1,631 @@
+/*
+* Copyright 2008, 2009 Free Software Foundation, Inc.
+*
+* This software is distributed under the terms of the GNU Affero Public License.
+* See the COPYING file in the main directory for details.
+*
+* This use of this software may be subject to additional restrictions.
+* See the LEGAL 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 Affero 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+/*
+ Compilation Flags
+
+ SWLOOPBACK compile for software loopback testing
+*/
+
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include "Threads.h"
+#include "USRPDevice.h"
+
+#include <Logger.h>
+
+
+using namespace std;
+
+string write_it(unsigned v) {
+ string s = " ";
+ s[0] = (v>>16) & 0x0ff;
+ s[1] = (v>>8) & 0x0ff;
+ s[2] = (v) & 0x0ff;
+ return s;
+}
+
+
+const float USRPDevice::LO_OFFSET = 4.0e6;
+const double USRPDevice::masterClockRate = (double) 52.0e6;
+
+bool USRPDevice::compute_regs(double freq,
+ unsigned *R,
+ unsigned *control,
+ unsigned *N,
+ double *actual_freq)
+{
+ if (freq < 1.2e9) {
+ DIV2 = 1;
+ freq_mult = 2;
+ }
+ else {
+ DIV2 = 0;
+ freq_mult = 1;
+ }
+
+ float phdet_freq = masterClockRate/R_DIV;
+ int desired_n = (int) round(freq*freq_mult/phdet_freq);
+ *actual_freq = desired_n * phdet_freq/freq_mult;
+ float B = floor(desired_n/16);
+ float A = desired_n - 16*B;
+ unsigned B_DIV = int(B);
+ unsigned A_DIV = int(A);
+ if (B < A) return false;
+ *R = (R_RSV<<22) |
+ (BSC << 20) |
+ (TEST << 19) |
+ (LDP << 18) |
+ (ABP << 16) |
+ (R_DIV << 2);
+ *control = (P<<22) |
+ (PD<<20) |
+ (CP2 << 17) |
+ (CP1 << 14) |
+ (PL << 12) |
+ (MTLD << 11) |
+ (CPG << 10) |
+ (CP3S << 9) |
+ (PDP << 8) |
+ (MUXOUT << 5) |
+ (CR << 4) |
+ (PC << 2);
+ *N = (DIVSEL<<23) |
+ (DIV2<<22) |
+ (CPGAIN<<21) |
+ (B_DIV<<8) |
+ (N_RSV<<7) |
+ (A_DIV<<2);
+ return true;
+}
+
+
+bool USRPDevice::tx_setFreq(double freq, double *actual_freq)
+{
+ unsigned R, control, N;
+ if (!compute_regs(freq, &R, &control, &N, actual_freq)) return false;
+ if (R==0) return false;
+
+ writeLock.lock();
+ m_uTx->_write_spi(0,SPI_ENABLE_TX_A,SPI_FMT_MSB | SPI_FMT_HDR_0,
+ write_it((R & ~0x3) | 1));
+ m_uTx->_write_spi(0,SPI_ENABLE_TX_A,SPI_FMT_MSB | SPI_FMT_HDR_0,
+ write_it((control & ~0x3) | 0));
+ usleep(10000);
+ m_uTx->_write_spi(0,SPI_ENABLE_TX_A,SPI_FMT_MSB | SPI_FMT_HDR_0,
+ write_it((N & ~0x3) | 2));
+ writeLock.unlock();
+
+ if (m_uTx->read_io(0) & PLL_LOCK_DETECT) return true;
+ if (m_uTx->read_io(0) & PLL_LOCK_DETECT) return true;
+ return false;
+}
+
+
+bool USRPDevice::rx_setFreq(double freq, double *actual_freq)
+{
+ unsigned R, control, N;
+ if (!compute_regs(freq, &R, &control, &N, actual_freq)) return false;
+ if (R==0) return false;
+
+ writeLock.lock();
+ m_uRx->_write_spi(0,SPI_ENABLE_RX_B,SPI_FMT_MSB | SPI_FMT_HDR_0,
+ write_it((R & ~0x3) | 1));
+ m_uRx->_write_spi(0,SPI_ENABLE_RX_B,SPI_FMT_MSB | SPI_FMT_HDR_0,
+ write_it((control & ~0x3) | 0));
+ usleep(10000);
+ m_uRx->_write_spi(0,SPI_ENABLE_RX_B,SPI_FMT_MSB | SPI_FMT_HDR_0,
+ write_it((N & ~0x3) | 2));
+ writeLock.unlock();
+
+ if (m_uRx->read_io(1) & PLL_LOCK_DETECT) return true;
+ if (m_uRx->read_io(1) & PLL_LOCK_DETECT) return true;
+ return false;
+}
+
+
+USRPDevice::USRPDevice (double _desiredSampleRate)
+{
+ LOG(INFO) << "creating USRP device...";
+ decimRate = (unsigned int) round(masterClockRate/_desiredSampleRate);
+ actualSampleRate = masterClockRate/decimRate;
+ rxGain = 0;
+
+#ifdef SWLOOPBACK
+ samplePeriod = 1.0e6/actualSampleRate;
+ loopbackBufferSize = 0;
+ gettimeofday(&lastReadTime,NULL);
+ firstRead = false;
+#endif
+}
+
+bool USRPDevice::make(bool wSkipRx)
+{
+ skipRx = wSkipRx;
+
+ writeLock.unlock();
+
+ LOG(INFO) << "making USRP device..";
+#ifndef SWLOOPBACK
+ string rbf = "std_inband.rbf";
+ //string rbf = "inband_1rxhb_1tx.rbf";
+ m_uRx.reset();
+ if (!skipRx) {
+ try {
+ m_uRx = usrp_standard_rx_sptr(usrp_standard_rx::make(0,decimRate,1,-1,
+ usrp_standard_rx::FPGA_MODE_NORMAL,
+ 1024,16*8,rbf));
+#ifdef HAVE_LIBUSRP_3_2
+ m_uRx->set_fpga_master_clock_freq(masterClockRate);
+#endif
+ }
+
+ catch(...) {
+ LOG(ALERT) << "make failed on Rx";
+ m_uRx.reset();
+ return false;
+ }
+
+ if (m_uRx->fpga_master_clock_freq() != masterClockRate)
+ {
+ LOG(ALERT) << "WRONG FPGA clock freq = " << m_uRx->fpga_master_clock_freq()
+ << ", desired clock freq = " << masterClockRate;
+ m_uRx.reset();
+ return false;
+ }
+ }
+
+ try {
+ m_uTx = usrp_standard_tx_sptr(usrp_standard_tx::make(0,decimRate*2,1,-1,
+ 1024,16*8,rbf));
+#ifdef HAVE_LIBUSRP_3_2
+ m_uTx->set_fpga_master_clock_freq(masterClockRate);
+#endif
+ }
+
+ catch(...) {
+ LOG(ALERT) << "make failed on Tx";
+ m_uTx.reset();
+ return false;
+ }
+
+ if (m_uTx->fpga_master_clock_freq() != masterClockRate)
+ {
+ LOG(ALERT) << "WRONG FPGA clock freq = " << m_uTx->fpga_master_clock_freq()
+ << ", desired clock freq = " << masterClockRate;
+ m_uTx.reset();
+ return false;
+ }
+
+ if (!skipRx) m_uRx->stop();
+ m_uTx->stop();
+
+#endif
+
+ samplesRead = 0;
+ samplesWritten = 0;
+ started = false;
+
+ return true;
+}
+
+
+
+bool USRPDevice::start()
+{
+ LOG(INFO) << "starting USRP...";
+#ifndef SWLOOPBACK
+ if (!m_uRx && !skipRx) return false;
+ if (!m_uTx) return false;
+
+ if (!skipRx) m_uRx->stop();
+ m_uTx->stop();
+
+ writeLock.lock();
+ // power up and configure daughterboards
+ m_uTx->_write_oe(0,0,0xffff);
+ m_uTx->_write_oe(0,(POWER_UP|RX_TXN|ENABLE), 0xffff);
+ m_uTx->write_io(0,(~POWER_UP|RX_TXN),(POWER_UP|RX_TXN|ENABLE));
+ m_uTx->write_io(0,ENABLE,(RX_TXN | ENABLE));
+ m_uTx->_write_fpga_reg(FR_ATR_MASK_0 ,0);//RX_TXN|ENABLE);
+ m_uTx->_write_fpga_reg(FR_ATR_TXVAL_0,0);//,0 |ENABLE);
+ m_uTx->_write_fpga_reg(FR_ATR_RXVAL_0,0);//,RX_TXN|0);
+ m_uTx->_write_fpga_reg(40,0);
+ m_uTx->_write_fpga_reg(42,0);
+ m_uTx->set_pga(0,m_uTx->pga_max()); // should be 20dB
+ m_uTx->set_pga(1,m_uTx->pga_max());
+ m_uTx->set_mux(0x00000098);
+ LOG(INFO) << "TX pgas: " << m_uTx->pga(0) << ", " << m_uTx->pga(1);
+ writeLock.unlock();
+
+ if (!skipRx) {
+ writeLock.lock();
+ m_uRx->_write_fpga_reg(FR_ATR_MASK_0 + 3*3,0);
+ m_uRx->_write_fpga_reg(FR_ATR_TXVAL_0 + 3*3,0);
+ m_uRx->_write_fpga_reg(FR_ATR_RXVAL_0 + 3*3,0);
+ m_uRx->_write_fpga_reg(43,0);
+ m_uRx->_write_oe(1,(POWER_UP|RX_TXN|ENABLE), 0xffff);
+ m_uRx->write_io(1,(~POWER_UP|RX_TXN|ENABLE),(POWER_UP|RX_TXN|ENABLE));
+ //m_uRx->write_io(1,0,RX2_RX1N); // using Tx/Rx/
+ m_uRx->write_io(1,RX2_RX1N,RX2_RX1N); // using Rx2
+ m_uRx->set_adc_buffer_bypass(2,true);
+ m_uRx->set_adc_buffer_bypass(3,true);
+ m_uRx->set_mux(0x00000032);
+ writeLock.unlock();
+ // FIXME -- This should be configurable.
+ setRxGain(47); //maxRxGain());
+ }
+
+ data = new short[currDataSize];
+ dataStart = 0;
+ dataEnd = 0;
+ timeStart = 0;
+ timeEnd = 0;
+ timestampOffset = 0;
+ latestWriteTimestamp = 0;
+ lastPktTimestamp = 0;
+ hi32Timestamp = 0;
+ isAligned = false;
+
+
+ if (!skipRx)
+ started = (m_uRx->start() && m_uTx->start());
+ else
+ started = m_uTx->start();
+ return started;
+#else
+ gettimeofday(&lastReadTime,NULL);
+ return true;
+#endif
+}
+
+bool USRPDevice::stop()
+{
+#ifndef SWLOOPBACK
+ if (!m_uRx) return false;
+ if (!m_uTx) return false;
+
+ // power down
+ m_uTx->write_io(0,(~POWER_UP|RX_TXN),(POWER_UP|RX_TXN|ENABLE));
+ m_uRx->write_io(1,~POWER_UP,(POWER_UP|ENABLE));
+
+ delete[] currData;
+
+ started = !(m_uRx->stop() && m_uTx->stop());
+ return !started;
+#else
+ return true;
+#endif
+}
+
+double USRPDevice::setTxGain(double dB) {
+
+ writeLock.lock();
+ if (dB > maxTxGain()) dB = maxTxGain();
+ if (dB < minTxGain()) dB = minTxGain();
+
+ m_uTx->set_pga(0,dB);
+ m_uTx->set_pga(1,dB);
+
+ LOG(NOTICE) << "Setting TX PGA to " << dB << " dB.";
+
+ writeLock.unlock();
+
+ return dB;
+}
+
+
+double USRPDevice::setRxGain(double dB) {
+
+ writeLock.lock();
+ if (dB > maxRxGain()) dB = maxRxGain();
+ if (dB < minRxGain()) dB = minRxGain();
+
+ double dBret = dB;
+
+ dB = dB - minRxGain();
+
+ double rfMax = 70.0;
+ if (dB > rfMax) {
+ m_uRx->set_pga(2,dB-rfMax);
+ m_uRx->set_pga(3,dB-rfMax);
+ dB = rfMax;
+ }
+ else {
+ m_uRx->set_pga(2,0);
+ m_uRx->set_pga(3,0);
+ }
+ m_uRx->write_aux_dac(1,0,
+ (int) ceil((1.2 + 0.02 - (dB/rfMax))*4096.0/3.3));
+
+ LOG(DEBUG) << "Setting DAC voltage to " << (1.2+0.02 - (dB/rfMax)) << " " << (int) ceil((1.2 + 0.02 - (dB/rfMax))*4096.0/3.3);
+
+ rxGain = dBret;
+
+ writeLock.unlock();
+
+ return dBret;
+}
+
+
+// NOTE: Assumes sequential reads
+int USRPDevice::readSamples(short *buf, int len, bool *overrun,
+ TIMESTAMP timestamp,
+ bool *underrun,
+ unsigned *RSSI)
+{
+#ifndef SWLOOPBACK
+ if (!m_uRx) return 0;
+
+ timestamp += timestampOffset;
+
+ if (timestamp + len < timeStart) {
+ memset(buf,0,len*2*sizeof(short));
+ return len;
+ }
+
+ if (underrun) *underrun = false;
+
+ uint32_t readBuf[2000];
+
+ while (1) {
+ //guestimate USB read size
+ int readLen=0;
+ {
+ int numSamplesNeeded = timestamp + len - timeEnd;
+ if (numSamplesNeeded <=0) break;
+ readLen = 512 * ((int) ceil((float) numSamplesNeeded/126.0));
+ if (readLen > 8000) readLen= (8000/512)*512;
+ }
+
+ // read USRP packets, parse and save A/D data as needed
+ readLen = m_uRx->read((void *)readBuf,readLen,overrun);
+ for(int pktNum = 0; pktNum < (readLen/512); pktNum++) {
+ // tmpBuf points to start of a USB packet
+ uint32_t* tmpBuf = (uint32_t *) (readBuf+pktNum*512/4);
+ TIMESTAMP pktTimestamp = usrp_to_host_u32(tmpBuf[1]);
+ uint32_t word0 = usrp_to_host_u32(tmpBuf[0]);
+ uint32_t chan = (word0 >> 16) & 0x1f;
+ unsigned payloadSz = word0 & 0x1ff;
+ LOG(DEBUG) << "first two bytes: " << hex << word0 << " " << dec << pktTimestamp;
+
+ bool incrementHi32 = ((lastPktTimestamp & 0x0ffffffffll) > pktTimestamp);
+ if (incrementHi32 && (timeStart!=0)) {
+ LOG(DEBUG) << "high 32 increment!!!";
+ hi32Timestamp++;
+ }
+ pktTimestamp = (((TIMESTAMP) hi32Timestamp) << 32) | pktTimestamp;
+ lastPktTimestamp = pktTimestamp;
+
+ if (chan == 0x01f) {
+ // control reply, check to see if its ping reply
+ uint32_t word2 = usrp_to_host_u32(tmpBuf[2]);
+ if ((word2 >> 16) == ((0x01 << 8) | 0x02)) {
+ timestamp -= timestampOffset;
+ timestampOffset = pktTimestamp - pingTimestamp + PINGOFFSET;
+ LOG(DEBUG) << "updating timestamp offset to: " << timestampOffset;
+ timestamp += timestampOffset;
+ isAligned = true;
+ }
+ continue;
+ }
+ if (chan != 0) {
+ LOG(DEBUG) << "chan: " << chan << ", timestamp: " << pktTimestamp << ", sz:" << payloadSz;
+ continue;
+ }
+ if ((word0 >> 28) & 0x04) {
+ if (underrun) *underrun = true;
+ LOG(DEBUG) << "UNDERRUN in TRX->USRP interface";
+ }
+ if (RSSI) *RSSI = (word0 >> 21) & 0x3f;
+
+ if (!isAligned) continue;
+
+ unsigned cursorStart = pktTimestamp - timeStart + dataStart;
+ while (cursorStart*2 > currDataSize) {
+ cursorStart -= currDataSize/2;
+ }
+ if (cursorStart*2 + payloadSz/2 > currDataSize) {
+ // need to circle around buffer
+ memcpy(data+cursorStart*2,tmpBuf+2,(currDataSize-cursorStart*2)*sizeof(short));
+ memcpy(data,tmpBuf+2+(currDataSize/2-cursorStart),payloadSz-(currDataSize-cursorStart*2)*sizeof(short));
+ }
+ else {
+ memcpy(data+cursorStart*2,tmpBuf+2,payloadSz);
+ }
+ if (pktTimestamp + payloadSz/2/sizeof(short) > timeEnd)
+ timeEnd = pktTimestamp+payloadSz/2/sizeof(short);
+
+ LOG(DEBUG) << "timeStart: " << timeStart << ", timeEnd: " << timeEnd << ", pktTimestamp: " << pktTimestamp;
+
+ }
+ }
+
+ // copy desired data to buf
+ unsigned bufStart = dataStart+(timestamp-timeStart);
+ if (bufStart + len < currDataSize/2) {
+ LOG(DEBUG) << "bufStart: " << bufStart;
+ memcpy(buf,data+bufStart*2,len*2*sizeof(short));
+ memset(data+bufStart*2,0,len*2*sizeof(short));
+ }
+ else {
+ LOG(DEBUG) << "len: " << len << ", currDataSize/2: " << currDataSize/2 << ", bufStart: " << bufStart;
+ unsigned firstLength = (currDataSize/2-bufStart);
+ LOG(DEBUG) << "firstLength: " << firstLength;
+ memcpy(buf,data+bufStart*2,firstLength*2*sizeof(short));
+ memset(data+bufStart*2,0,firstLength*2*sizeof(short));
+ memcpy(buf+firstLength*2,data,(len-firstLength)*2*sizeof(short));
+ memset(data,0,(len-firstLength)*2*sizeof(short));
+ }
+ dataStart = (bufStart + len) % (currDataSize/2);
+ timeStart = timestamp + len;
+
+ // do IQ swap here
+ for (int i = 0; i < len; i++) {
+ short tmp = usrp_to_host_short(buf[2*i]);
+ buf[2*i] = usrp_to_host_short(buf[2*i+1]);
+ buf[2*i+1] = tmp;
+ }
+
+ return len;
+
+#else
+ if (loopbackBufferSize < 2) return 0;
+ int numSamples = 0;
+ struct timeval currTime;
+ gettimeofday(&currTime,NULL);
+ double timeElapsed = (currTime.tv_sec - lastReadTime.tv_sec)*1.0e6 +
+ (currTime.tv_usec - lastReadTime.tv_usec);
+ if (timeElapsed < samplePeriod) {return 0;}
+ int numSamplesToRead = (int) floor(timeElapsed/samplePeriod);
+ if (numSamplesToRead < len) return 0;
+
+ if (numSamplesToRead > len) numSamplesToRead = len;
+ if (numSamplesToRead > loopbackBufferSize/2) {
+ firstRead =false;
+ numSamplesToRead = loopbackBufferSize/2;
+ }
+ memcpy(buf,loopbackBuffer,sizeof(short)*2*numSamplesToRead);
+ loopbackBufferSize -= 2*numSamplesToRead;
+ memcpy(loopbackBuffer,loopbackBuffer+2*numSamplesToRead,
+ sizeof(short)*loopbackBufferSize);
+ numSamples = numSamplesToRead;
+ if (firstRead) {
+ int new_usec = lastReadTime.tv_usec + (int) round((double) numSamplesToRead * samplePeriod);
+ lastReadTime.tv_sec = lastReadTime.tv_sec + new_usec/1000000;
+ lastReadTime.tv_usec = new_usec % 1000000;
+ }
+ else {
+ gettimeofday(&lastReadTime,NULL);
+ firstRead = true;
+ }
+ samplesRead += numSamples;
+
+ return numSamples;
+#endif
+}
+
+int USRPDevice::writeSamples(short *buf, int len, bool *underrun,
+ unsigned long long timestamp,
+ bool isControl)
+{
+ writeLock.lock();
+
+#ifndef SWLOOPBACK
+ if (!m_uTx) return 0;
+
+ static uint32_t outData[128*20];
+
+ for (int i = 0; i < len*2; i++) {
+ buf[i] = host_to_usrp_short(buf[i]);
+ }
+
+ int numWritten = 0;
+ unsigned isStart = 1;
+ unsigned RSSI = 0;
+ unsigned CHAN = (isControl) ? 0x01f : 0x00;
+ len = len*2*sizeof(short);
+ int numPkts = (int) ceil((float)len/(float)504);
+ unsigned isEnd = (numPkts < 2);
+ uint32_t *outPkt = outData;
+ int pktNum = 0;
+ while (numWritten < len) {
+ // pkt is pointer to start of a USB packet
+ uint32_t *pkt = outPkt + pktNum*128;
+ isEnd = (len - numWritten <= 504);
+ unsigned payloadLen = ((len - numWritten) < 504) ? (len-numWritten) : 504;
+ pkt[0] = (isStart << 12 | isEnd << 11 | (RSSI & 0x3f) << 5 | CHAN) << 16 | payloadLen;
+ pkt[1] = timestamp & 0x0ffffffffll;
+ memcpy(pkt+2,buf+(numWritten/sizeof(short)),payloadLen);
+ numWritten += payloadLen;
+ timestamp += payloadLen/2/sizeof(short);
+ isStart = 0;
+ pkt[0] = host_to_usrp_u32(pkt[0]);
+ pkt[1] = host_to_usrp_u32(pkt[1]);
+ pktNum++;
+ }
+ m_uTx->write((const void*) outPkt,sizeof(uint32_t)*128*numPkts,NULL);
+
+ samplesWritten += len/2/sizeof(short);
+ writeLock.unlock();
+
+ return len/2/sizeof(short);
+#else
+ int retVal = len;
+ memcpy(loopbackBuffer+loopbackBufferSize,buf,sizeof(short)*2*len);
+ samplesWritten += retVal;
+ loopbackBufferSize += retVal*2;
+
+ return retVal;
+#endif
+}
+
+bool USRPDevice::updateAlignment(TIMESTAMP timestamp)
+{
+#ifndef SWLOOPBACK
+ short data[] = {0x00,0x02,0x00,0x00};
+ uint32_t *wordPtr = (uint32_t *) data;
+ *wordPtr = host_to_usrp_u32(*wordPtr);
+ bool tmpUnderrun;
+ if (writeSamples((short *) data,1,&tmpUnderrun,timestamp & 0x0ffffffffll,true)) {
+ pingTimestamp = timestamp;
+ return true;
+ }
+ return false;
+#else
+ return true;
+#endif
+}
+
+#ifndef SWLOOPBACK
+bool USRPDevice::setTxFreq(double wFreq) {
+ // Tune to wFreq+LO_OFFSET, to prevent LO bleedthrough from interfering with transmitted signal.
+ double actFreq;
+ if (!tx_setFreq(wFreq+1*LO_OFFSET,&actFreq)) return false;
+ bool retVal = m_uTx->set_tx_freq(0,(wFreq-actFreq));
+ LOG(INFO) << "set TX: " << wFreq-actFreq << " actual TX: " << m_uTx->tx_freq(0);
+ return retVal;
+};
+
+bool USRPDevice::setRxFreq(double wFreq) {
+ // Tune to wFreq-2*LO_OFFSET, to
+ // 1) prevent LO bleedthrough (as with the setTxFreq method above)
+ // 2) The extra LO_OFFSET pushes potential transmitter energy (GSM BS->MS transmissions
+ // are 45Mhz above MS->BS transmissions) into a notch of the baseband lowpass filter
+ // in front of the ADC. This possibly gives us an extra 10-20dB Tx/Rx isolation.
+ double actFreq;
+ // FIXME -- This should bo configurable.
+ if (!rx_setFreq(wFreq-2*LO_OFFSET,&actFreq)) return false;
+ bool retVal = m_uRx->set_rx_freq(0,(wFreq-actFreq));
+ LOG(DEBUG) << "set RX: " << wFreq-actFreq << " actual RX: " << m_uRx->rx_freq(0);
+ return retVal;
+};
+
+#else
+bool USRPDevice::setTxFreq(double wFreq) { return true;};
+bool USRPDevice::setRxFreq(double wFreq) { return true;};
+#endif
diff --git a/Transceiver52M/USRPDevice.h b/Transceiver52M/USRPDevice.h
new file mode 100644
index 0000000..19aa043
--- /dev/null
+++ b/Transceiver52M/USRPDevice.h
@@ -0,0 +1,261 @@
+/*
+* Copyright 2008 Free Software Foundation, Inc.
+*
+* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
+*
+* This use of this software may be subject to additional restrictions.
+* See the LEGAL file in the main directory for details.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+*/
+
+#ifndef _USRP_DEVICE_H_
+#define _USRP_DEVICE_H_
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "radioDevice.h"
+
+#ifdef HAVE_LIBUSRP_3_3 // [
+# include <usrp/usrp_standard.h>
+# include <usrp/usrp_bytesex.h>
+# include <usrp/usrp_prims.h>
+#else // HAVE_LIBUSRP_3_3 ][
+# include "usrp_standard.h"
+# include "usrp_bytesex.h"
+# include "usrp_prims.h"
+#endif // !HAVE_LIBUSRP_3_3 ]
+#include <sys/time.h>
+#include <math.h>
+#include <string>
+#include <iostream>
+
+
+/** Define types which are not defined in libusrp-3.1 */
+#ifndef HAVE_LIBUSRP_3_2
+#include <boost/shared_ptr.hpp>
+typedef boost::shared_ptr<usrp_standard_tx> usrp_standard_tx_sptr;
+typedef boost::shared_ptr<usrp_standard_rx> usrp_standard_rx_sptr;
+#endif // HAVE_LIBUSRP_3_2
+
+
+
+/** A class to handle a USRP rev 4, with a two RFX900 daughterboards */
+class USRPDevice: public RadioDevice {
+
+private:
+
+ static const double masterClockRate; ///< the USRP clock rate
+ double desiredSampleRate; ///< the desired sampling rate
+ usrp_standard_rx_sptr m_uRx; ///< the USRP receiver
+ usrp_standard_tx_sptr m_uTx; ///< the USRP transmitter
+
+ double actualSampleRate; ///< the actual USRP sampling rate
+ unsigned int decimRate; ///< the USRP decimation rate
+
+ unsigned long long samplesRead; ///< number of samples read from USRP
+ unsigned long long samplesWritten; ///< number of samples sent to USRP
+
+ bool started; ///< flag indicates USRP has started
+ bool skipRx; ///< set if USRP is transmit-only.
+
+ static const unsigned int currDataSize_log2 = 21;
+ static const unsigned long currDataSize = (1 << currDataSize_log2);
+ short *data;
+ unsigned long dataStart;
+ unsigned long dataEnd;
+ TIMESTAMP timeStart;
+ TIMESTAMP timeEnd;
+ bool isAligned;
+
+ Mutex writeLock;
+
+ short *currData; ///< internal data buffer when reading from USRP
+ TIMESTAMP currTimestamp; ///< timestamp of internal data buffer
+ unsigned currLen; ///< size of internal data buffer
+
+ TIMESTAMP timestampOffset; ///< timestamp offset b/w Tx and Rx blocks
+ TIMESTAMP latestWriteTimestamp; ///< timestamp of most recent ping command
+ TIMESTAMP pingTimestamp; ///< timestamp of most recent ping response
+ static const TIMESTAMP PINGOFFSET = 272; ///< undetermined delay b/w ping response timestamp and true receive timestamp
+ unsigned long hi32Timestamp;
+ unsigned long lastPktTimestamp;
+
+ double rxGain;
+
+#ifdef SWLOOPBACK
+ short loopbackBuffer[1000000];
+ int loopbackBufferSize;
+ double samplePeriod;
+
+ struct timeval startTime;
+ struct timeval lastReadTime;
+ bool firstRead;
+#endif
+
+ /** Mess of constants used to control various hardware on the USRP */
+ static const unsigned POWER_UP = (1 << 7);
+ static const unsigned RX_TXN = (1 << 6);
+ static const unsigned RX2_RX1N = (1 << 6);
+ static const unsigned ENABLE = (1 << 5);
+ static const unsigned PLL_LOCK_DETECT = (1 << 2);
+
+ static const unsigned SPI_ENABLE_TX_A = 0x10;
+ static const unsigned SPI_ENABLE_RX_A = 0x20;
+ static const unsigned SPI_ENABLE_TX_B = 0x40;
+ static const unsigned SPI_ENABLE_RX_B = 0x80;
+
+ static const unsigned SPI_FMT_MSB = (0 << 7);
+ static const unsigned SPI_FMT_HDR_0 = (0 << 5);
+
+ static const float LO_OFFSET;
+ //static const float LO_OFFSET = 4.0e6;
+
+ static const unsigned R_DIV = 16;
+ static const unsigned P = 1;
+ static const unsigned CP2 = 7;
+ static const unsigned CP1 = 7;
+ static const unsigned DIVSEL = 0;
+ unsigned DIV2; // changes with GSM band
+ unsigned freq_mult; // changes with GSM band
+ static const unsigned CPGAIN = 0;
+
+ // R-Register Common Values
+ static const unsigned R_RSV = 0; // bits 23,22
+ static const unsigned BSC = 3; // bits 21,20 Div by 8 to be safe
+ static const unsigned TEST = 0; // bit 19
+ static const unsigned LDP = 1; // bit 18
+ static const unsigned ABP = 0; // bit 17,16 3ns
+
+ // N-Register Common Values
+ static const unsigned N_RSV = 0; // bit 7
+
+ // Control Register Common Values
+ static const unsigned PD = 0; // bits 21,20 Normal operation
+ static const unsigned PL = 0; // bits 13,12 11mA
+ static const unsigned MTLD = 1; // bit 11 enabled
+ static const unsigned CPG = 0; // bit 10 CP setting 1
+ static const unsigned CP3S = 0; // bit 9 Normal
+ static const unsigned PDP = 1; // bit 8 Positive
+ static const unsigned MUXOUT = 1;// bits 7:5 Digital Lock Detect
+ static const unsigned CR = 0; // bit 4 Normal
+ static const unsigned PC = 1; // bits 3,2 Core power 10mA
+
+ // ATR register value
+ static const int FR_ATR_MASK_0 = 20;
+ static const int FR_ATR_TXVAL_0 = 21;
+ static const int FR_ATR_RXVAL_0 = 22;
+
+ /** Compute register values to tune daughterboard to desired frequency */
+ bool compute_regs(double freq,
+ unsigned *R,
+ unsigned *control,
+ unsigned *N,
+ double *actual_freq);
+
+ /** Set the transmission frequency */
+ bool tx_setFreq(double freq, double *actual_freq);
+
+ /** Set the receiver frequency */
+ bool rx_setFreq(double freq, double *actual_freq);
+
+ public:
+
+ /** Object constructor */
+ USRPDevice (double _desiredSampleRate);
+
+ /** Instantiate the USRP */
+ bool make(bool skipRx = false);
+
+ /** Start the USRP */
+ bool start();
+
+ /** Stop the USRP */
+ bool stop();
+
+ /**
+ Read samples from the USRP.
+ @param buf preallocated buf to contain read result
+ @param len number of samples desired
+ @param overrun Set if read buffer has been overrun, e.g. data not being read fast enough
+ @param timestamp The timestamp of the first samples to be read
+ @param underrun Set if USRP does not have data to transmit, e.g. data not being sent fast enough
+ @param RSSI The received signal strength of the read result
+ @return The number of samples actually read
+ */
+ int readSamples(short *buf, int len, bool *overrun,
+ TIMESTAMP timestamp = 0xffffffff,
+ bool *underrun = NULL,
+ unsigned *RSSI = NULL);
+ /**
+ Write samples to the USRP.
+ @param buf Contains the data to be written.
+ @param len number of samples to write.
+ @param underrun Set if USRP does not have data to transmit, e.g. data not being sent fast enough
+ @param timestamp The timestamp of the first sample of the data buffer.
+ @param isControl Set if data is a control packet, e.g. a ping command
+ @return The number of samples actually written
+ */
+ int writeSamples(short *buf, int len, bool *underrun,
+ TIMESTAMP timestamp = 0xffffffff,
+ bool isControl = false);
+
+ /** Update the alignment between the read and write timestamps */
+ bool updateAlignment(TIMESTAMP timestamp);
+
+ /** Set the transmitter frequency */
+ bool setTxFreq(double wFreq);
+
+ /** Set the receiver frequency */
+ bool setRxFreq(double wFreq);
+
+ /** Returns the starting write Timestamp*/
+ TIMESTAMP initialWriteTimestamp(void) { return 20000;}
+
+ /** Returns the starting read Timestamp*/
+ TIMESTAMP initialReadTimestamp(void) { return 20000;}
+
+ /** returns the full-scale transmit amplitude **/
+ double fullScaleInputValue() {return 13500.0;}
+
+ /** returns the full-scale receive amplitude **/
+ double fullScaleOutputValue() {return 9450.0;}
+
+ /** sets the receive chan gain, returns the gain setting **/
+ double setRxGain(double dB);
+
+ /** get the current receive gain */
+ double getRxGain(void) {return rxGain;}
+
+ /** return maximum Rx Gain **/
+ double maxRxGain(void) {return 97.0;}
+
+ /** return minimum Rx Gain **/
+ double minRxGain(void) {return 7.0;}
+
+ /** sets the transmit chan gain, returns the gain setting **/
+ double setTxGain(double dB);
+
+ /** return maximum Tx Gain **/
+ double maxTxGain(void) {return 0.0;}
+
+ /** return minimum Rx Gain **/
+ double minTxGain(void) {return -20.0;}
+
+
+ /** Return internal status values */
+ inline double getTxFreq() { return 0;}
+ inline double getRxFreq() { return 0;}
+ inline double getSampleRate() {return actualSampleRate;}
+ inline double numberRead() { return samplesRead; }
+ inline double numberWritten() { return samplesWritten;}
+
+};
+
+#endif // _USRP_DEVICE_H_
+
diff --git a/Transceiver52M/USRPping.cpp b/Transceiver52M/USRPping.cpp
new file mode 100644
index 0000000..b238c69
--- /dev/null
+++ b/Transceiver52M/USRPping.cpp
@@ -0,0 +1,96 @@
+/*
+* Copyright 2008, 2009 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 use of this software may be subject to additional restrictions.
+* See the LEGAL 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 <stdint.h>
+#include <stdio.h>
+#include <Logger.h>
+#include <Configuration.h>
+#include "USRPDevice.h"
+
+ConfigurationTable gConfig;
+
+using namespace std;
+
+int main(int argc, char *argv[]) {
+
+ // Configure logger.
+ if (argc>1) gLogInit(argv[1]);
+ else gLogInit("DEBUG");
+ //if (argc>2) gSetLogFile(argv[2]);
+
+ USRPDevice *usrp = new USRPDevice(52.0e6/192.0);
+
+ usrp->make();
+
+ TIMESTAMP timestamp;
+
+ usrp->setTxFreq(825.4e6);
+ usrp->setRxFreq(825.4e6);
+
+ usrp->start();
+
+ usrp->setRxGain(57);
+
+ LOG(INFO) << "Looping...";
+ bool underrun;
+
+ short data[]={0x00,0x02};
+
+ usrp->updateAlignment(20000);
+ usrp->updateAlignment(21000);
+
+ int numpkts = 1;
+ short data2[512*2*numpkts];
+ for (int i = 0; i < 512*numpkts; i++) {
+ data2[i<<1] = 10000;//4096*cos(2*3.14159*(i % 126)/126);
+ data2[(i<<1) + 1] = 10000;//4096*sin(2*3.14159*(i % 126)/126);
+ }
+
+ for (int i = 0; i < 1; i++)
+ usrp->writeSamples((short*) data2,512*numpkts,&underrun,102000+i*1000);
+
+ timestamp = 19000;
+ double sum = 0.0;
+ unsigned long num = 0;
+ while (1) {
+ short readBuf[512*2];
+ int rd = usrp->readSamples(readBuf,512,&underrun,timestamp);
+ if (rd) {
+ LOG(INFO) << "rcvd. data@:" << timestamp;
+ for (int i = 0; i < 512; i++) {
+ uint32_t *wordPtr = (uint32_t *) &readBuf[2*i];
+ *wordPtr = usrp_to_host_u32(*wordPtr);
+ printf ("%llu: %d %d\n", timestamp+i,readBuf[2*i],readBuf[2*i+1]);
+ sum += (readBuf[2*i+1]*readBuf[2*i+1] + readBuf[2*i]*readBuf[2*i]);
+ num++;
+ //if (num % 10000 == 0) printf("avg pwr: %f\n",sum/num);
+ }
+ timestamp += rd;
+ //usrp->writeSamples((short*) data2,512*numpkts,&underrun,timestamp+1000);
+ }
+ }
+
+}
diff --git a/Transceiver52M/inband-signaling-usb b/Transceiver52M/inband-signaling-usb
new file mode 100644
index 0000000..14f8347
--- /dev/null
+++ b/Transceiver52M/inband-signaling-usb
@@ -0,0 +1,314 @@
+This file specifies the format of USB packets used for in-band data
+transmission and signaling on the USRP. All packets are 512-byte long,
+and are transfered using USB "bulk" transfers.
+
+IN packets are sent towards the host.
+OUT packets are sent away from the host.
+
+The layout is 32-bits wide. All data is transmitted in little-endian
+format across the USB.
+
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |O|U|D|S|E| RSSI | Chan | mbz | Tag | Payload Len |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Timestamp |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ + +
+ | Payload |
+ . .
+ . .
+ . .
+ | |
+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ... | .
+ +-+-+-+-+-+-+-+ .
+ . .
+ . Padding .
+ . .
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+ mbz Must be Zero: these bits must be zero in both IN and OUT packets.
+
+ O Overrun Flag: set in an IN packet if an overrun condition was
+ detected. Must be zero in OUT packets. Overrun occurs when
+ the FPGA has data to transmit to the host and there is no
+ buffer space available. This generally indicates a problem on
+ the host. Either it is not keeping up, or it has configured
+ the FPGA to transmit data at a higher rate than the transport
+ (USB) can support.
+
+ U Underrun Flag: set in an IN packet if an underrun condition
+ was detected. Must be zero in OUT packets. Underrun occurs
+ when the FPGA runs out of samples, and it's not between
+ bursts. See the "End of Burst flag" below.
+
+ D Dropped Packet Flag: Set in an IN packet if the FPGA
+ discarded an OUT packet because its timestamp had already
+ passed.
+
+ S Start of Burst Flag: Set in an OUT packet if the data is the
+ first segment of what is logically a continuous burst of data.
+ Must be zero in IN packets.
+
+ E End of Burst Flag: Set in an OUT packet if the data is the
+ last segment of what is logically a continuous burst of data.
+ Must be zero in IN packets. Underruns are not reported
+ when the FPGA runs out of samples between bursts.
+
+
+ RSSI 6-bit Received Strength Signal Indicator: Must be zero in OUT
+ packets. In IN packets, indicates RSSI as reported by front end.
+ FIXME The format and interpretation are to be determined.
+
+ Chan 5-bit logical channel number. Channel number 0x1f is reserved
+ for control information. See "Control Channel" below. Other
+ channels are "data channels." Each data channel is logically
+ independent of the others. A data channel payload field
+ contains a sequence of homogeneous samples. The format of the
+ samples is determined by the configuration associated with the
+ given channel. It is often the case that the payload field
+ contains 32-bit complex samples, each containing 16-bit real
+ and imaginary components.
+
+ Tag 4-bit tag for matching IN packets with OUT packets.
+ [FIXME, write more...]
+
+ Payload Len: 9-bit field that specifies the length of the payload
+ field in bytes. Must be in the range 0 to 504 inclusive.
+
+ Timestamp: 32-bit timestamp.
+ On IN packets, the timestamp indicates the time at which the
+ first sample of the packet was produced by the A/D converter(s)
+ for that channel. On OUT packets, the timestamp specifies the
+ time at which the first sample in the packet should go out the
+ D/A converter(s) for that channel. If a packet reaches the
+ head of the transmit queue, and the current time is later than
+ the timestamp, an error is assumed to have occurred and the
+ packet is discarded. As a special case, the timestamp
+ 0xffffffff is interpreted as "Now".
+
+ The time base is a free running 32-bit counter that is
+ incremented by the A/D sample-clock.
+
+ Payload: Variable length field. Length is specified by the
+ Payload Len field.
+
+ Padding: This field is 504 - Payload Len bytes long, and its content
+ is unspecified. This field pads the packet out to a constant
+ 512 bytes.
+
+
+
+"Data Channel" payload format:
+-------------------------------
+
+If Chan != 0x1f, the packet is a "data packet" and the payload is a
+sequence of homogeneous samples. The format of the samples is
+determined by the configuration associated with the given channel.
+It is often the case that the payload field contains 32-bit complex
+samples, each containing 16-bit real and imaginary components.
+
+
+"Control Channel" payload format:
+---------------------------------
+
+If Chan == 0x1f, the packet is a "control packet". The control channel
+payload consists of a sequence of 0 or more sub-packets.
+
+Each sub-packet starts on a 32-bit boundary, and consists of an 8-bit
+Opcode field, an 8-bit Length field, Length bytes of arguments, and 0,
+1, 2 or 3 bytes of padding to align the tail of the sub-packet to
+a 32-bit boundary.
+
+Control channel packets shall be processed at the head of the queue,
+and shall observe the timestamp semantics described above.
+
+
+General sub-packet format:
+--------------------------
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-//-+-+-+-+-+-+-+-+
+ | Opcode | Length | <length bytes> ... |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-//-+-+-+-+-+-+-+-+
+
+
+Specific sub-packet formats:
+----------------------------
+
+ RID: 6-bit Request-ID. Copied from request sub-packet into corresponding
+ reply sub-packet. RID allows the host to match requests and replies.
+
+ Reg Number: 10-bit Register Number.
+
+
+
+Ping Fixed Length:
+
+ Opcode: OP_PING_FIXED
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Opcode | 2 | RID | Ping Value |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+Ping Fixed Length Reply:
+
+ Opcode: OP_PING_FIXED_REPLY
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Opcode | 2 | RID | Ping Value |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+Write Register:
+
+ Opcode: OP_WRITE_REG
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Opcode | 6 | mbz | Reg Number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Register Value |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+Write Register Masked:
+
+ Opcode: OP_WRITE_REG_MASKED
+
+ REG[Num] = (REG[Num] & ~Mask) | (Value & Mask)
+
+ That is, only the register bits that correspond to 1's in the
+ mask are written with the new value.
+
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Opcode | 10 | mbz | Reg Number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Register Value |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Mask Value |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+Read Register:
+
+ Opcode: OP_READ_REG
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Opcode | 2 | RID | Reg Number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+Read Register Reply:
+
+ Opcode: OP_READ_REG_REPLY
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Opcode | 6 | RID | Reg Number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Register Value |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+I2C Write:
+
+ Opcode: OP_I2C_WRITE
+ I2C Addr: 7-bit I2C address
+ Data: The bytes to write to the I2C bus
+ Length: Length of Data + 2
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Opcode | Length | mbz | I2C Addr |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Data ... .
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+I2C Read:
+
+ Opcode: OP_I2C_READ
+ I2C Addr: 7-bit I2C address
+ Nbytes: Number of bytes to read from I2C bus
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Opcode | 3 | RID | mbz | I2C Addr |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Nbytes | unspecified padding |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+I2C Read Reply:
+
+ Opcode: OP_I2C_READ_REPLY
+ I2C Addr: 7-bit I2C address
+ Data: Length - 2 bytes of data read from I2C bus.
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Opcode | Length | RID | mbz | I2C Addr |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Data ... .
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+SPI Write:
+
+ Opcode: OP_SPI_WRITE
+ Enables: Which SPI enables to assert (mask)
+ Format: Specifies format of SPI data and Opt Header Bytes
+ Opt Header Bytes: 2-byte field containing optional Tx bytes; see Format
+ Data: The bytes to write to the SPI bus
+ Length: Length of Data + 6
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Opcode | Length | mbz |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Enables | Format | Opt Header Bytes |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Data ... .
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+SPI Read:
+
+ Opcode: OP_SPI_READ
+ Enables: Which SPI enables to assert (mask)
+ Format: Specifies format of SPI data and Opt Header Bytes
+ Opt Header Bytes: 2-byte field containing optional Tx bytes; see Format
+ Nbytes: Number of bytes to read from SPI bus.
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Opcode | 7 | RID | mbz |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Enables | Format | Opt Header Bytes |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Nbytes | unspecified padding |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+SPI Read Reply:
+
+ Opcode: OP_SPI_READ_REPLY
+ Data: Length - 2 bytes of data read from SPI bus.
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Opcode | Length | RID | mbz |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Data ... .
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+Delay:
+
+ Opcode: OP_DELAY
+ Ticks: 16-bit unsigned delay count
+
+ Delay Ticks clock ticks before executing next operation.
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Opcode | 2 | Ticks |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
diff --git a/Transceiver52M/pulseApproximate.m b/Transceiver52M/pulseApproximate.m
new file mode 100644
index 0000000..2ff9234
--- /dev/null
+++ b/Transceiver52M/pulseApproximate.m
@@ -0,0 +1,15 @@
+pp = [0 0 0.015 0.18 0.7 0.96 0.7 0.18 0.015 0 0];
+t = -2.5:0.5:2.5;
+
+v = -0.000:-0.001:-1.999;
+
+
+for ix1 = 1:length(v),
+ disp(ix1);
+ for ix2 = 1:length(v),
+ p = exp(v(ix1)*t.^2+v(ix2)*t.^4);
+ r(ix1,ix2) = norm(p./max(abs(p)) - pp./max(abs(pp)));
+ end;
+end;
+
+
diff --git a/Transceiver52M/radioDevice.h b/Transceiver52M/radioDevice.h
new file mode 100644
index 0000000..9ca39da
--- /dev/null
+++ b/Transceiver52M/radioDevice.h
@@ -0,0 +1,115 @@
+/*
+* Copyright 2008 Free Software Foundation, Inc.
+*
+* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
+*
+* This use of this software may be subject to additional restrictions.
+* See the LEGAL file in the main directory for details.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+*/
+
+#ifndef __RADIO_DEVICE_H__
+#define __RADIO_DEVICE_H__
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/** a 64-bit virtual timestamp for radio data */
+typedef unsigned long long TIMESTAMP;
+
+/** A class to handle a USRP rev 4, with a two RFX900 daughterboards */
+class RadioDevice {
+
+ public:
+
+ /** Start the USRP */
+ virtual bool start()=0;
+
+ /** Stop the USRP */
+ virtual bool stop()=0;
+
+ /**
+ Read samples from the radio.
+ @param buf preallocated buf to contain read result
+ @param len number of samples desired
+ @param overrun Set if read buffer has been overrun, e.g. data not being read fast enough
+ @param timestamp The timestamp of the first samples to be read
+ @param underrun Set if radio does not have data to transmit, e.g. data not being sent fast enough
+ @param RSSI The received signal strength of the read result
+ @return The number of samples actually read
+ */
+ virtual int readSamples(short *buf, int len, bool *overrun,
+ TIMESTAMP timestamp,
+ bool *underrun,
+ unsigned *RSSI=NULL)=0;
+ /**
+ Write samples to the radio.
+ @param buf Contains the data to be written.
+ @param len number of samples to write.
+ @param underrun Set if radio does not have data to transmit, e.g. data not being sent fast enough
+ @param timestamp The timestamp of the first sample of the data buffer.
+ @param isControl Set if data is a control packet, e.g. a ping command
+ @return The number of samples actually written
+ */
+ virtual int writeSamples(short *buf, int len, bool *underrun,
+ TIMESTAMP timestamp,
+ bool isControl=false)=0;
+
+ /** Update the alignment between the read and write timestamps */
+ virtual bool updateAlignment(TIMESTAMP timestamp)=0;
+
+ /** Set the transmitter frequency */
+ virtual bool setTxFreq(double wFreq)=0;
+
+ /** Set the receiver frequency */
+ virtual bool setRxFreq(double wFreq)=0;
+
+ /** Returns the starting write Timestamp*/
+ virtual TIMESTAMP initialWriteTimestamp(void)=0;
+
+ /** Returns the starting read Timestamp*/
+ virtual TIMESTAMP initialReadTimestamp(void)=0;
+
+ /** returns the full-scale transmit amplitude **/
+ virtual double fullScaleInputValue()=0;
+
+ /** returns the full-scale receive amplitude **/
+ virtual double fullScaleOutputValue()=0;
+
+ /** sets the receive chan gain, returns the gain setting **/
+ virtual double setRxGain(double dB)=0;
+
+ /** gets the current receive gain **/
+ virtual double getRxGain(void)=0;
+
+ /** return maximum Rx Gain **/
+ virtual double maxRxGain(void) = 0;
+
+ /** return minimum Rx Gain **/
+ virtual double minRxGain(void) = 0;
+
+ /** sets the transmit chan gain, returns the gain setting **/
+ virtual double setTxGain(double dB)=0;
+
+ /** return maximum Tx Gain **/
+ virtual double maxTxGain(void) = 0;
+
+ /** return minimum Tx Gain **/
+ virtual double minTxGain(void) = 0;
+
+ /** Return internal status values */
+ virtual double getTxFreq()=0;
+ virtual double getRxFreq()=0;
+ virtual double getSampleRate()=0;
+ virtual double numberRead()=0;
+ virtual double numberWritten()=0;
+
+};
+
+#endif
diff --git a/Transceiver52M/radioInterface.cpp b/Transceiver52M/radioInterface.cpp
new file mode 100644
index 0000000..5266bfd
--- /dev/null
+++ b/Transceiver52M/radioInterface.cpp
@@ -0,0 +1,315 @@
+/*
+* Copyright 2008, 2009 Free Software Foundation, Inc.
+*
+* This software is distributed under the terms of the GNU Affero Public License.
+* See the COPYING file in the main directory for details.
+*
+* This use of this software may be subject to additional restrictions.
+* See the LEGAL 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 Affero 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+//#define NDEBUG
+#include "radioInterface.h"
+#include <Logger.h>
+
+
+GSM::Time VectorQueue::nextTime() const
+{
+ GSM::Time retVal;
+ ScopedLock lock(mLock);
+ while (mQ.size()==0) mWriteSignal.wait(mLock);
+ return mQ.top()->time();
+}
+
+radioVector* VectorQueue::getStaleBurst(const GSM::Time& targTime)
+{
+ ScopedLock lock(mLock);
+ if ((mQ.size()==0)) {
+ return NULL;
+ }
+ if (mQ.top()->time() < targTime) {
+ radioVector* retVal = mQ.top();
+ mQ.pop();
+ return retVal;
+ }
+ return NULL;
+}
+
+
+radioVector* VectorQueue::getCurrentBurst(const GSM::Time& targTime)
+{
+ ScopedLock lock(mLock);
+ if ((mQ.size()==0)) {
+ return NULL;
+ }
+ if (mQ.top()->time() == targTime) {
+ radioVector* retVal = mQ.top();
+ mQ.pop();
+ return retVal;
+ }
+ return NULL;
+}
+
+
+
+RadioInterface::RadioInterface(RadioDevice *wRadio,
+ int wReceiveOffset,
+ int wRadioOversampling,
+ int wTransceiverOversampling,
+ GSM::Time wStartTime)
+
+{
+ underrun = false;
+
+ sendCursor = 0;
+ rcvCursor = 0;
+ mOn = false;
+
+ mRadio = wRadio;
+ receiveOffset = wReceiveOffset;
+ samplesPerSymbol = wRadioOversampling;
+ mClock.set(wStartTime);
+ powerScaling = 1.0;
+}
+
+RadioInterface::~RadioInterface(void) {
+ if (rcvBuffer!=NULL) delete rcvBuffer;
+ //mReceiveFIFO.clear();
+}
+
+double RadioInterface::fullScaleInputValue(void) {
+ return mRadio->fullScaleInputValue();
+}
+
+double RadioInterface::fullScaleOutputValue(void) {
+ return mRadio->fullScaleOutputValue();
+}
+
+
+void RadioInterface::setPowerAttenuation(double dBAtten)
+{
+ float HWdBAtten = mRadio->setTxGain(-dBAtten);
+ dBAtten -= (-HWdBAtten);
+ float linearAtten = powf(10.0F,0.1F*dBAtten);
+ if (linearAtten < 1.0)
+ powerScaling = 1.0;
+ else
+ powerScaling = 1.0/sqrt(linearAtten);
+ LOG(INFO) << "setting HW gain to " << HWdBAtten << " and power scaling to " << powerScaling;
+}
+
+
+short *RadioInterface::radioifyVector(signalVector &wVector, short *retVector, double scale, bool zeroOut)
+{
+
+
+ signalVector::iterator itr = wVector.begin();
+ short *shortItr = retVector;
+ if (zeroOut) {
+ while (itr < wVector.end()) {
+ *shortItr++ = 0;
+ *shortItr++ = 0;
+ itr++;
+ }
+ }
+ else if (scale != 1.0) {
+ while (itr < wVector.end()) {
+ *shortItr++ = (short) (itr->real()*scale);
+ *shortItr++ = (short) (itr->imag()*scale);
+ itr++;
+ }
+ }
+ else {
+ while (itr < wVector.end()) {
+ *shortItr++ = (short) (itr->real());
+ *shortItr++ = (short) (itr->imag());
+ itr++;
+ }
+ }
+
+ return retVector;
+
+}
+
+void RadioInterface::unRadioifyVector(short *shortVector, signalVector& newVector)
+{
+
+ signalVector::iterator itr = newVector.begin();
+ short *shortItr = shortVector;
+ while (itr < newVector.end()) {
+ *itr++ = Complex<float>(*shortItr,*(shortItr+1));
+ //LOG(DEBUG) << (*(itr-1));
+ shortItr += 2;
+ }
+
+}
+
+
+bool started = false;
+
+void RadioInterface::pushBuffer(void) {
+
+ if (sendCursor < 2*INCHUNK*samplesPerSymbol) return;
+
+ // send resampleVector
+ int samplesWritten = mRadio->writeSamples(sendBuffer,
+ INCHUNK*samplesPerSymbol,
+ &underrun,
+ writeTimestamp);
+ //LOG(DEBUG) << "writeTimestamp: " << writeTimestamp << ", samplesWritten: " << samplesWritten;
+
+ writeTimestamp += (TIMESTAMP) samplesWritten;
+
+ if (sendCursor > 2*samplesWritten)
+ memcpy(sendBuffer,sendBuffer+samplesWritten*2,sizeof(short)*2*(sendCursor-2*samplesWritten));
+ sendCursor = sendCursor - 2*samplesWritten;
+}
+
+
+void RadioInterface::pullBuffer(void)
+{
+
+ bool localUnderrun;
+
+ // receive receiveVector
+ short* shortVector = rcvBuffer+rcvCursor;
+ //LOG(DEBUG) << "Reading USRP samples at timestamp " << readTimestamp;
+ int samplesRead = mRadio->readSamples(shortVector,OUTCHUNK*samplesPerSymbol,&overrun,readTimestamp,&localUnderrun);
+ underrun |= localUnderrun;
+ readTimestamp += (TIMESTAMP) samplesRead;
+ while (samplesRead < OUTCHUNK*samplesPerSymbol) {
+ int oldSamplesRead = samplesRead;
+ samplesRead += mRadio->readSamples(shortVector+2*samplesRead,
+ OUTCHUNK*samplesPerSymbol-samplesRead,
+ &overrun,
+ readTimestamp,
+ &localUnderrun);
+ underrun |= localUnderrun;
+ readTimestamp += (TIMESTAMP) (samplesRead - oldSamplesRead);
+ }
+ //LOG(DEBUG) << "samplesRead " << samplesRead;
+
+ rcvCursor += samplesRead*2;
+
+}
+
+bool RadioInterface::tuneTx(double freq)
+{
+ return mRadio->setTxFreq(freq);
+}
+
+bool RadioInterface::tuneRx(double freq)
+{
+ return mRadio->setRxFreq(freq);
+}
+
+
+void RadioInterface::start()
+{
+ LOG(INFO) << "starting radio interface...";
+ mAlignRadioServiceLoopThread.start((void * (*)(void*))AlignRadioServiceLoopAdapter,
+ (void*)this);
+ writeTimestamp = mRadio->initialWriteTimestamp();
+ readTimestamp = mRadio->initialReadTimestamp();
+ mRadio->start();
+ LOG(DEBUG) << "Radio started";
+ mRadio->updateAlignment(writeTimestamp-10000);
+ mRadio->updateAlignment(writeTimestamp-10000);
+
+ sendBuffer = new short[2*2*INCHUNK*samplesPerSymbol];
+ rcvBuffer = new short[2*2*OUTCHUNK*samplesPerSymbol];
+
+ mOn = true;
+
+}
+
+void *AlignRadioServiceLoopAdapter(RadioInterface *radioInterface)
+{
+ while (1) {
+ radioInterface->alignRadio();
+ pthread_testcancel();
+ }
+ return NULL;
+}
+
+void RadioInterface::alignRadio() {
+ sleep(60);
+ mRadio->updateAlignment(writeTimestamp+ (TIMESTAMP) 10000);
+}
+
+void RadioInterface::driveTransmitRadio(signalVector &radioBurst, bool zeroBurst) {
+
+ if (!mOn) return;
+
+ radioifyVector(radioBurst, sendBuffer+sendCursor, powerScaling, zeroBurst);
+
+ sendCursor += (radioBurst.size()*2);
+
+ pushBuffer();
+}
+
+void RadioInterface::driveReceiveRadio() {
+
+ if (!mOn) return;
+
+ if (mReceiveFIFO.size() > 8) return;
+
+ pullBuffer();
+
+ GSM::Time rcvClock = mClock.get();
+ rcvClock.decTN(receiveOffset);
+ unsigned tN = rcvClock.TN();
+ int rcvSz = rcvCursor/2;
+ int readSz = 0;
+ const int symbolsPerSlot = gSlotLen + 8;
+
+ // while there's enough data in receive buffer, form received
+ // GSM bursts and pass up to Transceiver
+ // Using the 157-156-156-156 symbols per timeslot format.
+ while (rcvSz > (symbolsPerSlot + (tN % 4 == 0))*samplesPerSymbol) {
+ signalVector rxVector((symbolsPerSlot + (tN % 4 == 0))*samplesPerSymbol);
+ unRadioifyVector(rcvBuffer+readSz*2,rxVector);
+ GSM::Time tmpTime = rcvClock;
+ if (rcvClock.FN() >= 0) {
+ //LOG(DEBUG) << "FN: " << rcvClock.FN();
+ radioVector *rxBurst = NULL;
+ if (!loadTest)
+ rxBurst = new radioVector(rxVector,tmpTime);
+ else {
+ if (tN % 4 == 0)
+ rxBurst = new radioVector(*finalVec9,tmpTime);
+ else
+ rxBurst = new radioVector(*finalVec,tmpTime);
+ }
+ mReceiveFIFO.put(rxBurst);
+ }
+ mClock.incTN();
+ rcvClock.incTN();
+ //if (mReceiveFIFO.size() >= 16) mReceiveFIFO.wait(8);
+ //LOG(DEBUG) << "receiveFIFO: wrote radio vector at time: " << mClock.get() << ", new size: " << mReceiveFIFO.size() ;
+ readSz += (symbolsPerSlot+(tN % 4 == 0))*samplesPerSymbol;
+ rcvSz -= (symbolsPerSlot+(tN % 4 == 0))*samplesPerSymbol;
+
+ tN = rcvClock.TN();
+ }
+
+ if (readSz > 0) {
+ memcpy(rcvBuffer,rcvBuffer+2*readSz,sizeof(short)*2*(rcvCursor-readSz));
+ rcvCursor = rcvCursor-2*readSz;
+ }
+}
+
diff --git a/Transceiver52M/radioInterface.h b/Transceiver52M/radioInterface.h
new file mode 100644
index 0000000..1dfb37c
--- /dev/null
+++ b/Transceiver52M/radioInterface.h
@@ -0,0 +1,243 @@
+/*
+* Copyright 2008 Free Software Foundation, Inc.
+*
+* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
+*
+* This use of this software may be subject to additional restrictions.
+* See the LEGAL file in the main directory for details.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+*/
+
+
+
+#include "sigProcLib.h"
+#include "GSMCommon.h"
+#include "LinkedLists.h"
+#include "radioDevice.h"
+
+/** samples per GSM symbol */
+#define SAMPSPERSYM 1
+#define INCHUNK (625)
+#define OUTCHUNK (625)
+
+/** class used to organize GSM bursts by GSM timestamps */
+class radioVector : public signalVector {
+
+private:
+
+ GSM::Time mTime; ///< the burst's GSM timestamp
+
+public:
+ /** constructor */
+ radioVector(const signalVector& wVector,
+ GSM::Time& wTime): signalVector(wVector),mTime(wTime) {};
+
+ /** timestamp read and write operators */
+ GSM::Time time() const { return mTime;}
+ void time(const GSM::Time& wTime) { mTime = wTime;}
+
+ /** comparison operator, used for sorting */
+ bool operator>(const radioVector& other) const {return mTime > other.mTime;}
+
+};
+
+/** a priority queue of radioVectors, i.e. GSM bursts, sorted so that earliest element is at top */
+class VectorQueue : public InterthreadPriorityQueue<radioVector> {
+
+public:
+
+ /** the top element of the queue */
+ GSM::Time nextTime() const;
+
+ /**
+ Get stale burst, if any.
+ @param targTime The target time.
+ @return Pointer to burst older than target time, removed from queue, or NULL.
+ */
+ radioVector* getStaleBurst(const GSM::Time& targTime);
+
+ /**
+ Get current burst, if any.
+ @param targTime The target time.
+ @return Pointer to burst at the target time, removed from queue, or NULL.
+ */
+ radioVector* getCurrentBurst(const GSM::Time& targTime);
+
+
+};
+
+/** a FIFO of radioVectors */
+class VectorFIFO {
+
+private:
+
+ PointerFIFO mQ;
+ Mutex mLock;
+
+public:
+
+ unsigned size() {return mQ.size();}
+
+ void put(radioVector *ptr) {ScopedLock lock(mLock); mQ.put((void*) ptr);}
+
+ radioVector *get() { ScopedLock lock(mLock); return (radioVector*) mQ.get();}
+
+};
+
+
+/** the basestation clock class */
+class RadioClock {
+
+private:
+
+ GSM::Time mClock;
+ Mutex mLock;
+ Signal updateSignal;
+
+public:
+
+ /** Set clock */
+ //void set(const GSM::Time& wTime) { ScopedLock lock(mLock); mClock = wTime; updateSignal.signal();}
+ void set(const GSM::Time& wTime) { ScopedLock lock(mLock); mClock = wTime; updateSignal.broadcast();;}
+
+ /** Increment clock */
+ //void incTN() { ScopedLock lock(mLock); mClock.incTN(); updateSignal.signal();}
+ void incTN() { ScopedLock lock(mLock); mClock.incTN(); updateSignal.broadcast();}
+
+ /** Get clock value */
+ GSM::Time get() { ScopedLock lock(mLock); return mClock; }
+
+ /** Wait until clock has changed */
+ //void wait() {ScopedLock lock(mLock); updateSignal.wait(mLock,1);}
+ // FIXME -- If we take away the timeout, a lot of threads don't start. Why?
+ void wait() {ScopedLock lock(mLock); updateSignal.wait(mLock);}
+
+};
+
+
+/** class to interface the transceiver with the USRP */
+class RadioInterface {
+
+private:
+
+ Thread mAlignRadioServiceLoopThread; ///< thread that synchronizes transmit and receive sections
+
+ VectorFIFO mReceiveFIFO; ///< FIFO that holds receive bursts
+
+ RadioDevice *mRadio; ///< the USRP object
+
+ short *sendBuffer; //[2*2*INCHUNK];
+ unsigned sendCursor;
+
+ short *rcvBuffer; //[2*2*OUTCHUNK];
+ unsigned rcvCursor;
+
+ bool underrun; ///< indicates writes to USRP are too slow
+ bool overrun; ///< indicates reads from USRP are too slow
+ TIMESTAMP writeTimestamp; ///< sample timestamp of next packet written to USRP
+ TIMESTAMP readTimestamp; ///< sample timestamp of next packet read from USRP
+
+ RadioClock mClock; ///< the basestation clock!
+
+ int samplesPerSymbol; ///< samples per GSM symbol
+ int receiveOffset; ///< offset b/w transmit and receive GSM timestamps, in timeslots
+ int mRadioOversampling;
+ int mTransceiverOversampling;
+
+ bool mOn; ///< indicates radio is on
+
+ double powerScaling;
+
+ bool loadTest;
+ int mNumARFCNs;
+ signalVector *finalVec, *finalVec9;
+
+ /** format samples to USRP */
+ short *radioifyVector(signalVector &wVector, short *shortVector, double scale, bool zeroOut);
+
+ /** format samples from USRP */
+ void unRadioifyVector(short *shortVector, signalVector &wVector);
+
+ /** push GSM bursts into the transmit buffer */
+ void pushBuffer(void);
+
+ /** pull GSM bursts from the receive buffer */
+ void pullBuffer(void);
+
+public:
+
+ /** start the interface */
+ void start();
+
+ /** constructor */
+ RadioInterface(RadioDevice* wRadio = NULL,
+ int receiveOffset = 3,
+ int wRadioOversampling = SAMPSPERSYM,
+ int wTransceiverOversampling = SAMPSPERSYM,
+ GSM::Time wStartTime = GSM::Time(0));
+
+ /** destructor */
+ ~RadioInterface();
+
+ void setSamplesPerSymbol(int wSamplesPerSymbol) {if (!mOn) samplesPerSymbol = wSamplesPerSymbol;}
+
+ int getSamplesPerSymbol() { return samplesPerSymbol;}
+
+ /** check for underrun, resets underrun value */
+ bool isUnderrun() { bool retVal = underrun; underrun = false; return retVal;}
+
+ /** attach an existing USRP to this interface */
+ void attach(RadioDevice *wRadio, int wRadioOversampling) {if (!mOn) {mRadio = wRadio; mRadioOversampling = SAMPSPERSYM;} }
+
+ /** return the receive FIFO */
+ VectorFIFO* receiveFIFO() { return &mReceiveFIFO;}
+
+ /** return the basestation clock */
+ RadioClock* getClock(void) { return &mClock;};
+
+ /** set receive gain */
+ double setRxGain(double dB) {if (mRadio) return mRadio->setRxGain(dB); else return -1;}
+
+ /** get receive gain */
+ double getRxGain(void) {if (mRadio) return mRadio->getRxGain(); else return -1;}
+
+
+ /** set transmit frequency */
+ bool tuneTx(double freq);
+
+ /** set receive frequency */
+ bool tuneRx(double freq);
+
+ /** drive transmission of GSM bursts */
+ void driveTransmitRadio(signalVector &radioBurst, bool zeroBurst);
+
+ /** drive reception of GSM bursts */
+ void driveReceiveRadio();
+
+ void setPowerAttenuation(double atten);
+
+ /** returns the full-scale transmit amplitude **/
+ double fullScaleInputValue();
+
+ /** returns the full-scale receive amplitude **/
+ double fullScaleOutputValue();
+
+
+protected:
+
+ /** drive synchronization of Tx/Rx of USRP */
+ void alignRadio();
+
+ /** reset the interface */
+ void reset();
+
+ friend void *AlignRadioServiceLoopAdapter(RadioInterface*);
+
+};
+
+/** synchronization thread loop */
+void *AlignRadioServiceLoopAdapter(RadioInterface*);
diff --git a/Transceiver52M/runTransceiver.cpp b/Transceiver52M/runTransceiver.cpp
new file mode 100644
index 0000000..d51720c
--- /dev/null
+++ b/Transceiver52M/runTransceiver.cpp
@@ -0,0 +1,123 @@
+/*
+* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
+* Copyright 2010 Kestrel Signal Processing, Inc.
+*
+* This software is distributed under the terms of the GNU Affero Public License.
+* See the COPYING file in the main directory for details.
+*
+* This use of this software may be subject to additional restrictions.
+* See the LEGAL 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 Affero 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+
+#include "Transceiver.h"
+#include "USRPDevice.h"
+#include "DummyLoad.h"
+
+#include <time.h>
+#include <signal.h>
+
+#include <GSMCommon.h>
+#include <Logger.h>
+#include <Configuration.h>
+
+using namespace std;
+
+ConfigurationTable gConfig("/etc/OpenBTS/OpenBTS.db");
+
+
+volatile bool gbShutdown = false;
+static void ctrlCHandler(int signo)
+{
+ cout << "Received shutdown signal" << endl;;
+ gbShutdown = true;
+}
+
+
+int main(int argc, char *argv[])
+{
+ if ( signal( SIGINT, ctrlCHandler ) == SIG_ERR )
+ {
+ cerr << "Couldn't install signal handler for SIGINT" << endl;
+ exit(1);
+ }
+
+ if ( signal( SIGTERM, ctrlCHandler ) == SIG_ERR )
+ {
+ cerr << "Couldn't install signal handler for SIGTERM" << endl;
+ exit(1);
+ }
+ // Configure logger.
+ gLogInit("transceiver",gConfig.getStr("Log.Level").c_str(),LOG_LOCAL7);
+
+ int numARFCN=1;
+
+ LOG(NOTICE) << "starting transceiver with " << numARFCN << " ARFCNs (argc=" << argc << ")";
+
+ srandom(time(NULL));
+
+ int mOversamplingRate = numARFCN/2 + numARFCN;
+ //DYNDevice *usrp = new DYNDevice(mOversamplingRate*1625.0e3/6.0);
+ USRPDevice *usrp = new USRPDevice(mOversamplingRate*1625.0e3/6.0);
+ //DummyLoad *usrp = new DummyLoad(mOversamplingRate*1625.0e3/6.0);
+ usrp->make();
+
+ RadioInterface* radio = new RadioInterface(usrp,3,SAMPSPERSYM,mOversamplingRate,false);
+ Transceiver *trx = new Transceiver(5700,"127.0.0.1",SAMPSPERSYM,GSM::Time(2,0),radio);
+ trx->receiveFIFO(radio->receiveFIFO());
+/*
+ signalVector *gsmPulse = generateGSMPulse(2,1);
+ BitVector normalBurstSeg = "0000101010100111110010101010010110101110011000111001101010000";
+ BitVector normalBurst(BitVector(normalBurstSeg,gTrainingSequence[0]),normalBurstSeg);
+ signalVector *modBurst = modulateBurst(normalBurst,*gsmPulse,8,1);
+ signalVector *modBurst9 = modulateBurst(normalBurst,*gsmPulse,9,1);
+ signalVector *interpolationFilter = createLPF(0.6/mOversamplingRate,6*mOversamplingRate,1);
+ signalVector totalBurst1(*modBurst,*modBurst9);
+ signalVector totalBurst2(*modBurst,*modBurst);
+ signalVector totalBurst(totalBurst1,totalBurst2);
+ scaleVector(totalBurst,usrp->fullScaleInputValue());
+ double beaconFreq = -1.0*(numARFCN-1)*200e3;
+ signalVector finalVec(625*mOversamplingRate);
+ for (int j = 0; j < numARFCN; j++) {
+ signalVector *frequencyShifter = new signalVector(625*mOversamplingRate);
+ frequencyShifter->fill(1.0);
+ frequencyShift(frequencyShifter,frequencyShifter,2.0*M_PI*(beaconFreq+j*400e3)/(1625.0e3/6.0*mOversamplingRate));
+ signalVector *interpVec = polyphaseResampleVector(totalBurst,mOversamplingRate,1,interpolationFilter);
+ multVector(*interpVec,*frequencyShifter);
+ addVector(finalVec,*interpVec);
+ }
+ signalVector::iterator itr = finalVec.begin();
+ short finalVecShort[2*finalVec.size()];
+ short *shortItr = finalVecShort;
+ while (itr < finalVec.end()) {
+ *shortItr++ = (short) (itr->real());
+ *shortItr++ = (short) (itr->imag());
+ itr++;
+ }
+ usrp->loadBurst(finalVecShort,finalVec.size());
+*/
+ trx->start();
+ //int i = 0;
+ while(!gbShutdown) { sleep(1); }//i++; if (i==60) break;}
+
+ cout << "Shutting down transceiver..." << endl;
+
+// trx->stop();
+ delete trx;
+// delete radio;
+}
diff --git a/Transceiver52M/sigProcLib.cpp b/Transceiver52M/sigProcLib.cpp
new file mode 100644
index 0000000..fe09c16
--- /dev/null
+++ b/Transceiver52M/sigProcLib.cpp
@@ -0,0 +1,1486 @@
+/*
+* Copyright 2008 Free Software Foundation, Inc.
+*
+* This software is distributed under the terms of the GNU Affero Public License.
+* See the COPYING file in the main directory for details.
+*
+* This use of this software may be subject to additional restrictions.
+* See the LEGAL 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 Affero 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+
+#define NDEBUG
+
+#include "sigProcLib.h"
+#include "GSMCommon.h"
+
+#include <Logger.h>
+
+#define TABLESIZE 1024
+
+/** Lookup tables for trigonometric approximation */
+float cosTable[TABLESIZE+1]; // add 1 element for wrap around
+float sinTable[TABLESIZE+1];
+
+/** Constants */
+static const float M_PI_F = (float)M_PI;
+static const float M_2PI_F = (float)(2.0*M_PI);
+static const float M_1_2PI_F = 1/M_2PI_F;
+
+/** Static vectors that contain a precomputed +/- f_b/4 sinusoid */
+signalVector *GMSKRotation = NULL;
+signalVector *GMSKReverseRotation = NULL;
+
+/** Static ideal RACH and midamble correlation waveforms */
+typedef struct {
+ signalVector *sequence;
+ signalVector *sequenceReversedConjugated;
+ float TOA;
+ complex gain;
+} CorrelationSequence;
+
+CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
+CorrelationSequence *gRACHSequence = NULL;
+
+void sigProcLibDestroy(void) {
+ if (GMSKRotation) {
+ delete GMSKRotation;
+ GMSKRotation = NULL;
+ }
+ if (GMSKReverseRotation) {
+ delete GMSKReverseRotation;
+ GMSKReverseRotation = NULL;
+ }
+ for (int i = 0; i < 8; i++) {
+ if (gMidambles[i]!=NULL) {
+ if (gMidambles[i]->sequence) delete gMidambles[i]->sequence;
+ if (gMidambles[i]->sequenceReversedConjugated) delete gMidambles[i]->sequenceReversedConjugated;
+ delete gMidambles[i];
+ gMidambles[i] = NULL;
+ }
+ }
+ if (gRACHSequence) {
+ if (gRACHSequence->sequence) delete gRACHSequence->sequence;
+ if (gRACHSequence->sequenceReversedConjugated) delete gRACHSequence->sequenceReversedConjugated;
+ delete gRACHSequence;
+ gRACHSequence = NULL;
+ }
+}
+
+
+
+// dB relative to 1.0.
+// if > 1.0, then return 0 dB
+float dB(float x) {
+
+ float arg = 1.0F;
+ float dB = 0.0F;
+
+ if (x >= 1.0F) return 0.0F;
+ if (x <= 0.0F) return -200.0F;
+
+ float prevArg = arg;
+ float prevdB = dB;
+ float stepSize = 16.0F;
+ float dBstepSize = 12.0F;
+ while (stepSize > 1.0F) {
+ do {
+ prevArg = arg;
+ prevdB = dB;
+ arg /= stepSize;
+ dB -= dBstepSize;
+ } while (arg > x);
+ arg = prevArg;
+ dB = prevdB;
+ stepSize *= 0.5F;
+ dBstepSize -= 3.0F;
+ }
+ return ((arg-x)*(dB-3.0F) + (x-arg*0.5F)*dB)/(arg - arg*0.5F);
+
+}
+
+// 10^(-dB/10), inverse of dB func.
+float dBinv(float x) {
+
+ float arg = 1.0F;
+ float dB = 0.0F;
+
+ if (x >= 0.0F) return 1.0F;
+ if (x <= -200.0F) return 0.0F;
+
+ float prevArg = arg;
+ float prevdB = dB;
+ float stepSize = 16.0F;
+ float dBstepSize = 12.0F;
+ while (stepSize > 1.0F) {
+ do {
+ prevArg = arg;
+ prevdB = dB;
+ arg /= stepSize;
+ dB -= dBstepSize;
+ } while (dB > x);
+ arg = prevArg;
+ dB = prevdB;
+ stepSize *= 0.5F;
+ dBstepSize -= 3.0F;
+ }
+
+ return ((dB-x)*(arg*0.5F)+(x-(dB-3.0F))*(arg))/3.0F;
+
+}
+
+float vectorNorm2(const signalVector &x)
+{
+ signalVector::const_iterator xPtr = x.begin();
+ float Energy = 0.0;
+ for (;xPtr != x.end();xPtr++) {
+ Energy += xPtr->norm2();
+ }
+ return Energy;
+}
+
+
+float vectorPower(const signalVector &x)
+{
+ return vectorNorm2(x)/x.size();
+}
+
+/** compute cosine via lookup table */
+float cosLookup(const float x)
+{
+ float arg = x*M_1_2PI_F;
+ while (arg > 1.0F) arg -= 1.0F;
+ while (arg < 0.0F) arg += 1.0F;
+
+ const float argT = arg*((float)TABLESIZE);
+ const int argI = (int)argT;
+ const float delta = argT-argI;
+ const float iDelta = 1.0F-delta;
+ return iDelta*cosTable[argI] + delta*cosTable[argI+1];
+}
+
+/** compute sine via lookup table */
+float sinLookup(const float x)
+{
+ float arg = x*M_1_2PI_F;
+ while (arg > 1.0F) arg -= 1.0F;
+ while (arg < 0.0F) arg += 1.0F;
+
+ const float argT = arg*((float)TABLESIZE);
+ const int argI = (int)argT;
+ const float delta = argT-argI;
+ const float iDelta = 1.0F-delta;
+ return iDelta*sinTable[argI] + delta*sinTable[argI+1];
+}
+
+
+/** compute e^(-jx) via lookup table. */
+complex expjLookup(float x)
+{
+ float arg = x*M_1_2PI_F;
+ while (arg > 1.0F) arg -= 1.0F;
+ while (arg < 0.0F) arg += 1.0F;
+
+ const float argT = arg*((float)TABLESIZE);
+ const int argI = (int)argT;
+ const float delta = argT-argI;
+ const float iDelta = 1.0F-delta;
+ return complex(iDelta*cosTable[argI] + delta*cosTable[argI+1],
+ iDelta*sinTable[argI] + delta*sinTable[argI+1]);
+}
+
+/** Library setup functions */
+void initTrigTables() {
+ for (int i = 0; i < TABLESIZE+1; i++) {
+ cosTable[i] = cos(2.0*M_PI*i/TABLESIZE);
+ sinTable[i] = sin(2.0*M_PI*i/TABLESIZE);
+ }
+}
+
+void initGMSKRotationTables(int samplesPerSymbol) {
+ GMSKRotation = new signalVector(157*samplesPerSymbol);
+ GMSKReverseRotation = new signalVector(157*samplesPerSymbol);
+ signalVector::iterator rotPtr = GMSKRotation->begin();
+ signalVector::iterator revPtr = GMSKReverseRotation->begin();
+ float phase = 0.0;
+ while (rotPtr != GMSKRotation->end()) {
+ *rotPtr++ = expjLookup(phase);
+ *revPtr++ = expjLookup(-phase);
+ phase += M_PI_F/2.0F/(float) samplesPerSymbol;
+ }
+}
+
+void sigProcLibSetup(int samplesPerSymbol) {
+ initTrigTables();
+ initGMSKRotationTables(samplesPerSymbol);
+}
+
+void GMSKRotate(signalVector &x) {
+ signalVector::iterator xPtr = x.begin();
+ signalVector::iterator rotPtr = GMSKRotation->begin();
+ if (x.isRealOnly()) {
+ while (xPtr < x.end()) {
+ *xPtr = *rotPtr++ * (xPtr->real());
+ xPtr++;
+ }
+ }
+ else {
+ while (xPtr < x.end()) {
+ *xPtr = *rotPtr++ * (*xPtr);
+ xPtr++;
+ }
+ }
+}
+
+void GMSKReverseRotate(signalVector &x) {
+ signalVector::iterator xPtr= x.begin();
+ signalVector::iterator rotPtr = GMSKReverseRotation->begin();
+ if (x.isRealOnly()) {
+ while (xPtr < x.end()) {
+ *xPtr = *rotPtr++ * (xPtr->real());
+ xPtr++;
+ }
+ }
+ else {
+ while (xPtr < x.end()) {
+ *xPtr = *rotPtr++ * (*xPtr);
+ xPtr++;
+ }
+ }
+}
+
+
+signalVector* convolve(const signalVector *a,
+ const signalVector *b,
+ signalVector *c,
+ ConvType spanType,
+ unsigned startIx,
+ unsigned len)
+{
+ if ((a==NULL) || (b==NULL)) return NULL;
+ int La = a->size();
+ int Lb = b->size();
+
+ int startIndex;
+ unsigned int outSize;
+ switch (spanType) {
+ case FULL_SPAN:
+ startIndex = 0;
+ outSize = La+Lb-1;
+ break;
+ case OVERLAP_ONLY:
+ startIndex = La;
+ outSize = abs(La-Lb)+1;
+ break;
+ case START_ONLY:
+ startIndex = 0;
+ outSize = La;
+ break;
+ case WITH_TAIL:
+ startIndex = Lb;
+ outSize = La;
+ break;
+ case NO_DELAY:
+ if (Lb % 2)
+ startIndex = Lb/2;
+ else
+ startIndex = Lb/2-1;
+ outSize = La;
+ break;
+ case CUSTOM:
+ startIndex = startIx;
+ outSize = len;
+ break;
+ default:
+ return NULL;
+ }
+
+
+ if (c==NULL)
+ c = new signalVector(outSize);
+ else if (c->size()!=outSize)
+ return NULL;
+
+ signalVector::const_iterator aStart = a->begin();
+ signalVector::const_iterator bStart = b->begin();
+ signalVector::const_iterator aEnd = a->end();
+ signalVector::const_iterator bEnd = b->end();
+ signalVector::iterator cPtr = c->begin();
+ int t = startIndex;
+ int stopIndex = startIndex + outSize;
+ switch (b->getSymmetry()) {
+ case NONE:
+ {
+ while (t < stopIndex) {
+ signalVector::const_iterator aP = aStart+t;
+ signalVector::const_iterator bP = bStart;
+ if (a->isRealOnly() && b->isRealOnly()) {
+ float sum = 0.0;
+ while (bP < bEnd) {
+ if (aP < aStart) break;
+ if (aP < aEnd) sum += (aP->real())*(bP->real());
+ aP--;
+ bP++;
+ }
+ *cPtr++ = sum;
+ }
+ else if (a->isRealOnly()) {
+ complex sum = 0.0;
+ while (bP < bEnd) {
+ if (aP < aStart) break;
+ if (aP < aEnd) sum += (*bP)*(aP->real());
+ aP--;
+ bP++;
+ }
+ *cPtr++ = sum;
+ }
+ else if (b->isRealOnly()) {
+ complex sum = 0.0;
+ while (bP < bEnd) {
+ if (aP < aStart) break;
+ if (aP < aEnd) sum += (*aP)*(bP->real());
+ aP--;
+ bP++;
+ }
+ *cPtr++ = sum;
+ }
+ else {
+ complex sum = 0.0;
+ while (bP < bEnd) {
+ if (aP < aStart) break;
+ if (aP < aEnd) sum += (*aP)*(*bP);
+ aP--;
+ bP++;
+ }
+ *cPtr++ = sum;
+ }
+ t++;
+ }
+ }
+ break;
+ case ABSSYM:
+ {
+ complex sum = 0.0;
+ bool isOdd = (bool) (Lb % 2);
+ if (isOdd)
+ bEnd = bStart + (Lb+1)/2;
+ else
+ bEnd = bStart + Lb/2;
+ while (t < stopIndex) {
+ signalVector::const_iterator aP = aStart+t;
+ signalVector::const_iterator aPsym = aP-Lb+1;
+ signalVector::const_iterator bP = bStart;
+ sum = 0.0;
+ if (!b->isRealOnly()) {
+ while (bP < bEnd) {
+ if (aP < aStart) break;
+ if (aP == aPsym)
+ sum+= (*aP)*(*bP);
+ else if ((aP < aEnd) && (aPsym >= aStart))
+ sum+= ((*aP)+(*aPsym))*(*bP);
+ else if (aP < aEnd)
+ sum += (*aP)*(*bP);
+ else if (aPsym >= aStart)
+ sum += (*aPsym)*(*bP);
+ aP--;
+ aPsym++;
+ bP++;
+ }
+ }
+ else {
+ while (bP < bEnd) {
+ if (aP < aStart) break;
+ if (aP == aPsym)
+ sum+= (*aP)*(bP->real());
+ else if ((aP < aEnd) && (aPsym >= aStart))
+ sum+= ((*aP)+(*aPsym))*(bP->real());
+ else if (aP < aEnd)
+ sum += (*aP)*(bP->real());
+ else if (aPsym >= aStart)
+ sum += (*aPsym)*(bP->real());
+ aP--;
+ aPsym++;
+ bP++;
+ }
+ }
+ *cPtr++ = sum;
+ t++;
+ }
+ }
+ break;
+ default:
+ return NULL;
+ break;
+ }
+
+
+ return c;
+}
+
+
+signalVector* generateGSMPulse(int symbolLength,
+ int samplesPerSymbol)
+{
+
+ int numSamples = samplesPerSymbol*symbolLength + 1;
+ signalVector *x = new signalVector(numSamples);
+ signalVector::iterator xP = x->begin();
+ int centerPoint = (numSamples-1)/2;
+ for (int i = 0; i < numSamples; i++) {
+ float arg = (float) (i-centerPoint)/(float) samplesPerSymbol;
+ *xP++ = 0.96*exp(-1.1380*arg*arg-0.527*arg*arg*arg*arg); // GSM pulse approx.
+ }
+
+ float avgAbsval = sqrtf(vectorNorm2(*x)/samplesPerSymbol);
+ xP = x->begin();
+ for (int i = 0; i < numSamples; i++)
+ *xP++ /= avgAbsval;
+ x->isRealOnly(true);
+ x->setSymmetry(ABSSYM);
+ return x;
+}
+
+signalVector* frequencyShift(signalVector *y,
+ signalVector *x,
+ float freq,
+ float startPhase,
+ float *finalPhase)
+{
+
+ if (!x) return NULL;
+
+ if (y==NULL) {
+ y = new signalVector(x->size());
+ y->isRealOnly(x->isRealOnly());
+ if (y==NULL) return NULL;
+ }
+
+ if (y->size() < x->size()) return NULL;
+
+ float phase = startPhase;
+ signalVector::iterator yP = y->begin();
+ signalVector::iterator xPEnd = x->end();
+ signalVector::iterator xP = x->begin();
+
+ if (x->isRealOnly()) {
+ while (xP < xPEnd) {
+ (*yP++) = expjLookup(phase)*( (xP++)->real() );
+ phase += freq;
+ }
+ }
+ else {
+ while (xP < xPEnd) {
+ (*yP++) = (*xP++)*expjLookup(phase);
+ phase += freq;
+ }
+ }
+
+
+ if (finalPhase) *finalPhase = phase;
+
+ return y;
+}
+
+signalVector* reverseConjugate(signalVector *b)
+{
+ signalVector *tmp = new signalVector(b->size());
+ tmp->isRealOnly(b->isRealOnly());
+ signalVector::iterator bP = b->begin();
+ signalVector::iterator bPEnd = b->end();
+ signalVector::iterator tmpP = tmp->end()-1;
+ if (!b->isRealOnly()) {
+ while (bP < bPEnd) {
+ *tmpP-- = bP->conj();
+ bP++;
+ }
+ }
+ else {
+ while (bP < bPEnd) {
+ *tmpP-- = bP->real();
+ bP++;
+ }
+ }
+
+ return tmp;
+}
+
+signalVector* correlate(signalVector *a,
+ signalVector *b,
+ signalVector *c,
+ ConvType spanType,
+ bool bReversedConjugated,
+ unsigned startIx,
+ unsigned len)
+{
+ signalVector *tmp = NULL;
+
+ if (!bReversedConjugated) {
+ tmp = reverseConjugate(b);
+ }
+ else {
+ tmp = b;
+ }
+
+ c = convolve(a,tmp,c,spanType,startIx,len);
+
+ if (!bReversedConjugated) delete tmp;
+
+ return c;
+}
+
+
+/* soft output slicer */
+bool vectorSlicer(signalVector *x)
+{
+
+ signalVector::iterator xP = x->begin();
+ signalVector::iterator xPEnd = x->end();
+ while (xP < xPEnd) {
+ *xP = (complex) (0.5*(xP->real()+1.0F));
+ if (xP->real() > 1.0) *xP = 1.0;
+ if (xP->real() < 0.0) *xP = 0.0;
+ xP++;
+ }
+ return true;
+}
+
+signalVector *modulateBurst(const BitVector &wBurst,
+ const signalVector &gsmPulse,
+ int guardPeriodLength,
+ int samplesPerSymbol)
+{
+
+ //static complex staticBurst[157];
+
+ int burstSize = samplesPerSymbol*(wBurst.size()+guardPeriodLength);
+ //signalVector modBurst((complex *) staticBurst,0,burstSize);
+ signalVector modBurst(burstSize);// = new signalVector(burstSize);
+ modBurst.isRealOnly(true);
+ //memset(staticBurst,0,sizeof(complex)*burstSize);
+ modBurst.fill(0.0);
+ signalVector::iterator modBurstItr = modBurst.begin();
+
+#if 0
+ // if wBurst is already differentially decoded
+ *modBurstItr = 2.0*(wBurst[0] & 0x01)-1.0;
+ signalVector::iterator prevVal = modBurstItr;
+ for (unsigned int i = 1; i < wBurst.size(); i++) {
+ modBurstItr += samplesPerSymbol;
+ if (wBurst[i] & 0x01)
+ *modBurstItr = *prevVal * complex(0.0,1.0);
+ else
+ *modBurstItr = *prevVal * complex(0.0,-1.0);
+ prevVal = modBurstItr;
+ }
+#else
+ // if wBurst are the raw bits
+ for (unsigned int i = 0; i < wBurst.size(); i++) {
+ *modBurstItr = 2.0*(wBurst[i] & 0x01)-1.0;
+ modBurstItr += samplesPerSymbol;
+ }
+
+ // shift up pi/2
+ // ignore starting phase, since spec allows for discontinuous phase
+ GMSKRotate(modBurst);
+#endif
+ modBurst.isRealOnly(false);
+
+ // filter w/ pulse shape
+ signalVector *shapedBurst = convolve(&modBurst,&gsmPulse,NULL,NO_DELAY);
+
+ //delete modBurst;
+
+ return shapedBurst;
+
+}
+
+float sinc(float x)
+{
+ if ((x >= 0.01F) || (x <= -0.01F)) return (sinLookup(x)/x);
+ return 1.0F;
+}
+
+void delayVector(signalVector &wBurst,
+ float delay)
+{
+
+ int intOffset = (int) floor(delay);
+ float fracOffset = delay - intOffset;
+
+ // do fractional shift first, only do it for reasonable offsets
+ if (fabs(fracOffset) > 1e-2) {
+ // create sinc function
+ signalVector sincVector(21);
+ sincVector.isRealOnly(true);
+ signalVector::iterator sincBurstItr = sincVector.begin();
+ for (int i = 0; i < 21; i++)
+ *sincBurstItr++ = (complex) sinc(M_PI_F*(i-10-fracOffset));
+
+ signalVector shiftedBurst(wBurst.size());
+ convolve(&wBurst,&sincVector,&shiftedBurst,NO_DELAY);
+ wBurst.clone(shiftedBurst);
+ }
+
+ if (intOffset < 0) {
+ intOffset = -intOffset;
+ signalVector::iterator wBurstItr = wBurst.begin();
+ signalVector::iterator shiftedItr = wBurst.begin()+intOffset;
+ while (shiftedItr < wBurst.end())
+ *wBurstItr++ = *shiftedItr++;
+ while (wBurstItr < wBurst.end())
+ *wBurstItr++ = 0.0;
+ }
+ else {
+ signalVector::iterator wBurstItr = wBurst.end()-1;
+ signalVector::iterator shiftedItr = wBurst.end()-1-intOffset;
+ while (shiftedItr >= wBurst.begin())
+ *wBurstItr-- = *shiftedItr--;
+ while (wBurstItr >= wBurst.begin())
+ *wBurstItr-- = 0.0;
+ }
+}
+
+signalVector *gaussianNoise(int length,
+ float variance,
+ complex mean)
+{
+
+ signalVector *noise = new signalVector(length);
+ signalVector::iterator nPtr = noise->begin();
+ float stddev = sqrtf(variance);
+ while (nPtr < noise->end()) {
+ float u1 = (float) rand()/ (float) RAND_MAX;
+ while (u1==0.0)
+ u1 = (float) rand()/ (float) RAND_MAX;
+ float u2 = (float) rand()/ (float) RAND_MAX;
+ float arg = 2.0*M_PI*u2;
+ *nPtr = mean + stddev*complex(cos(arg),sin(arg))*sqrtf(-2.0*log(u1));
+ nPtr++;
+ }
+
+ return noise;
+}
+
+complex interpolatePoint(const signalVector &inSig,
+ float ix)
+{
+
+ int start = (int) (floor(ix) - 10);
+ if (start < 0) start = 0;
+ int end = (int) (floor(ix) + 11);
+ if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
+
+ complex pVal = 0.0;
+ if (!inSig.isRealOnly()) {
+ for (int i = start; i < end; i++)
+ pVal += inSig[i] * sinc(M_PI_F*(i-ix));
+ }
+ else {
+ for (int i = start; i < end; i++)
+ pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
+ }
+
+ return pVal;
+}
+
+
+
+complex peakDetect(const signalVector &rxBurst,
+ float *peakIndex,
+ float *avgPwr)
+{
+
+
+ complex maxVal = 0.0;
+ float maxIndex = -1;
+ float sumPower = 0.0;
+
+ for (unsigned int i = 0; i < rxBurst.size(); i++) {
+ float samplePower = rxBurst[i].norm2();
+ if (samplePower > maxVal.real()) {
+ maxVal = samplePower;
+ maxIndex = i;
+ }
+ sumPower += samplePower;
+ }
+
+ // interpolate around the peak
+ // to save computation, we'll use early-late balancing
+ float earlyIndex = maxIndex-1;
+ float lateIndex = maxIndex+1;
+
+ float incr = 0.5;
+ while (incr > 1.0/1024.0) {
+ complex earlyP = interpolatePoint(rxBurst,earlyIndex);
+ complex lateP = interpolatePoint(rxBurst,lateIndex);
+ if (earlyP < lateP)
+ earlyIndex += incr;
+ else if (earlyP > lateP)
+ earlyIndex -= incr;
+ else break;
+ incr /= 2.0;
+ lateIndex = earlyIndex + 2.0;
+ }
+
+ maxIndex = earlyIndex + 1.0;
+ maxVal = interpolatePoint(rxBurst,maxIndex);
+
+ if (peakIndex!=NULL)
+ *peakIndex = maxIndex;
+
+ if (avgPwr!=NULL)
+ *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
+
+ return maxVal;
+
+}
+
+void scaleVector(signalVector &x,
+ complex scale)
+{
+ signalVector::iterator xP = x.begin();
+ signalVector::iterator xPEnd = x.end();
+ if (!x.isRealOnly()) {
+ while (xP < xPEnd) {
+ *xP = *xP * scale;
+ xP++;
+ }
+ }
+ else {
+ while (xP < xPEnd) {
+ *xP = xP->real() * scale;
+ xP++;
+ }
+ }
+}
+
+/** in-place conjugation */
+void conjugateVector(signalVector &x)
+{
+ if (x.isRealOnly()) return;
+ signalVector::iterator xP = x.begin();
+ signalVector::iterator xPEnd = x.end();
+ while (xP < xPEnd) {
+ *xP = xP->conj();
+ xP++;
+ }
+}
+
+
+// in-place addition!!
+bool addVector(signalVector &x,
+ signalVector &y)
+{
+ signalVector::iterator xP = x.begin();
+ signalVector::iterator yP = y.begin();
+ signalVector::iterator xPEnd = x.end();
+ signalVector::iterator yPEnd = y.end();
+ while ((xP < xPEnd) && (yP < yPEnd)) {
+ *xP = *xP + *yP;
+ xP++; yP++;
+ }
+ return true;
+}
+
+// in-place multiplication!!
+bool multVector(signalVector &x,
+ signalVector &y)
+{
+ signalVector::iterator xP = x.begin();
+ signalVector::iterator yP = y.begin();
+ signalVector::iterator xPEnd = x.end();
+ signalVector::iterator yPEnd = y.end();
+ while ((xP < xPEnd) && (yP < yPEnd)) {
+ *xP = (*xP) * (*yP);
+ xP++; yP++;
+ }
+ return true;
+}
+
+
+void offsetVector(signalVector &x,
+ complex offset)
+{
+ signalVector::iterator xP = x.begin();
+ signalVector::iterator xPEnd = x.end();
+ if (!x.isRealOnly()) {
+ while (xP < xPEnd) {
+ *xP += offset;
+ xP++;
+ }
+ }
+ else {
+ while (xP < xPEnd) {
+ *xP = xP->real() + offset;
+ xP++;
+ }
+ }
+}
+
+bool generateMidamble(signalVector &gsmPulse,
+ int samplesPerSymbol,
+ int TSC)
+{
+
+ if ((TSC < 0) || (TSC > 7))
+ return false;
+
+ if (gMidambles[TSC]) {
+ if (gMidambles[TSC]->sequence!=NULL) delete gMidambles[TSC]->sequence;
+ if (gMidambles[TSC]->sequenceReversedConjugated!=NULL) delete gMidambles[TSC]->sequenceReversedConjugated;
+ }
+
+ signalVector emptyPulse(1);
+ *(emptyPulse.begin()) = 1.0;
+
+ // only use middle 16 bits of each TSC
+ signalVector *middleMidamble = modulateBurst(gTrainingSequence[TSC].segment(5,16),
+ emptyPulse,
+ 0,
+ samplesPerSymbol);
+ signalVector *midamble = modulateBurst(gTrainingSequence[TSC],
+ gsmPulse,
+ 0,
+ samplesPerSymbol);
+
+ if (midamble == NULL) return false;
+ if (middleMidamble == NULL) return false;
+
+ // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
+ // the ideal TSC has an + 180 degree phase shift,
+ // due to the pi/2 frequency shift, that
+ // needs to be accounted for.
+ // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
+ scaleVector(*middleMidamble,complex(-1.0,0.0));
+ scaleVector(*midamble,complex(0.0,1.0));
+
+ signalVector *autocorr = correlate(midamble,middleMidamble,NULL,NO_DELAY);
+
+ if (autocorr == NULL) return false;
+
+ gMidambles[TSC] = new CorrelationSequence;
+ gMidambles[TSC]->sequence = middleMidamble;
+ gMidambles[TSC]->sequenceReversedConjugated = reverseConjugate(middleMidamble);
+ gMidambles[TSC]->gain = peakDetect(*autocorr,&gMidambles[TSC]->TOA,NULL);
+
+ LOG(DEBUG) << "midamble autocorr: " << *autocorr;
+
+ LOG(DEBUG) << "TOA: " << gMidambles[TSC]->TOA;
+
+ //gMidambles[TSC]->TOA -= 5*samplesPerSymbol;
+
+ delete autocorr;
+ delete midamble;
+
+ return true;
+}
+
+bool generateRACHSequence(signalVector &gsmPulse,
+ int samplesPerSymbol)
+{
+
+ if (gRACHSequence) {
+ if (gRACHSequence->sequence!=NULL) delete gRACHSequence->sequence;
+ if (gRACHSequence->sequenceReversedConjugated!=NULL) delete gRACHSequence->sequenceReversedConjugated;
+ }
+
+ signalVector *RACHSeq = modulateBurst(gRACHSynchSequence,
+ gsmPulse,
+ 0,
+ samplesPerSymbol);
+
+ assert(RACHSeq);
+
+ signalVector *autocorr = correlate(RACHSeq,RACHSeq,NULL,NO_DELAY);
+
+ assert(autocorr);
+
+ gRACHSequence = new CorrelationSequence;
+ gRACHSequence->sequence = RACHSeq;
+ gRACHSequence->sequenceReversedConjugated = reverseConjugate(RACHSeq);
+ gRACHSequence->gain = peakDetect(*autocorr,&gRACHSequence->TOA,NULL);
+
+ delete autocorr;
+
+ return true;
+
+}
+
+
+bool detectRACHBurst(signalVector &rxBurst,
+ float detectThreshold,
+ int samplesPerSymbol,
+ complex *amplitude,
+ float* TOA)
+{
+
+ //static complex staticData[500];
+
+ //signalVector correlatedRACH(staticData,0,rxBurst.size());
+ signalVector correlatedRACH(rxBurst.size());
+ correlate(&rxBurst,gRACHSequence->sequenceReversedConjugated,&correlatedRACH,NO_DELAY,true);
+
+ float meanPower;
+ complex peakAmpl = peakDetect(correlatedRACH,TOA,&meanPower);
+
+ float valleyPower = 0.0;
+
+ // check for bogus results
+ if ((*TOA < 0.0) || (*TOA > correlatedRACH.size())) {
+ *amplitude = 0.0;
+ return false;
+ }
+ complex *peakPtr = correlatedRACH.begin() + (int) rint(*TOA);
+
+ LOG(DEBUG) << "RACH corr: " << correlatedRACH;
+
+ float numSamples = 0.0;
+ for (int i = 57*samplesPerSymbol; i <= 107*samplesPerSymbol;i++) {
+ if (peakPtr+i >= correlatedRACH.end())
+ break;
+ valleyPower += (peakPtr+i)->norm2();
+ numSamples++;
+ }
+
+ if (numSamples < 2) {
+ *amplitude = 0.0;
+ return false;
+ }
+
+ float RMS = sqrtf(valleyPower/(float) numSamples)+0.00001;
+ float peakToMean = peakAmpl.abs()/RMS;
+
+ LOG(DEBUG) << "RACH peakAmpl=" << peakAmpl << " RMS=" << RMS << " peakToMean=" << peakToMean;
+ *amplitude = peakAmpl/(gRACHSequence->gain);
+
+ *TOA = (*TOA) - gRACHSequence->TOA - 8*samplesPerSymbol;
+
+ LOG(DEBUG) << "RACH thresh: " << peakToMean;
+
+ return (peakToMean > detectThreshold);
+}
+
+bool energyDetect(signalVector &rxBurst,
+ unsigned windowLength,
+ float detectThreshold,
+ float *avgPwr)
+{
+
+ signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
+ float energy = 0.0;
+ if (windowLength < 0) windowLength = 20;
+ if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
+ for (unsigned i = 0; i < windowLength; i++) {
+ energy += windowItr->norm2();
+ windowItr+=4;
+ }
+ if (avgPwr) *avgPwr = energy/windowLength;
+ LOG(DEBUG) << "detected energy: " << energy/windowLength;
+ return (energy/windowLength > detectThreshold*detectThreshold);
+}
+
+
+bool analyzeTrafficBurst(signalVector &rxBurst,
+ unsigned TSC,
+ float detectThreshold,
+ int samplesPerSymbol,
+ complex *amplitude,
+ float *TOA,
+ unsigned maxTOA,
+ bool requestChannel,
+ signalVector **channelResponse,
+ float *channelResponseOffset)
+{
+
+ assert(TSC<8);
+ assert(amplitude);
+ assert(TOA);
+ assert(gMidambles[TSC]);
+
+ if (maxTOA < 3*samplesPerSymbol) maxTOA = 3*samplesPerSymbol;
+ unsigned spanTOA = maxTOA;
+ if (spanTOA < 5*samplesPerSymbol) spanTOA = 5*samplesPerSymbol;
+
+ unsigned startIx = (66-spanTOA)*samplesPerSymbol;
+ unsigned endIx = (66+16+spanTOA)*samplesPerSymbol;
+ unsigned windowLen = endIx - startIx;
+ unsigned corrLen = 2*maxTOA+1;
+
+ unsigned expectedTOAPeak = (unsigned) round(gMidambles[TSC]->TOA + (gMidambles[TSC]->sequenceReversedConjugated->size()-1)/2);
+
+ signalVector burstSegment(rxBurst.begin(),startIx,windowLen);
+
+ //static complex staticData[200];
+ //signalVector correlatedBurst(staticData,0,corrLen);
+ signalVector correlatedBurst(corrLen);
+ correlate(&burstSegment, gMidambles[TSC]->sequenceReversedConjugated,
+ &correlatedBurst, CUSTOM,true,
+ expectedTOAPeak-maxTOA,corrLen);
+
+ float meanPower;
+ *amplitude = peakDetect(correlatedBurst,TOA,&meanPower);
+ float valleyPower = 0.0; //amplitude->norm2();
+ complex *peakPtr = correlatedBurst.begin() + (int) rint(*TOA);
+
+ // check for bogus results
+ if ((*TOA < 0.0) || (*TOA > correlatedBurst.size())) {
+ *amplitude = 0.0;
+ return false;
+ }
+
+ int numRms = 0;
+ for (int i = 2*samplesPerSymbol; i <= 5*samplesPerSymbol;i++) {
+ if (peakPtr - i >= correlatedBurst.begin()) {
+ valleyPower += (peakPtr-i)->norm2();
+ numRms++;
+ }
+ if (peakPtr + i < correlatedBurst.end()) {
+ valleyPower += (peakPtr+i)->norm2();
+ numRms++;
+ }
+ }
+
+ if (numRms < 2) {
+ // check for bogus results
+ *amplitude = 0.0;
+ return false;
+ }
+
+ float RMS = sqrtf(valleyPower/(float)numRms)+0.00001;
+ float peakToMean = (amplitude->abs())/RMS;
+
+ // NOTE: Because ideal TSC is 66 symbols into burst,
+ // the ideal TSC has an +/- 180 degree phase shift,
+ // due to the pi/4 frequency shift, that
+ // needs to be accounted for.
+
+ *amplitude = (*amplitude)/gMidambles[TSC]->gain;
+ *TOA = (*TOA) - (maxTOA);
+
+ LOG(DEBUG) << "TCH peakAmpl=" << amplitude->abs() << " RMS=" << RMS << " peakToMean=" << peakToMean << " TOA=" << *TOA;
+
+ LOG(DEBUG) << "autocorr: " << correlatedBurst;
+
+ if (requestChannel && (peakToMean > detectThreshold)) {
+ float TOAoffset = maxTOA; //gMidambles[TSC]->TOA+(66*samplesPerSymbol-startIx);
+ delayVector(correlatedBurst,-(*TOA));
+ // midamble only allows estimation of a 6-tap channel
+ signalVector channelVector(6*samplesPerSymbol);
+ float maxEnergy = -1.0;
+ int maxI = -1;
+ for (int i = 0; i < 7; i++) {
+ if (TOAoffset+(i-5)*samplesPerSymbol + channelVector.size() > correlatedBurst.size()) continue;
+ if (TOAoffset+(i-5)*samplesPerSymbol < 0) continue;
+ correlatedBurst.segmentCopyTo(channelVector,(int) floor(TOAoffset+(i-5)*samplesPerSymbol),channelVector.size());
+ float energy = vectorNorm2(channelVector);
+ if (energy > 0.95*maxEnergy) {
+ maxI = i;
+ maxEnergy = energy;
+ }
+ }
+
+ *channelResponse = new signalVector(channelVector.size());
+ correlatedBurst.segmentCopyTo(**channelResponse,(int) floor(TOAoffset+(maxI-5)*samplesPerSymbol),(*channelResponse)->size());
+ scaleVector(**channelResponse,complex(1.0,0.0)/gMidambles[TSC]->gain);
+ LOG(DEBUG) << "channelResponse: " << **channelResponse;
+
+ if (channelResponseOffset)
+ *channelResponseOffset = 5*samplesPerSymbol-maxI;
+
+ }
+
+ return (peakToMean > detectThreshold);
+
+}
+
+signalVector *decimateVector(signalVector &wVector,
+ int decimationFactor)
+{
+
+ if (decimationFactor <= 1) return NULL;
+
+ signalVector *decVector = new signalVector(wVector.size()/decimationFactor);
+ decVector->isRealOnly(wVector.isRealOnly());
+
+ signalVector::iterator vecItr = decVector->begin();
+ for (unsigned int i = 0; i < wVector.size();i+=decimationFactor)
+ *vecItr++ = wVector[i];
+
+ return decVector;
+}
+
+
+SoftVector *demodulateBurst(signalVector &rxBurst,
+ const signalVector &gsmPulse,
+ int samplesPerSymbol,
+ complex channel,
+ float TOA)
+
+{
+ scaleVector(rxBurst,((complex) 1.0)/channel);
+ delayVector(rxBurst,-TOA);
+
+ signalVector *shapedBurst = &rxBurst;
+
+ // shift up by a quarter of a frequency
+ // ignore starting phase, since spec allows for discontinuous phase
+ GMSKReverseRotate(*shapedBurst);
+
+ // run through slicer
+ if (samplesPerSymbol > 1) {
+ signalVector *decShapedBurst = decimateVector(*shapedBurst,samplesPerSymbol);
+ shapedBurst = decShapedBurst;
+ }
+
+ LOG(DEBUG) << "shapedBurst: " << *shapedBurst;
+
+ vectorSlicer(shapedBurst);
+
+ SoftVector *burstBits = new SoftVector(shapedBurst->size());
+
+ SoftVector::iterator burstItr = burstBits->begin();
+ signalVector::iterator shapedItr = shapedBurst->begin();
+ for (; shapedItr < shapedBurst->end(); shapedItr++)
+ *burstItr++ = shapedItr->real();
+
+ if (samplesPerSymbol > 1) delete shapedBurst;
+
+ return burstBits;
+
+}
+
+
+// 1.0 is sampling frequency
+// must satisfy cutoffFreq > 1/filterLen
+signalVector *createLPF(float cutoffFreq,
+ int filterLen,
+ float gainDC)
+{
+
+ signalVector *LPF = new signalVector(filterLen-1);
+ LPF->isRealOnly(true);
+ LPF->setSymmetry(ABSSYM);
+ signalVector::iterator itr = LPF->begin();
+ double sum = 0.0;
+ for (int i = 1; i < filterLen; i++) {
+ float ys = sinc(M_2PI_F*cutoffFreq*((float)i-(float)(filterLen)/2.0F));
+ float yg = 4.0F * cutoffFreq;
+ // Blackman -- less brickwall (sloping transition) but larger stopband attenuation
+ float yw = 0.42 - 0.5*cos(((float)i)*M_2PI_F/(float)(filterLen)) + 0.08*cos(((float)i)*2*M_2PI_F/(float)(filterLen));
+ // Hamming -- more brickwall with smaller stopband attenuation
+ //float yw = 0.53836F - 0.46164F * cos(((float)i)*M_2PI_F/(float)(filterLen+1));
+ *itr++ = (complex) ys*yg*yw;
+ sum += ys*yg*yw;
+ }
+
+ float normFactor = gainDC/sum; //sqrtf(gainDC/vectorNorm2(*LPF));
+ // normalize power
+ itr = LPF->begin();
+ for (int i = 1; i < filterLen; i++) {
+ *itr = *itr*normFactor;
+ itr++;
+ }
+ return LPF;
+
+}
+
+
+
+#define POLYPHASESPAN 10
+
+// assumes filter group delay is 0.5*(length of filter)
+signalVector *polyphaseResampleVector(signalVector &wVector,
+ int P, int Q,
+ signalVector *LPF)
+
+{
+
+ bool deleteLPF = false;
+
+ if (LPF==NULL) {
+ float cutoffFreq = (P < Q) ? (1.0/(float) Q) : (1.0/(float) P);
+ LPF = createLPF(cutoffFreq/3.0,100*POLYPHASESPAN+1,Q);
+ deleteLPF = true;
+ }
+
+ signalVector *resampledVector = new signalVector((int) ceil(wVector.size()*(float) P / (float) Q));
+ resampledVector->fill(0);
+ resampledVector->isRealOnly(wVector.isRealOnly());
+ signalVector::iterator newItr = resampledVector->begin();
+
+ //FIXME: need to update for real-only vectors
+ int outputIx = (LPF->size()+1)/2/Q; //((P > Q) ? P : Q);
+ while (newItr < resampledVector->end()) {
+ int outputBranch = (outputIx*Q) % P;
+ int inputOffset = (outputIx*Q - outputBranch)/P;
+ signalVector::const_iterator inputItr = wVector.begin() + inputOffset;
+ signalVector::const_iterator filtItr = LPF->begin() + outputBranch;
+ while (inputItr >= wVector.end()) {
+ inputItr--;
+ filtItr+=P;
+ }
+ complex sum = 0.0;
+ if ((LPF->getSymmetry()!=ABSSYM) || (P>1)) {
+ if (!LPF->isRealOnly()) {
+ while ( (inputItr >= wVector.begin()) && (filtItr < LPF->end()) ) {
+ sum += (*inputItr)*(*filtItr);
+ inputItr--;
+ filtItr += P;
+ }
+ }
+ else {
+ while ( (inputItr >= wVector.begin()) && (filtItr < LPF->end()) ) {
+ sum += (*inputItr)*(filtItr->real());
+ inputItr--;
+ filtItr += P;
+ }
+ }
+ }
+ else {
+ signalVector::const_iterator revInputItr = inputItr- LPF->size() + 1;
+ signalVector::const_iterator filtMidpoint = LPF->begin()+(LPF->size()-1)/2;
+ if (!LPF->isRealOnly()) {
+ while (filtItr <= filtMidpoint) {
+ if (inputItr < revInputItr) break;
+ if (inputItr == revInputItr)
+ sum += (*inputItr)*(*filtItr);
+ else if ( (inputItr < wVector.end()) && (revInputItr >= wVector.begin()) )
+ sum += (*inputItr + *revInputItr)*(*filtItr);
+ else if ( inputItr < wVector.end() )
+ sum += (*inputItr)*(*filtItr);
+ else if ( revInputItr >= wVector.begin() )
+ sum += (*revInputItr)*(*filtItr);
+ inputItr--;
+ revInputItr++;
+ filtItr++;
+ }
+ }
+ else {
+ while (filtItr <= filtMidpoint) {
+ if (inputItr < revInputItr) break;
+ if (inputItr == revInputItr)
+ sum += (*inputItr)*(filtItr->real());
+ else if ( (inputItr < wVector.end()) && (revInputItr >= wVector.begin()) )
+ sum += (*inputItr + *revInputItr)*(filtItr->real());
+ else if ( inputItr < wVector.end() )
+ sum += (*inputItr)*(filtItr->real());
+ else if ( revInputItr >= wVector.begin() )
+ sum += (*revInputItr)*(filtItr->real());
+ inputItr--;
+ revInputItr++;
+ filtItr++;
+ }
+ }
+ }
+ *newItr = sum;
+ newItr++;
+ outputIx++;
+ }
+
+ if (deleteLPF) delete LPF;
+
+ return resampledVector;
+}
+
+
+signalVector *resampleVector(signalVector &wVector,
+ float expFactor,
+ complex endPoint)
+
+{
+
+ if (expFactor < 1.0) return NULL;
+
+ signalVector *retVec = new signalVector((int) ceil(wVector.size()*expFactor));
+
+ float t = 0.0;
+
+ signalVector::iterator retItr = retVec->begin();
+ while (retItr < retVec->end()) {
+ unsigned tLow = (unsigned int) floor(t);
+ unsigned tHigh = tLow + 1;
+ if (tLow > wVector.size()-1) break;
+ if (tHigh > wVector.size()) break;
+ complex lowPoint = wVector[tLow];
+ complex highPoint = (tHigh == wVector.size()) ? endPoint : wVector[tHigh];
+ complex a = (tHigh-t);
+ complex b = (t-tLow);
+ *retItr = (a*lowPoint + b*highPoint);
+ t += 1.0/expFactor;
+ }
+
+ return retVec;
+
+}
+
+
+// Assumes symbol-spaced sampling!!!
+// Based upon paper by Al-Dhahir and Cioffi
+bool designDFE(signalVector &channelResponse,
+ float SNRestimate,
+ int Nf,
+ signalVector **feedForwardFilter,
+ signalVector **feedbackFilter)
+{
+
+ signalVector G0(Nf);
+ signalVector G1(Nf);
+ signalVector::iterator G0ptr = G0.begin();
+ signalVector::iterator G1ptr = G1.begin();
+ signalVector::iterator chanPtr = channelResponse.begin();
+
+ int nu = channelResponse.size()-1;
+
+ *G0ptr = 1.0/sqrtf(SNRestimate);
+ for(int j = 0; j <= nu; j++) {
+ *G1ptr = chanPtr->conj();
+ G1ptr++; chanPtr++;
+ }
+
+ signalVector *L[Nf];
+ signalVector::iterator Lptr;
+ float d;
+ for(int i = 0; i < Nf; i++) {
+ d = G0.begin()->norm2() + G1.begin()->norm2();
+ L[i] = new signalVector(Nf+nu);
+ Lptr = L[i]->begin()+i;
+ G0ptr = G0.begin(); G1ptr = G1.begin();
+ while ((G0ptr < G0.end()) && (Lptr < L[i]->end())) {
+ *Lptr = (*G0ptr*(G0.begin()->conj()) + *G1ptr*(G1.begin()->conj()) )/d;
+ Lptr++;
+ G0ptr++;
+ G1ptr++;
+ }
+ complex k = (*G1.begin())/(*G0.begin());
+
+ if (i != Nf-1) {
+ signalVector G0new = G1;
+ scaleVector(G0new,k.conj());
+ addVector(G0new,G0);
+
+ signalVector G1new = G0;
+ scaleVector(G1new,k*(-1.0));
+ addVector(G1new,G1);
+ delayVector(G1new,-1.0);
+
+ scaleVector(G0new,1.0/sqrtf(1.0+k.norm2()));
+ scaleVector(G1new,1.0/sqrtf(1.0+k.norm2()));
+ G0 = G0new;
+ G1 = G1new;
+ }
+ }
+
+ *feedbackFilter = new signalVector(nu);
+ L[Nf-1]->segmentCopyTo(**feedbackFilter,Nf,nu);
+ scaleVector(**feedbackFilter,(complex) -1.0);
+ conjugateVector(**feedbackFilter);
+
+ signalVector v(Nf);
+ signalVector::iterator vStart = v.begin();
+ signalVector::iterator vPtr;
+ *(vStart+Nf-1) = (complex) 1.0;
+ for(int k = Nf-2; k >= 0; k--) {
+ Lptr = L[k]->begin()+k+1;
+ vPtr = vStart + k+1;
+ complex v_k = 0.0;
+ for (int j = k+1; j < Nf; j++) {
+ v_k -= (*vPtr)*(*Lptr);
+ vPtr++; Lptr++;
+ }
+ *(vStart + k) = v_k;
+ }
+
+ *feedForwardFilter = new signalVector(Nf);
+ signalVector::iterator w = (*feedForwardFilter)->begin();
+ for (int i = 0; i < Nf; i++) {
+ delete L[i];
+ complex w_i = 0.0;
+ int endPt = ( nu < (Nf-1-i) ) ? nu : (Nf-1-i);
+ vPtr = vStart+i;
+ chanPtr = channelResponse.begin();
+ for (int k = 0; k < endPt+1; k++) {
+ w_i += (*vPtr)*(chanPtr->conj());
+ vPtr++; chanPtr++;
+ }
+ *w = w_i/d;
+ w++;
+ }
+
+
+ return true;
+
+}
+
+// Assumes symbol-rate sampling!!!!
+SoftVector *equalizeBurst(signalVector &rxBurst,
+ float TOA,
+ int samplesPerSymbol,
+ signalVector &w, // feedforward filter
+ signalVector &b) // feedback filter
+{
+
+ delayVector(rxBurst,-TOA);
+
+ signalVector* postForwardFull = convolve(&rxBurst,&w,NULL,FULL_SPAN);
+
+ signalVector* postForward = new signalVector(rxBurst.size());
+ postForwardFull->segmentCopyTo(*postForward,w.size()-1,rxBurst.size());
+ delete postForwardFull;
+
+ signalVector::iterator dPtr = postForward->begin();
+ signalVector::iterator dBackPtr;
+ signalVector::iterator rotPtr = GMSKRotation->begin();
+ signalVector::iterator revRotPtr = GMSKReverseRotation->begin();
+
+ signalVector *DFEoutput = new signalVector(postForward->size());
+ signalVector::iterator DFEItr = DFEoutput->begin();
+
+ // NOTE: can insert the midamble and/or use midamble to estimate BER
+ for (; dPtr < postForward->end(); dPtr++) {
+ dBackPtr = dPtr-1;
+ signalVector::iterator bPtr = b.begin();
+ while ( (bPtr < b.end()) && (dBackPtr >= postForward->begin()) ) {
+ *dPtr = *dPtr + (*bPtr)*(*dBackPtr);
+ bPtr++;
+ dBackPtr--;
+ }
+ *dPtr = *dPtr * (*revRotPtr);
+ *DFEItr = *dPtr;
+ // make decision on symbol
+ *dPtr = (dPtr->real() > 0.0) ? 1.0 : -1.0;
+ //*DFEItr = *dPtr;
+ *dPtr = *dPtr * (*rotPtr);
+ DFEItr++;
+ rotPtr++;
+ revRotPtr++;
+ }
+
+ vectorSlicer(DFEoutput);
+
+ SoftVector *burstBits = new SoftVector(postForward->size());
+ SoftVector::iterator burstItr = burstBits->begin();
+ DFEItr = DFEoutput->begin();
+ for (; DFEItr < DFEoutput->end(); DFEItr++)
+ *burstItr++ = DFEItr->real();
+
+ delete postForward;
+
+ delete DFEoutput;
+
+ return burstBits;
+}
diff --git a/Transceiver52M/sigProcLib.h b/Transceiver52M/sigProcLib.h
new file mode 100644
index 0000000..f9f0dce
--- /dev/null
+++ b/Transceiver52M/sigProcLib.h
@@ -0,0 +1,386 @@
+/*
+* Copyright 2008 Free Software Foundation, Inc.
+*
+* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
+*
+* This use of this software may be subject to additional restrictions.
+* See the LEGAL file in the main directory for details.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+*/
+
+
+
+#include "Vector.h"
+#include "Complex.h"
+#include "GSMTransfer.h"
+
+
+using namespace GSM;
+
+/** Indicated signalVector symmetry */
+typedef enum Symmetry {
+ NONE = 0,
+ ABSSYM = 1
+};
+
+/** Convolution type indicator */
+typedef enum ConvType {
+ FULL_SPAN = 0,
+ OVERLAP_ONLY = 1,
+ START_ONLY = 2,
+ WITH_TAIL = 3,
+ NO_DELAY = 4,
+ CUSTOM = 5,
+ UNDEFINED = 255
+};
+
+/** the core data structure of the Transceiver */
+class signalVector: public Vector<complex>
+{
+
+ private:
+
+ Symmetry symmetry; ///< the symmetry of the vector
+ bool realOnly; ///< true if vector is real-valued, not complex-valued
+
+ public:
+
+ /** Constructors */
+ signalVector(int dSize=0, Symmetry wSymmetry = NONE):
+ Vector<complex>(dSize),
+ realOnly(false)
+ {
+ symmetry = wSymmetry;
+ };
+
+ signalVector(complex* wData, size_t start,
+ size_t span, Symmetry wSymmetry = NONE):
+ Vector<complex>(NULL,wData+start,wData+start+span),
+ realOnly(false)
+ {
+ symmetry = wSymmetry;
+ };
+
+ signalVector(const signalVector &vec1, const signalVector &vec2):
+ Vector<complex>(vec1,vec2),
+ realOnly(false)
+ {
+ symmetry = vec1.symmetry;
+ };
+
+ signalVector(const signalVector &wVector):
+ Vector<complex>(wVector.size()),
+ realOnly(false)
+ {
+ wVector.copyTo(*this);
+ symmetry = wVector.getSymmetry();
+ };
+
+ /** symmetry operators */
+ Symmetry getSymmetry() const { return symmetry;};
+ void setSymmetry(Symmetry wSymmetry) { symmetry = wSymmetry;};
+
+ /** real-valued operators */
+ bool isRealOnly() const { return realOnly;};
+ void isRealOnly(bool wOnly) { realOnly = wOnly;};
+};
+
+/** Convert a linear number to a dB value */
+float dB(float x);
+
+/** Convert a dB value into a linear value */
+float dBinv(float x);
+
+/** Compute the energy of a vector */
+float vectorNorm2(const signalVector &x);
+
+/** Compute the average power of a vector */
+float vectorPower(const signalVector &x);
+
+/** Setup the signal processing library */
+void sigProcLibSetup(int samplesPerSymbol);
+
+/** Destroy the signal processing library */
+void sigProcLibDestroy(void);
+
+/**
+ Convolve two vectors.
+ @param a,b The vectors to be convolved.
+ @param c, A preallocated vector to hold the convolution result.
+ @param spanType The type/span of the convolution.
+ @return The convolution result.
+*/
+signalVector* convolve(const signalVector *a,
+ const signalVector *b,
+ signalVector *c,
+ ConvType spanType,
+ unsigned startIx = 0,
+ unsigned len = 0);
+
+/**
+ Generate the GSM pulse.
+ @param samplesPerSymbol The number of samples per GSM symbol.
+ @param symbolLength The size of the pulse.
+ @return The GSM pulse.
+*/
+signalVector* generateGSMPulse(int samplesPerSymbol,
+ int symbolLength);
+
+/**
+ Frequency shift a vector.
+ @param y The frequency shifted vector.
+ @param x The vector to-be-shifted.
+ @param freq The digital frequency shift
+ @param startPhase The starting phase of the oscillator
+ @param finalPhase The final phase of the oscillator
+ @return The frequency shifted vector.
+*/
+signalVector* frequencyShift(signalVector *y,
+ signalVector *x,
+ float freq = 0.0,
+ float startPhase = 0.0,
+ float *finalPhase=NULL);
+
+/**
+ Correlate two vectors.
+ @param a,b The vectors to be correlated.
+ @param c, A preallocated vector to hold the correlation result.
+ @param spanType The type/span of the correlation.
+ @return The correlation result.
+*/
+signalVector* correlate(signalVector *a,
+ signalVector *b,
+ signalVector *c,
+ ConvType spanType,
+ bool bReversedConjugated = false,
+ unsigned startIx = 0,
+ unsigned len = 0);
+
+/** Operate soft slicer on real-valued portion of vector */
+bool vectorSlicer(signalVector *x);
+
+/** GMSK modulate a GSM burst of bits */
+signalVector *modulateBurst(const BitVector &wBurst,
+ const signalVector &gsmPulse,
+ int guardPeriodLength,
+ int samplesPerSymbol);
+
+/** Sinc function */
+float sinc(float x);
+
+/** Delay a vector */
+void delayVector(signalVector &wBurst,
+ float delay);
+
+/** Add two vectors in-place */
+bool addVector(signalVector &x,
+ signalVector &y);
+
+/** Multiply two vectors in-place*/
+bool multVector(signalVector &x,
+ signalVector &y);
+
+/** Generate a vector of gaussian noise */
+signalVector *gaussianNoise(int length,
+ float variance = 1.0,
+ complex mean = complex(0.0));
+
+/**
+ Given a non-integer index, interpolate a sample.
+ @param inSig The signal from which to interpolate.
+ @param ix The index.
+ @return The interpolated signal value.
+*/
+complex interpolatePoint(const signalVector &inSig,
+ float ix);
+
+/**
+ Given a correlator output, locate the correlation peak.
+ @param rxBurst The correlator result.
+ @param peakIndex Pointer to value to receive interpolated peak index.
+ @param avgPower Power to value to receive mean power.
+ @return Peak value.
+*/
+complex peakDetect(const signalVector &rxBurst,
+ float *peakIndex,
+ float *avgPwr);
+
+/**
+ Apply a scalar to a vector.
+ @param x The vector of interest.
+ @param scale The scalar.
+*/
+void scaleVector(signalVector &x,
+ complex scale);
+
+/**
+ Add a constant offset to a vecotr.
+ @param x The vector of interest.
+ @param offset The offset.
+*/
+void offsetVector(signalVector &x,
+ complex offset);
+
+/**
+ Generate a modulated GSM midamble, stored within the library.
+ @param gsmPulse The GSM pulse used for modulation.
+ @param samplesPerSymbol The number of samples per GSM symbol.
+ @param TSC The training sequence [0..7]
+ @return Success.
+*/
+bool generateMidamble(signalVector &gsmPulse,
+ int samplesPerSymbol,
+ int TSC);
+/**
+ Generate a modulated RACH sequence, stored within the library.
+ @param gsmPulse The GSM pulse used for modulation.
+ @param samplesPerSymbol The number of samples per GSM symbol.
+ @return Success.
+*/
+bool generateRACHSequence(signalVector &gsmPulse,
+ int samplesPerSymbol);
+
+/**
+ Energy detector, checks to see if received burst energy is above a threshold.
+ @param rxBurst The received GSM burst of interest.
+ @param windowLength The number of burst samples used to compute burst energy
+ @param detectThreshold The detection threshold, a linear value.
+ @param avgPwr The average power of the received burst.
+ @return True if burst energy is above threshold.
+*/
+bool energyDetect(signalVector &rxBurst,
+ unsigned windowLength,
+ float detectThreshold,
+ float *avgPwr = NULL);
+
+/**
+ RACH correlator/detector.
+ @param rxBurst The received GSM burst of interest.
+ @param detectThreshold The threshold that the received burst's post-correlator SNR is compared against to determine validity.
+ @param samplesPerSymbol The number of samples per GSM symbol.
+ @param amplitude The estimated amplitude of received RACH burst.
+ @param TOA The estimate time-of-arrival of received RACH burst.
+ @return True if burst SNR is larger that the detectThreshold value.
+*/
+bool detectRACHBurst(signalVector &rxBurst,
+ float detectThreshold,
+ int samplesPerSymbol,
+ complex *amplitude,
+ float* TOA);
+
+/**
+ Normal burst correlator, detector, channel estimator.
+ @param rxBurst The received GSM burst of interest.
+
+ @param detectThreshold The threshold that the received burst's post-correlator SNR is compared against to determine validity.
+ @param samplesPerSymbol The number of samples per GSM symbol.
+ @param amplitude The estimated amplitude of received TSC burst.
+ @param TOA The estimate time-of-arrival of received TSC burst.
+ @param maxTOA The maximum expected time-of-arrival
+ @param requestChannel Set to true if channel estimation is desired.
+ @param channelResponse The estimated channel.
+ @param channelResponseOffset The time offset b/w the first sample of the channel response and the reported TOA.
+ @return True if burst SNR is larger that the detectThreshold value.
+*/
+bool analyzeTrafficBurst(signalVector &rxBurst,
+ unsigned TSC,
+ float detectThreshold,
+ int samplesPerSymbol,
+ complex *amplitude,
+ float *TOA,
+ unsigned maxTOA,
+ bool requestChannel = false,
+ signalVector** channelResponse = NULL,
+ float *channelResponseOffset = NULL);
+
+/**
+ Decimate a vector.
+ @param wVector The vector of interest.
+ @param decimationFactor The amount of decimation, i.e. the decimation factor.
+ @return The decimated signal vector.
+*/
+signalVector *decimateVector(signalVector &wVector,
+ int decimationFactor);
+
+/**
+ Demodulates a received burst using a soft-slicer.
+ @param rxBurst The burst to be demodulated.
+ @param gsmPulse The GSM pulse.
+ @param samplesPerSymbol The number of samples per GSM symbol.
+ @param channel The amplitude estimate of the received burst.
+ @param TOA The time-of-arrival of the received burst.
+ @return The demodulated bit sequence.
+*/
+SoftVector *demodulateBurst(signalVector &rxBurst,
+ const signalVector &gsmPulse,
+ int samplesPerSymbol,
+ complex channel,
+ float TOA);
+
+/**
+ Creates a simple Kaiser-windowed low-pass FIR filter.
+ @param cutoffFreq The digital 3dB bandwidth of the filter.
+ @param filterLen The number of taps in the filter.
+ @param gainDC The DC gain of the filter.
+ @return The desired LPF
+*/
+signalVector *createLPF(float cutoffFreq,
+ int filterLen,
+ float gainDC = 1.0);
+
+/**
+ Change sampling rate of a vector via polyphase resampling.
+ @param wVector The vector to be resampled.
+ @param P The numerator, i.e. the amount of upsampling.
+ @param Q The denominator, i.e. the amount of downsampling.
+ @param LPF An optional low-pass filter used in the resampling process.
+ @return A vector resampled at P/Q of the original sampling rate.
+*/
+signalVector *polyphaseResampleVector(signalVector &wVector,
+ int P, int Q,
+ signalVector *LPF);
+
+/**
+ Change the sampling rate of a vector via linear interpolation.
+ @param wVector The vector to be resampled.
+ @param expFactor Ratio of new sampling rate/original sampling rate.
+ @param endPoint ???
+ @return A vector resampled a expFactor*original sampling rate.
+*/
+signalVector *resampleVector(signalVector &wVector,
+ float expFactor,
+ complex endPoint);
+
+/**
+ Design the necessary filters for a decision-feedback equalizer.
+ @param channelResponse The multipath channel that we're mitigating.
+ @param SNRestimate The signal-to-noise estimate of the channel, a linear value
+ @param Nf The number of taps in the feedforward filter.
+ @param feedForwardFilter The designed feed forward filter.
+ @param feedbackFilter The designed feedback filter.
+ @return True if DFE can be designed.
+*/
+bool designDFE(signalVector &channelResponse,
+ float SNRestimate,
+ int Nf,
+ signalVector **feedForwardFilter,
+ signalVector **feedbackFilter);
+
+/**
+ Equalize/demodulate a received burst via a decision-feedback equalizer.
+ @param rxBurst The received burst to be demodulated.
+ @param TOA The time-of-arrival of the received burst.
+ @param samplesPerSymbol The number of samples per GSM symbol.
+ @param w The feed forward filter of the DFE.
+ @param b The feedback filter of the DFE.
+ @return The demodulated bit sequence.
+*/
+SoftVector *equalizeBurst(signalVector &rxBurst,
+ float TOA,
+ int samplesPerSymbol,
+ signalVector &w,
+ signalVector &b);
diff --git a/Transceiver52M/sigProcLibTest.cpp b/Transceiver52M/sigProcLibTest.cpp
new file mode 100644
index 0000000..1c2a1af
--- /dev/null
+++ b/Transceiver52M/sigProcLibTest.cpp
@@ -0,0 +1,168 @@
+/*
+* Copyright 2011 Free Software Foundation, Inc.
+* Copyright 2008, 2010 Kestrel Signal Processing, Inc.
+*
+* This software is distributed under the terms of the GNU Affero Public License.
+* See the COPYING file in the main directory for details.
+*
+* This use of this software may be subject to additional restrictions.
+* See the LEGAL 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 Affero 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/*
+Contributors:
+Harvind S. Samra, hssamra@kestrelsp.com
+*/
+
+
+#include "sigProcLib.h"
+//#include "radioInterface.h"
+#include <Logger.h>
+#include <Configuration.h>
+
+using namespace std;
+
+ConfigurationTable gConfig;
+
+int main(int argc, char **argv) {
+
+ gLogInit("sigProcLibTest","DEBUG");
+
+ int samplesPerSymbol = 1;
+
+ int TSC = 2;
+
+ sigProcLibSetup(samplesPerSymbol);
+
+ signalVector *gsmPulse = generateGSMPulse(2,samplesPerSymbol);
+ cout << *gsmPulse << endl;
+
+ BitVector RACHBurstStart = "01010101";
+ BitVector RACHBurstRest = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
+
+ BitVector RACHBurst(BitVector(RACHBurstStart,gRACHSynchSequence),RACHBurstRest);
+
+
+ signalVector *RACHSeq = modulateBurst(RACHBurst,
+ *gsmPulse,
+ 9,
+ samplesPerSymbol);
+
+ generateRACHSequence(*gsmPulse,samplesPerSymbol);
+
+ complex a; float t;
+ detectRACHBurst(*RACHSeq, 5, samplesPerSymbol,&a,&t);
+
+ //cout << *RACHSeq << endl;
+ //signalVector *autocorr = correlate(RACHSeq,RACHSeq,NULL,NO_DELAY);
+
+ //cout << *autocorr;
+
+ //exit(1);
+
+
+ /*signalVector x(6500);
+ x.fill(1.0);
+
+ frequencyShift(&x,&x,0.48*M_PI);
+
+ signalVector *y = polyphaseResampleVector(x,96,65,NULL);
+
+ cout << *y << endl;
+
+ exit(1);*/
+
+ //CommSig normalBurstSeg = "0000000000000000000000000000000000000000000000000000000000000";
+
+ BitVector normalBurstSeg = "0000101010100111110010101010010110101110011000111001101010000";
+
+ BitVector normalBurst(BitVector(normalBurstSeg,gTrainingSequence[TSC]),normalBurstSeg);
+
+
+ generateMidamble(*gsmPulse,samplesPerSymbol,TSC);
+
+
+ signalVector *modBurst = modulateBurst(normalBurst,*gsmPulse,
+ 0,samplesPerSymbol);
+
+
+ //delayVector(*rsVector2,6.932);
+
+ complex ampl = 1;
+ float TOA = 0;
+
+ //modBurst = rsVector2;
+ //delayVector(*modBurst,0.8);
+
+ /*
+ signalVector channelResponse(4);
+ signalVector::iterator c=channelResponse.begin();
+ *c = (complex) 9000.0; c++;
+ *c = (complex) 0.4*9000.0; c++; c++;
+ *c = (complex) -1.2*0;
+
+ signalVector *guhBurst = convolve(modBurst,&channelResponse,NULL,NO_DELAY);
+ delete modBurst; modBurst = guhBurst;
+ */
+
+ signalVector *chanResp;
+ /*
+ double noisePwr = 0.001/sqrtf(2);
+ signalVector *noise = gaussianNoise(modBurst->size(),noisePwr);
+ */
+ float chanRespOffset;
+ analyzeTrafficBurst(*modBurst,TSC,8.0,samplesPerSymbol,&ampl,&TOA,1,true,&chanResp,&chanRespOffset);
+ //addVector(*modBurst,*noise);
+
+ cout << "ampl:" << ampl << endl;
+ cout << "TOA: " << TOA << endl;
+ //cout << "chanResp: " << *chanResp << endl;
+ SoftVector *demodBurst = demodulateBurst(*modBurst,*gsmPulse,samplesPerSymbol,(complex) ampl, TOA);
+
+ cout << *demodBurst << endl;
+
+ /*
+ COUT("chanResp: " << *chanResp);
+
+ signalVector *w,*b;
+ designDFE(*chanResp,1.0/noisePwr,7,&w,&b);
+ COUT("w: " << *w);
+ COUT("b: " << *b);
+
+
+ SoftSig *DFEBurst = equalizeBurst(*modBurst,TOA-chanRespOffset,samplesPerSymbol,*w,*b);
+ COUT("DFEBurst: " << *DFEBurst);
+
+ delete gsmPulse;
+ delete RACHSeq;
+ delete modBurst;
+ delete sendLPF;
+ delete rcvLPF;
+ delete rsVector;
+ //delete rsVector2;
+ delete autocorr;
+ delete chanResp;
+ delete noise;
+ delete demodBurst;
+ delete w;
+ delete b;
+ delete DFEBurst;
+ */
+
+ sigProcLibDestroy();
+
+}
diff --git a/Transceiver52M/std_inband.rbf b/Transceiver52M/std_inband.rbf
new file mode 100755
index 0000000..63842b7
--- /dev/null
+++ b/Transceiver52M/std_inband.rbf
Binary files differ