mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-trx.git
				synced 2025-11-03 21:53:18 +00:00 
			
		
		
		
	Compare commits
	
		
			20 Commits
		
	
	
		
			Hoernchen/
			...
			achemeris/
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					eac726bc17 | ||
| 
						 | 
					facdadc254 | ||
| 
						 | 
					eefa8e58f7 | ||
| 
						 | 
					3ac1cbf40e | ||
| 
						 | 
					139c84564c | ||
| 
						 | 
					2cb6070e09 | ||
| 
						 | 
					f2bdd1a24c | ||
| 
						 | 
					34e5a3807f | ||
| 
						 | 
					b49874aa64 | ||
| 
						 | 
					030951695c | ||
| 
						 | 
					b721d6104d | ||
| 
						 | 
					c19d1f6c36 | ||
| 
						 | 
					f0d8a581b4 | ||
| 
						 | 
					37b445d4c8 | ||
| 
						 | 
					df127bc74e | ||
| 
						 | 
					6512812e43 | ||
| 
						 | 
					ded68da44f | ||
| 
						 | 
					37bbfa2125 | ||
| 
						 | 
					fdbf914584 | ||
| 
						 | 
					bbef7e4d70 | 
@@ -193,7 +193,7 @@ Log::~Log()
 | 
			
		||||
	if (mDummyInit) return;
 | 
			
		||||
	// Anything at or above LOG_CRIT is an "alarm".
 | 
			
		||||
	// Save alarms in the local list and echo them to stderr.
 | 
			
		||||
	if (mPriority <= LOG_CRIT) {
 | 
			
		||||
	if (mPriority <= LOG_ERR) {
 | 
			
		||||
		if (sLoggerInited) addAlarm(mStream.str().c_str());
 | 
			
		||||
		cerr << mStream.str() << endl;
 | 
			
		||||
	}
 | 
			
		||||
@@ -206,7 +206,7 @@ Log::~Log()
 | 
			
		||||
	if (gLogToConsole||gLogToFile) {
 | 
			
		||||
		int mlen = mStream.str().size();
 | 
			
		||||
		int neednl = (mlen==0 || mStream.str()[mlen-1] != '\n');
 | 
			
		||||
		gLogToLock.lock();
 | 
			
		||||
		ScopedLock lock(gLogToLock);
 | 
			
		||||
		if (gLogToConsole) {
 | 
			
		||||
			// The COUT() macro prevents messages from stomping each other but adds uninteresting thread numbers,
 | 
			
		||||
			// so just use std::cout.
 | 
			
		||||
@@ -218,7 +218,6 @@ Log::~Log()
 | 
			
		||||
			if (neednl) {fputc('\n',gLogToFile);}
 | 
			
		||||
			fflush(gLogToFile);
 | 
			
		||||
		}
 | 
			
		||||
		gLogToLock.unlock();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										260
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										260
									
								
								README
									
									
									
									
									
								
							@@ -1,168 +1,116 @@
 | 
			
		||||
Welcome to the OpenBTS source code.
 | 
			
		||||
This is the interface to the transcevier.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
For free support, please subscribe to openbts-discuss@lists.sourceforge.net.
 | 
			
		||||
See http://sourceforge.net/mailarchive/forum.php?forum_name=openbts-discuss
 | 
			
		||||
and https://lists.sourceforge.net/lists/listinfo/openbts-discuss for details.
 | 
			
		||||
 | 
			
		||||
For additional information, refer to http://openbts.org.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
These are the directories:
 | 
			
		||||
 | 
			
		||||
AsteriskConfig	Asterisk configuration files for use with OpenBTS.
 | 
			
		||||
CommonLib	Common-use libraries, mostly C++ wrappers for basic facilities.
 | 
			
		||||
Control		Control-layer functions for the protocols of GSM 04.08 and SIP.
 | 
			
		||||
GSM		The GSM stack.
 | 
			
		||||
SIP		Components of the SIP state machines ued by the control layer.
 | 
			
		||||
SMS		The SMS stack.
 | 
			
		||||
SR		The subscriber registry.
 | 
			
		||||
TRXManager	The interface between the GSM stack and the radio.
 | 
			
		||||
Transceiver	The software transceiver and specific installation tests.
 | 
			
		||||
apps		OpenBTS application binaries.
 | 
			
		||||
doc		Project documentation.
 | 
			
		||||
tests		Test fixtures for subsets of OpenBTS components.
 | 
			
		||||
smqueue		RFC-3428 store-and-forward server for SMS
 | 
			
		||||
Each TRX Manager UDP socket interface represents a single ARFCN.
 | 
			
		||||
Each of these per-ARFCN interfaces is a pair of UDP sockets, one for control and one for data.
 | 
			
		||||
Give a base port B (5700), the master clock interface is at port P=B.
 | 
			
		||||
The TRX-side control interface for C(N) is on  port P=B+2N+1 and the data interface is on an odd numbered port P=B+2N+2.
 | 
			
		||||
The corresponding core-side interface for every socket is at P+100.
 | 
			
		||||
For any given build, the number of ARFCN interfaces can be fixed.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
By default, OpenBTS assumes the following UDP port assignments:
 | 
			
		||||
Indications on the Master Clock Interface
 | 
			
		||||
 | 
			
		||||
5060 -- Asterisk SIP interface
 | 
			
		||||
5061 -- local SIP softphone
 | 
			
		||||
5062 -- OpenBTS SIP interface
 | 
			
		||||
5063 -- smqueue SIP interface
 | 
			
		||||
5064 -- subscriber registry SIP interface
 | 
			
		||||
5700-range -- OpenBTS-transceiver interface
 | 
			
		||||
The master clock interface is output only (from the radio).
 | 
			
		||||
Messages are "indications".
 | 
			
		||||
 | 
			
		||||
These can be controlled in the CONFIG table in /etc/OpenBTS.db.
 | 
			
		||||
CLOCK gives the current value of the transceiver clock to be used by the core.
 | 
			
		||||
This message is sent whenever a trasmission packet arrives that is too late or too early.  The clock value is NOT the current transceiver time.  It is a time setting the the core should use to give better packet arrival times.
 | 
			
		||||
IND CLOCK <totalFrames>
 | 
			
		||||
 | 
			
		||||
Standrd paths:
 | 
			
		||||
/OpenBTS -- Binary installation.
 | 
			
		||||
/etc/OpenBTS -- Configuration databases.
 | 
			
		||||
/var/run/OpenBTS -- Real-time reporting databases.
 | 
			
		||||
 | 
			
		||||
The script apps/setUpFiles.sh will create these directories and install the
 | 
			
		||||
correct files in them.
 | 
			
		||||
 | 
			
		||||
Commands on the Per-ARFCN Control Interface
 | 
			
		||||
 | 
			
		||||
The per-ARFCN control interface uses a command-reponse protocol.
 | 
			
		||||
Commands are NULL-terminated ASCII strings, one per UDP socket.
 | 
			
		||||
Each command has a corresponding response.
 | 
			
		||||
Every command is of the form:
 | 
			
		||||
 | 
			
		||||
CMD <cmdtype> [params]
 | 
			
		||||
 | 
			
		||||
The <cmdtype> is the actual command.
 | 
			
		||||
Parameters are optional depending on the commands type.
 | 
			
		||||
Every response is of the form:
 | 
			
		||||
 | 
			
		||||
RSP <cmdtype> <status> [result]
 | 
			
		||||
 | 
			
		||||
The <status> is 0 for success and a non-zero error code for failure.
 | 
			
		||||
Successful responses may include results, depending on the command type.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Power Control
 | 
			
		||||
 | 
			
		||||
POWEROFF shuts off transmitter power and stops the demodulator.
 | 
			
		||||
CMD POWEROFF
 | 
			
		||||
RSP POWEROFF <status>
 | 
			
		||||
 | 
			
		||||
POWERON starts the transmitter and starts the demodulator.  Initial power level is very low.
 | 
			
		||||
This command fails if the transmitter and receiver are not yet tuned.
 | 
			
		||||
This command fails if the transmit or receive frequency creates a conflict with another ARFCN that is already runnng.
 | 
			
		||||
If the transceiver is already on, it response with success to this command.
 | 
			
		||||
CMD POWERON
 | 
			
		||||
RSP POWERON <status>
 | 
			
		||||
 | 
			
		||||
SETPOWER sets output power in dB wrt full scale.
 | 
			
		||||
This command fails if the transmitter and receiver are not running.
 | 
			
		||||
CMD SETPOWER <dB>
 | 
			
		||||
RSP SETPOWER <status> <dB>
 | 
			
		||||
 | 
			
		||||
ADJPOWER adjusts power by the given dB step.  Response returns resulting power level wrt full scale.
 | 
			
		||||
This command fails if the transmitter and receiver are not running.
 | 
			
		||||
CMD ADJPOWER <dBStep>
 | 
			
		||||
RSP ADJPOWER <status> <dBLevel>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Tuning Control
 | 
			
		||||
 | 
			
		||||
RXTUNE tunes the receiver to a given frequency in kHz.
 | 
			
		||||
This command fails if the receiver is already running.
 | 
			
		||||
(To re-tune you stop the radio, re-tune, and restart.)
 | 
			
		||||
This command fails if the transmit or receive frequency creates a conflict with another ARFCN that is already runnng.
 | 
			
		||||
CMD RXTUNE <kHz>
 | 
			
		||||
RSP RXTUNE <status> <kHz>
 | 
			
		||||
 | 
			
		||||
TXTUNE tunes the transmitter to a given frequency in kHz.
 | 
			
		||||
This command fails if the transmitter is already running.
 | 
			
		||||
(To re-tune you stop the radio, re-tune, and restart.)
 | 
			
		||||
This command fails if the transmit or receive frequency creates a conflict with another ARFCN that is already runnng.
 | 
			
		||||
CMD TXTUNE <kHz>
 | 
			
		||||
RSP TXTUNE <status> <kHz>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Timeslot Control
 | 
			
		||||
 | 
			
		||||
SETSLOT sets the format of the uplink timeslots in the ARFCN.
 | 
			
		||||
The <timeslot> indicates the timeslot of interest.
 | 
			
		||||
The <chantype> indicates the type of channel that occupies the timeslot.
 | 
			
		||||
A chantype of zero indicates the timeslot is off.
 | 
			
		||||
CMD SETSLOT <timeslot> <chantype>
 | 
			
		||||
RSP SETSLOT <status> <timeslot> <chantype>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Messages on the per-ARFCN Data Interface
 | 
			
		||||
 | 
			
		||||
Messages on the data interface carry one radio burst per UDP message.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Received Data Burst
 | 
			
		||||
 | 
			
		||||
1 byte timeslot index
 | 
			
		||||
4 bytes GSM frame number, big endian
 | 
			
		||||
1 byte RSSI in -dBm
 | 
			
		||||
2 bytes correlator timing offset in 1/256 symbol steps, 2's-comp, big endian
 | 
			
		||||
148 bytes soft symbol estimates, 0 -> definite "0", 255 -> definite "1"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Transmit Data Burst
 | 
			
		||||
 | 
			
		||||
1 byte timeslot index
 | 
			
		||||
4 bytes GSM frame number, big endian
 | 
			
		||||
1 byte transmit level wrt ARFCN max, -dB (attenuation)
 | 
			
		||||
148 bytes output symbol values, 0 & 1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Release history:
 | 
			
		||||
 | 
			
		||||
Release	Name		SVN Reposiory	SVN Rev	Comments
 | 
			
		||||
 | 
			
		||||
1.0	(none)		SF.net		??		completed L1, L2
 | 
			
		||||
 | 
			
		||||
1.1	Arnaudville	GNU Radio	r10019 (trunk)
 | 
			
		||||
 | 
			
		||||
1.2	Breaux Bridge	GNU Radio	r10088 (trunk)	GNU Build, very early assignment
 | 
			
		||||
 | 
			
		||||
1.3	Carencro	KSP		r1 (trunk)	first post-injunction release
 | 
			
		||||
 | 
			
		||||
1.4	Donaldsonville	KSP		r23 (trunk)	fixed Ubuntu build error
 | 
			
		||||
 | 
			
		||||
1.5	Eunice		KSP		r39 (trunk)	fixed L2 bugs related to segmentation
 | 
			
		||||
							removed incomplete SMS directory
 | 
			
		||||
							moved "abort" calls into L3 subclasses
 | 
			
		||||
 | 
			
		||||
1.6	New Iberia	KSP		r130 (trunk)	import of all 2.2 improvements to non-SMS release
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
2.0	St. Francisville KSP		r54 (smswork)	SMS support
 | 
			
		||||
							file-based configuration
 | 
			
		||||
 | 
			
		||||
2.1	Grand Coteau	KSP		r70 (smswork)	DTMF support
 | 
			
		||||
							fixed more Linux-related build errors
 | 
			
		||||
								-lpthread
 | 
			
		||||
								TLMessage constructor
 | 
			
		||||
							expanded stack to prevent overflows in Linux
 | 
			
		||||
							moved gSIPInterface to main app
 | 
			
		||||
							fixed iterator bug in Pager
 | 
			
		||||
 | 
			
		||||
2.2	Houma		KSP		r122 (smswork)	added LEGAL notice
 | 
			
		||||
							removed Assert classes
 | 
			
		||||
							stop paging on page response
 | 
			
		||||
							fixed Pager-spin bug
 | 
			
		||||
							fixed Transceiver spin bugs
 | 
			
		||||
							fixed 2^32 microsecond rollover bug
 | 
			
		||||
							reduced stack footprints in Transceiver
 | 
			
		||||
							fixed SMS timestamps
 | 
			
		||||
							check LAI before using TMSI in LUR
 | 
			
		||||
							reduced memory requirement by 75%
 | 
			
		||||
							removed PagerTest
 | 
			
		||||
							fixed stale-transaction bug in paging handler
 | 
			
		||||
							fixed USRP clock rollover bug
 | 
			
		||||
							faster call connection
 | 
			
		||||
							new USRPDevice design
 | 
			
		||||
 | 
			
		||||
2.3	Jean Lafitte	KSP		r190? (trunk)	check for out-of-date RACH bursts
 | 
			
		||||
							better TRX-GSM clock sync
 | 
			
		||||
							formal logging system
 | 
			
		||||
							command line interface
 | 
			
		||||
							emergency call setup
 | 
			
		||||
 | 
			
		||||
2.4	Kinder		KSP		r208? (trunk)	fixed BCCH neighbor list bug
 | 
			
		||||
							support for neighbor lists
 | 
			
		||||
							fixed support for non-local Asterisk servers
 | 
			
		||||
							cleaner configuration management
 | 
			
		||||
							more realtime control of BCCH parameters
 | 
			
		||||
							proper rejection of Hold messages
 | 
			
		||||
							fixed L3 hanging bug in MTDCheckBYE
 | 
			
		||||
 | 
			
		||||
2.4.1	Kinder		KSP		r462		fixed lots of valgrind errors
 | 
			
		||||
 | 
			
		||||
2.4.2	Kinder		KSP		r482		zero-length calling party number bug
 | 
			
		||||
							g++ 4.4 #includes
 | 
			
		||||
 | 
			
		||||
2.5	Lacassine	KSP		r551		imported Joshua Lackey patches
 | 
			
		||||
							SIP fixes from Anne Kwong
 | 
			
		||||
							SIP fixes from testing with SMS server
 | 
			
		||||
							L3 TI handling fixes
 | 
			
		||||
							SMS server support
 | 
			
		||||
							GNU Radio 3.2 compatibility
 | 
			
		||||
							configurable max range and LU-reject cause
 | 
			
		||||
							"page" & "testcall" CLI features
 | 
			
		||||
 | 
			
		||||
2.5.1	Lacassine	KSP		r595		fixed some build bugs for some Linux distros
 | 
			
		||||
 | 
			
		||||
2.5.2	Lacassine	KSP		r630		fixed channel assignment bug for Nokia DCT4+ handsets
 | 
			
		||||
 | 
			
		||||
2.5.3	Lacassine	KSP		r756		merged fix for transceiver startup crash
 | 
			
		||||
								due to use of uninitialized variables (r646)
 | 
			
		||||
							merged fix for fusb bug from trunk (r582)
 | 
			
		||||
 | 
			
		||||
2.5.4	Lacassine	KSP		r812		merged fixes to build under latest Fedora and
 | 
			
		||||
								to build with git GnuRadio (r814)
 | 
			
		||||
 | 
			
		||||
2.6	Mamou		KSP		r886		fixed infamous fusb bug (r582)
 | 
			
		||||
							fixed idle-filling table size bug
 | 
			
		||||
							smoother uplink power control
 | 
			
		||||
							load-limiting downlink power control
 | 
			
		||||
							new "config" features (optional, static)
 | 
			
		||||
							IMEI interrogation
 | 
			
		||||
							fixed MOD "missing FIFO" bug
 | 
			
		||||
							configurable short code features
 | 
			
		||||
							fixed transceiver startup crash (r646)
 | 
			
		||||
							readline support is back
 | 
			
		||||
							fixed timing advance bug (r844)
 | 
			
		||||
							added CLI "chans" command
 | 
			
		||||
							track time-of-use in TMSI table (r844)
 | 
			
		||||
							added CLI "noise" command (r844)
 | 
			
		||||
							added CLI "rxpower" command (r844)
 | 
			
		||||
							added CLI "unconfig" command
 | 
			
		||||
 | 
			
		||||
2.7	Natchitoches	Range	rxxx			(never released publicly)
 | 
			
		||||
							converted TMSITable to sqlite3 (r902)
 | 
			
		||||
							sqlite3-based configuration (r???)
 | 
			
		||||
							converted Logger to syslogd (r903)
 | 
			
		||||
							added support for rest octets (r1022)
 | 
			
		||||
							external database for transaction reporting (r1184)
 | 
			
		||||
							external database for channel status reporting (r1203)
 | 
			
		||||
							in-call delivery and submission of text messages (r1231)
 | 
			
		||||
							RFC-2833 DMTF (r1249)
 | 
			
		||||
 | 
			
		||||
2.8	Opelousas	Range	rxxx			move databases to /etc and /var
 | 
			
		||||
							RRLP aiding support
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,8 @@
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <iomanip>      // std::setprecision
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include "Transceiver.h"
 | 
			
		||||
#include <Logger.h>
 | 
			
		||||
 | 
			
		||||
@@ -143,15 +145,21 @@ Transceiver::Transceiver(int wBasePort,
 | 
			
		||||
                         const char *wTRXAddress,
 | 
			
		||||
                         size_t wSPS, size_t wChans,
 | 
			
		||||
                         GSM::Time wTransmitLatency,
 | 
			
		||||
			 RadioInterface *wRadioInterface)
 | 
			
		||||
                         RadioInterface *wRadioInterface,
 | 
			
		||||
                         double wRssiOffset)
 | 
			
		||||
  : mBasePort(wBasePort), mAddr(wTRXAddress),
 | 
			
		||||
    mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
 | 
			
		||||
    mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
 | 
			
		||||
    rssiOffset(wRssiOffset),
 | 
			
		||||
    mSPSTx(wSPS), mSPSRx(1), mChans(wChans), mOn(false),
 | 
			
		||||
    mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelay(0)
 | 
			
		||||
    mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelay(0), mWriteBurstToDiskMask(0)
 | 
			
		||||
{
 | 
			
		||||
  txFullScale = mRadioInterface->fullScaleInputValue();
 | 
			
		||||
  rxFullScale = mRadioInterface->fullScaleOutputValue();
 | 
			
		||||
 | 
			
		||||
  for (int i = 0; i < 8; i++) {
 | 
			
		||||
    for (int j = 0; j < 8; j++)
 | 
			
		||||
      mHandover[i][j] = false;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Transceiver::~Transceiver()
 | 
			
		||||
@@ -168,6 +176,7 @@ Transceiver::~Transceiver()
 | 
			
		||||
    mTxPriorityQueues[i].clear();
 | 
			
		||||
    delete mCtrlSockets[i];
 | 
			
		||||
    delete mDataSockets[i];
 | 
			
		||||
    delete mClockSockets[i];
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -182,7 +191,7 @@ Transceiver::~Transceiver()
 | 
			
		||||
 */
 | 
			
		||||
bool Transceiver::init(int filler, size_t rtsc)
 | 
			
		||||
{
 | 
			
		||||
  int d_srcport, d_dstport, c_srcport, c_dstport;
 | 
			
		||||
  int t_srcport, t_dstport, d_srcport, d_dstport, c_srcport, c_dstport;
 | 
			
		||||
 | 
			
		||||
  if (!mChans) {
 | 
			
		||||
    LOG(ALERT) << "No channels assigned";
 | 
			
		||||
@@ -196,6 +205,7 @@ bool Transceiver::init(int filler, size_t rtsc)
 | 
			
		||||
 | 
			
		||||
  mDataSockets.resize(mChans);
 | 
			
		||||
  mCtrlSockets.resize(mChans);
 | 
			
		||||
  mClockSockets.resize(mChans);
 | 
			
		||||
  mControlServiceLoopThreads.resize(mChans);
 | 
			
		||||
  mTxPriorityQueueServiceLoopThreads.resize(mChans);
 | 
			
		||||
  mRxServiceLoopThreads.resize(mChans);
 | 
			
		||||
@@ -210,13 +220,16 @@ bool Transceiver::init(int filler, size_t rtsc)
 | 
			
		||||
 | 
			
		||||
  /* Setup sockets */
 | 
			
		||||
  for (size_t i = 0; i < mChans; i++) {
 | 
			
		||||
    c_srcport = mBasePort + 2 * i + 1;
 | 
			
		||||
    c_dstport = mBasePort + 2 * i + 101;
 | 
			
		||||
    d_srcport = mBasePort + 2 * i + 2;
 | 
			
		||||
    d_dstport = mBasePort + 2 * i + 102;
 | 
			
		||||
    t_srcport = mBasePort + 3 * i;
 | 
			
		||||
    t_dstport = mBasePort + 3 * i + 100;
 | 
			
		||||
    c_srcport = mBasePort + 3 * i + 1;
 | 
			
		||||
    c_dstport = mBasePort + 3 * i + 101;
 | 
			
		||||
    d_srcport = mBasePort + 3 * i + 2;
 | 
			
		||||
    d_dstport = mBasePort + 3 * i + 102;
 | 
			
		||||
 | 
			
		||||
    mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
 | 
			
		||||
    mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
 | 
			
		||||
    mClockSockets[i] = new UDPSocket(t_srcport, mAddr.c_str(), t_dstport);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Randomize the central clock */
 | 
			
		||||
@@ -459,9 +472,15 @@ void Transceiver::setModulus(size_t timeslot, size_t chan)
 | 
			
		||||
Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
 | 
			
		||||
                                                    size_t chan)
 | 
			
		||||
{
 | 
			
		||||
  static int tchh_subslot[26] = { 0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,1 };
 | 
			
		||||
  static int sdcch4_subslot[102] = { 3,3,3,3,0,0,2,2,2,2,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,2,2,2,2,
 | 
			
		||||
                                     3,3,3,3,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,2,2,2,2 };
 | 
			
		||||
  static int sdcch8_subslot[102] = { 5,5,5,5,6,6,6,6,7,7,7,7,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,0,0,0,0,
 | 
			
		||||
                                     1,1,1,1,2,2,2,2,3,3,3,3,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,4,4,4,4 };
 | 
			
		||||
  TransceiverState *state = &mStates[chan];
 | 
			
		||||
  unsigned burstTN = currTime.TN();
 | 
			
		||||
  unsigned burstFN = currTime.FN();
 | 
			
		||||
  int subch;
 | 
			
		||||
 | 
			
		||||
  switch (state->chanType[burstTN]) {
 | 
			
		||||
  case NONE:
 | 
			
		||||
@@ -471,16 +490,25 @@ Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
 | 
			
		||||
    return IDLE;
 | 
			
		||||
    break;
 | 
			
		||||
  case I:
 | 
			
		||||
    // TODO: Are we expecting RACH on an IDLE frame?
 | 
			
		||||
/*    if (burstFN % 26 == 25)
 | 
			
		||||
      return IDLE;*/
 | 
			
		||||
    if (mHandover[burstTN][0])
 | 
			
		||||
      return RACH;
 | 
			
		||||
    return TSC;
 | 
			
		||||
    /*if (burstFN % 26 == 25) 
 | 
			
		||||
      return IDLE;
 | 
			
		||||
    else
 | 
			
		||||
      return TSC;*/
 | 
			
		||||
    break;
 | 
			
		||||
  case II:
 | 
			
		||||
    subch = tchh_subslot[burstFN % 26];
 | 
			
		||||
    if (subch == 1)
 | 
			
		||||
      return IDLE;
 | 
			
		||||
    if (mHandover[burstTN][0])
 | 
			
		||||
      return RACH;
 | 
			
		||||
    return TSC;
 | 
			
		||||
    break;
 | 
			
		||||
  case III:
 | 
			
		||||
    subch = tchh_subslot[burstFN % 26];
 | 
			
		||||
    if (mHandover[burstTN][subch])
 | 
			
		||||
      return RACH;
 | 
			
		||||
    return TSC;
 | 
			
		||||
    break;
 | 
			
		||||
  case IV:
 | 
			
		||||
@@ -495,6 +523,8 @@ Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
 | 
			
		||||
      return RACH;
 | 
			
		||||
    else if ((mod51 == 45) || (mod51 == 46))
 | 
			
		||||
      return RACH;
 | 
			
		||||
    else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
 | 
			
		||||
      return RACH;
 | 
			
		||||
    else
 | 
			
		||||
      return TSC;
 | 
			
		||||
    break;
 | 
			
		||||
@@ -502,6 +532,8 @@ Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
 | 
			
		||||
  case VII:
 | 
			
		||||
    if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
 | 
			
		||||
      return IDLE;
 | 
			
		||||
    else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
 | 
			
		||||
      return RACH;
 | 
			
		||||
    else
 | 
			
		||||
      return TSC;
 | 
			
		||||
    break;
 | 
			
		||||
@@ -531,13 +563,13 @@ Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
 | 
			
		||||
 * Detect RACH synchronization sequence within a burst. No equalization
 | 
			
		||||
 * is used or available on the RACH channel.
 | 
			
		||||
 */
 | 
			
		||||
bool Transceiver::detectRACH(TransceiverState *state,
 | 
			
		||||
int Transceiver::detectRACH(TransceiverState *state,
 | 
			
		||||
                            signalVector &burst,
 | 
			
		||||
                            complex &, float &toa)
 | 
			
		||||
{
 | 
			
		||||
  float threshold = 6.0;
 | 
			
		||||
 | 
			
		||||
  return detectRACHBurst(burst, threshold, mSPSRx, &, &toa);
 | 
			
		||||
  return detectRACHBurst(burst, threshold, mSPSRx, amp, toa);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -545,12 +577,13 @@ bool Transceiver::detectRACH(TransceiverState *state,
 | 
			
		||||
 * state information and channel estimate if necessary. Equalization
 | 
			
		||||
 * is currently disabled.
 | 
			
		||||
 */
 | 
			
		||||
bool Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
 | 
			
		||||
int Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
 | 
			
		||||
                           complex &, float &toa, GSM::Time &time)
 | 
			
		||||
{
 | 
			
		||||
  int success;
 | 
			
		||||
  int tn = time.TN();
 | 
			
		||||
  float chanOffset, threshold = 5.0;
 | 
			
		||||
  bool noise, needDFE = false, estimateChan = false;
 | 
			
		||||
  bool needDFE = false, estimateChan = false;
 | 
			
		||||
  double elapsed = time - state->chanEstimateTime[tn];
 | 
			
		||||
  signalVector *chanResp;
 | 
			
		||||
 | 
			
		||||
@@ -565,17 +598,18 @@ bool Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Detect normal burst midambles */
 | 
			
		||||
  if (!analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, &,
 | 
			
		||||
                           &toa, mMaxExpectedDelay, estimateChan,
 | 
			
		||||
                           &chanResp, &chanOffset)) {
 | 
			
		||||
    return false;
 | 
			
		||||
  success = analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, amp,
 | 
			
		||||
                                toa, mMaxExpectedDelay, estimateChan,
 | 
			
		||||
                                &chanResp, &chanOffset);
 | 
			
		||||
  if (success <= 0) {
 | 
			
		||||
    return success;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  noise = state->mNoiseLev;
 | 
			
		||||
  state->SNRestimate[tn] = amp.norm2() / (noise * noise + 1.0);
 | 
			
		||||
 | 
			
		||||
  /* Set equalizer if unabled */
 | 
			
		||||
  if (needDFE && estimateChan) {
 | 
			
		||||
     float noise = state->mNoiseLev;
 | 
			
		||||
     state->SNRestimate[tn] = amp.norm2() / (noise * noise + 1.0);
 | 
			
		||||
 | 
			
		||||
     state->chanResponse[tn] = chanResp;
 | 
			
		||||
     state->chanRespOffset[tn] = chanOffset;
 | 
			
		||||
     state->chanRespAmplitude[tn] = amp;
 | 
			
		||||
@@ -588,7 +622,7 @@ bool Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
 | 
			
		||||
     state->chanEstimateTime[tn] = time;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;;
 | 
			
		||||
  return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -611,20 +645,33 @@ SoftVector *Transceiver::demodulate(TransceiverState *state,
 | 
			
		||||
  return demodulateBurst(burst, mSPSRx, amp, toa);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void writeToFile(radioVector *radio_burst, size_t chan)
 | 
			
		||||
{
 | 
			
		||||
  GSM::Time time = radio_burst->getTime();
 | 
			
		||||
  std::ostringstream fname;
 | 
			
		||||
  fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
 | 
			
		||||
  std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
 | 
			
		||||
  outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
 | 
			
		||||
  outfile.close();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Pull bursts from the FIFO and handle according to the slot
 | 
			
		||||
 * and burst correlation type. Equalzation is currently disabled. 
 | 
			
		||||
 */
 | 
			
		||||
SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
 | 
			
		||||
                                         int &timingOffset, size_t chan)
 | 
			
		||||
SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
 | 
			
		||||
                                         double &timingOffset, double &noise,
 | 
			
		||||
                                         size_t chan)
 | 
			
		||||
{
 | 
			
		||||
  bool success, equalize = false;
 | 
			
		||||
  int success;
 | 
			
		||||
  bool equalize = false;
 | 
			
		||||
  complex amp;
 | 
			
		||||
  float toa, pow, max = -1.0, avg = 0.0;
 | 
			
		||||
  int max_i = -1;
 | 
			
		||||
  signalVector *burst;
 | 
			
		||||
  SoftVector *bits = NULL;
 | 
			
		||||
  TransceiverState *state = &mStates[chan];
 | 
			
		||||
  isRssiValid = false;
 | 
			
		||||
 | 
			
		||||
  /* Blocking FIFO read */
 | 
			
		||||
  radioVector *radio_burst = mReceiveFIFO[chan]->read();
 | 
			
		||||
@@ -635,7 +682,15 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
 | 
			
		||||
  GSM::Time time = radio_burst->getTime();
 | 
			
		||||
  CorrType type = expectedCorrType(time, chan);
 | 
			
		||||
 | 
			
		||||
  if ((type == OFF) || (type == IDLE)) {
 | 
			
		||||
  /* Debug: dump bursts to disk */
 | 
			
		||||
  /* bits 0-7  - chan 0 timeslots
 | 
			
		||||
   * bits 8-15 - chan 1 timeslots */
 | 
			
		||||
  if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
 | 
			
		||||
    writeToFile(radio_burst, chan);
 | 
			
		||||
 | 
			
		||||
  /* No processing if the timeslot is off.
 | 
			
		||||
   * Not even power level or noise calculation. */
 | 
			
		||||
  if (type == OFF) {
 | 
			
		||||
    delete radio_burst;
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
@@ -659,7 +714,25 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
 | 
			
		||||
  /* Average noise on diversity paths and update global levels */
 | 
			
		||||
  burst = radio_burst->getVector(max_i);
 | 
			
		||||
  avg = sqrt(avg / radio_burst->chans());
 | 
			
		||||
 | 
			
		||||
  wTime = time;
 | 
			
		||||
  RSSI = 20.0 * log10(rxFullScale / avg);
 | 
			
		||||
 | 
			
		||||
  /* RSSI estimation are valid */
 | 
			
		||||
  isRssiValid = true;
 | 
			
		||||
 | 
			
		||||
  if (type == IDLE) {
 | 
			
		||||
    /* Update noise levels */
 | 
			
		||||
    state->mNoises.insert(avg);
 | 
			
		||||
    state->mNoiseLev = state->mNoises.avg();
 | 
			
		||||
    noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
 | 
			
		||||
 | 
			
		||||
    delete radio_burst;
 | 
			
		||||
    return NULL;
 | 
			
		||||
  } else {
 | 
			
		||||
    /* Do not update noise levels */
 | 
			
		||||
    noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Detect normal or RACH bursts */
 | 
			
		||||
  if (type == TSC)
 | 
			
		||||
@@ -667,33 +740,27 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
 | 
			
		||||
  else
 | 
			
		||||
    success = detectRACH(state, *burst, amp, toa);
 | 
			
		||||
 | 
			
		||||
  /* Update noise average if no bust detected or alert on error */
 | 
			
		||||
  /* Alert an error and exit */
 | 
			
		||||
  if (success <= 0) {
 | 
			
		||||
    if (!success) {
 | 
			
		||||
      state->mNoises.insert(avg);
 | 
			
		||||
    } else if (success == -SIGERR_CLIP) {
 | 
			
		||||
      LOG(ALERT) << "Clipping detected on RACH input";
 | 
			
		||||
    } else if (success < 0) {
 | 
			
		||||
      LOG(ALERT) << "Unhandled RACH error";
 | 
			
		||||
    if (success == -SIGERR_CLIP) {
 | 
			
		||||
      LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
 | 
			
		||||
    } else if (success != SIGERR_NONE) {
 | 
			
		||||
      LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    delete radio_burst;
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  timingOffset = toa / mSPSRx;
 | 
			
		||||
 | 
			
		||||
  /* Demodulate and set output info */
 | 
			
		||||
  if (equalize && (type != TSC))
 | 
			
		||||
    equalize = false;
 | 
			
		||||
 | 
			
		||||
  if (avg - state->mNoiseLev > 0.0)
 | 
			
		||||
  bits = demodulate(state, *burst, amp, toa, time.TN(), equalize);
 | 
			
		||||
 | 
			
		||||
  wTime = time;
 | 
			
		||||
  RSSI = (int) floor(20.0 * log10(rxFullScale / avg));
 | 
			
		||||
  timingOffset = (int) round(toa * 256.0 / mSPSRx);
 | 
			
		||||
 | 
			
		||||
  delete radio_burst;
 | 
			
		||||
 | 
			
		||||
  return bits;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -743,6 +810,24 @@ void Transceiver::driveControl(size_t chan)
 | 
			
		||||
      sprintf(response,"RSP POWERON 1");
 | 
			
		||||
    else
 | 
			
		||||
      sprintf(response,"RSP POWERON 0");
 | 
			
		||||
      for (int i = 0; i < 8; i++) {
 | 
			
		||||
        for (int j = 0; j < 8; j++)
 | 
			
		||||
          mHandover[i][j] = false;
 | 
			
		||||
      }
 | 
			
		||||
  }
 | 
			
		||||
  else if (strcmp(command,"HANDOVER")==0){
 | 
			
		||||
    int ts=0,ss=0;
 | 
			
		||||
    sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
 | 
			
		||||
    mHandover[ts][ss] = true;
 | 
			
		||||
    LOG(WARNING) << "HANDOVER RACH at timeslot " << ts << " subslot " << ss;
 | 
			
		||||
    sprintf(response,"RSP HANDOVER 0 %d %d",ts,ss);
 | 
			
		||||
  }
 | 
			
		||||
  else if (strcmp(command,"NOHANDOVER")==0){
 | 
			
		||||
    int ts=0,ss=0;
 | 
			
		||||
    sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
 | 
			
		||||
    mHandover[ts][ss] = false;
 | 
			
		||||
    LOG(WARNING) << "NOHANDOVER at timeslot " << ts << " subslot " << ss;
 | 
			
		||||
    sprintf(response,"RSP NOHANDOVER 0 %d %d",ts,ss);
 | 
			
		||||
  }
 | 
			
		||||
  else if (strcmp(command,"SETMAXDLY")==0) {
 | 
			
		||||
    //set expected maximum time-of-arrival
 | 
			
		||||
@@ -836,6 +921,14 @@ void Transceiver::driveControl(size_t chan)
 | 
			
		||||
    sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
  else if (strcmp(command,"_SETBURSTTODISKMASK")==0) {
 | 
			
		||||
    // debug command! may change or disapear without notice
 | 
			
		||||
    // set a mask which bursts to dump to disk
 | 
			
		||||
    int mask;
 | 
			
		||||
    sscanf(buffer,"%3s %s %d",cmdcheck,command,&mask);
 | 
			
		||||
    mWriteBurstToDiskMask = mask;
 | 
			
		||||
    sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    LOG(WARNING) << "bogus command " << command << " on control interface.";
 | 
			
		||||
    sprintf(response,"RSP ERR 1");
 | 
			
		||||
@@ -892,27 +985,34 @@ void Transceiver::driveReceiveRadio()
 | 
			
		||||
void Transceiver::driveReceiveFIFO(size_t chan)
 | 
			
		||||
{
 | 
			
		||||
  SoftVector *rxBurst = NULL;
 | 
			
		||||
  int RSSI;
 | 
			
		||||
  int TOA;  // in 1/256 of a symbol
 | 
			
		||||
  double RSSI; // in dBFS
 | 
			
		||||
  double dBm;  // in dBm
 | 
			
		||||
  double TOA;  // in symbols
 | 
			
		||||
  int TOAint;  // in 1/256 symbols
 | 
			
		||||
  double noise; // noise level in dBFS
 | 
			
		||||
  GSM::Time burstTime;
 | 
			
		||||
  bool isRssiValid; // are RSSI, noise and burstTime valid
 | 
			
		||||
 | 
			
		||||
  rxBurst = pullRadioVector(burstTime, RSSI, TOA, chan);
 | 
			
		||||
  rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
 | 
			
		||||
 | 
			
		||||
  if (rxBurst) { 
 | 
			
		||||
    dBm = RSSI+rssiOffset;
 | 
			
		||||
    TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
 | 
			
		||||
 | 
			
		||||
    LOG(DEBUG) << "burst parameters: "
 | 
			
		||||
	LOG(DEBUG) << std::fixed << std::right
 | 
			
		||||
      << " time: "   << burstTime
 | 
			
		||||
	  << " RSSI: " << RSSI
 | 
			
		||||
	  << " TOA: "  << TOA
 | 
			
		||||
	  << " RSSI: "   << std::setw(5) << std::setprecision(1) << RSSI << "dBFS/" << std::setw(6) << -dBm << "dBm"
 | 
			
		||||
	  << " noise: "  << std::setw(5) << std::setprecision(1) << noise << "dBFS/" << std::setw(6) << -(noise+rssiOffset) << "dBm"
 | 
			
		||||
	  << " TOA: "    << std::setw(5) << std::setprecision(2) << 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;
 | 
			
		||||
    burstString[5] = (int)dBm;
 | 
			
		||||
    burstString[6] = (TOAint >> 8) & 0x0ff;
 | 
			
		||||
    burstString[7] = TOAint & 0x0ff;
 | 
			
		||||
    SoftVector::iterator burstItr = rxBurst->begin();
 | 
			
		||||
 | 
			
		||||
    for (unsigned int i = 0; i < gSlotLen; i++) {
 | 
			
		||||
@@ -987,7 +1087,8 @@ void Transceiver::writeClockInterface()
 | 
			
		||||
 | 
			
		||||
  LOG(INFO) << "ClockInterface: sending " << command;
 | 
			
		||||
 | 
			
		||||
  mClockSocket.write(command, strlen(command) + 1);
 | 
			
		||||
  for (size_t i=0; i<mClockSockets.size(); i++)
 | 
			
		||||
    mClockSockets[i]->write(command, strlen(command) + 1);
 | 
			
		||||
 | 
			
		||||
  mLastClockUpdateTime = mTransmitDeadlineClock;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -100,7 +100,8 @@ public:
 | 
			
		||||
              const char *TRXAddress,
 | 
			
		||||
              size_t wSPS, size_t chans,
 | 
			
		||||
              GSM::Time wTransmitLatency,
 | 
			
		||||
	      RadioInterface *wRadioInterface);
 | 
			
		||||
              RadioInterface *wRadioInterface,
 | 
			
		||||
              double wRssiOffset);
 | 
			
		||||
 | 
			
		||||
  /** Destructor */
 | 
			
		||||
  ~Transceiver();
 | 
			
		||||
@@ -161,7 +162,7 @@ private:
 | 
			
		||||
 | 
			
		||||
  std::vector<UDPSocket *> mDataSockets;  ///< socket for writing to/reading from GSM core
 | 
			
		||||
  std::vector<UDPSocket *> mCtrlSockets;  ///< socket for writing/reading control commands from GSM core
 | 
			
		||||
  UDPSocket mClockSocket;                 ///< socket for writing clock updates to GSM core
 | 
			
		||||
  std::vector<UDPSocket *> mClockSockets; ///< socket for writing clock updates to GSM core
 | 
			
		||||
 | 
			
		||||
  std::vector<VectorQueue> mTxPriorityQueues;   ///< priority queue of transmit bursts received from GSM core
 | 
			
		||||
  std::vector<VectorFIFO *>  mReceiveFIFO;      ///< radioInterface FIFO of receive bursts
 | 
			
		||||
@@ -181,6 +182,8 @@ private:
 | 
			
		||||
  double txFullScale;                     ///< full scale input to radio
 | 
			
		||||
  double rxFullScale;                     ///< full scale output to radio
 | 
			
		||||
 | 
			
		||||
  double rssiOffset;                      ///< RSSI to dBm conversion offset
 | 
			
		||||
 | 
			
		||||
  /** modulate and add a burst to the transmit queue */
 | 
			
		||||
  void addRadioVector(size_t chan, BitVector &bits,
 | 
			
		||||
                      int RSSI, GSM::Time &wTime);
 | 
			
		||||
@@ -192,8 +195,9 @@ private:
 | 
			
		||||
  void pushRadioVector(GSM::Time &nowTime);
 | 
			
		||||
 | 
			
		||||
  /** Pull and demodulate a burst from the receive FIFO */
 | 
			
		||||
  SoftVector *pullRadioVector(GSM::Time &wTime, int &RSSI,
 | 
			
		||||
                              int &timingOffset, size_t chan = 0);
 | 
			
		||||
  SoftVector *pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
 | 
			
		||||
                              double &timingOffset, double &noise,
 | 
			
		||||
                              size_t chan = 0);
 | 
			
		||||
 | 
			
		||||
  /** Set modulus for specific timeslot */
 | 
			
		||||
  void setModulus(size_t timeslot, size_t chan);
 | 
			
		||||
@@ -205,12 +209,12 @@ private:
 | 
			
		||||
  void writeClockInterface(void);
 | 
			
		||||
 | 
			
		||||
  /** Detect RACH bursts */
 | 
			
		||||
  bool detectRACH(TransceiverState *state,
 | 
			
		||||
  int detectRACH(TransceiverState *state,
 | 
			
		||||
                 signalVector &burst,
 | 
			
		||||
                 complex &, float &toa);
 | 
			
		||||
 | 
			
		||||
  /** Detect normal bursts */
 | 
			
		||||
  bool detectTSC(TransceiverState *state,
 | 
			
		||||
  int detectTSC(TransceiverState *state,
 | 
			
		||||
                signalVector &burst,
 | 
			
		||||
                complex &, float &toa, GSM::Time &time);
 | 
			
		||||
 | 
			
		||||
@@ -224,10 +228,12 @@ private:
 | 
			
		||||
  size_t mChans;
 | 
			
		||||
 | 
			
		||||
  bool mOn;	                           ///< flag to indicate that transceiver is powered on
 | 
			
		||||
  bool mHandover[8][8];                ///< expect handover to the timeslot/subslot
 | 
			
		||||
  double mTxFreq;                      ///< the transmit frequency
 | 
			
		||||
  double mRxFreq;                      ///< the receive frequency
 | 
			
		||||
  unsigned mTSC;                       ///< the midamble sequence code
 | 
			
		||||
  unsigned mMaxExpectedDelay;          ///< maximum expected time-of-arrival offset in GSM symbols
 | 
			
		||||
  unsigned mWriteBurstToDiskMask;      ///< debug: bitmask to indicate which timeslots to dump to disk
 | 
			
		||||
 | 
			
		||||
  std::vector<TransceiverState> mStates;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -210,8 +210,7 @@ uhd::time_spec_t convert_time(TIMESTAMP ticks, double rate)
 | 
			
		||||
 | 
			
		||||
TIMESTAMP convert_time(uhd::time_spec_t ts, double rate)
 | 
			
		||||
{
 | 
			
		||||
	TIMESTAMP ticks = ts.get_full_secs() * rate;
 | 
			
		||||
	return ts.get_tick_count(rate) + ticks;
 | 
			
		||||
	return (TIMESTAMP)(ts.get_real_secs() * rate + 0.5);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -290,7 +289,7 @@ public:
 | 
			
		||||
	uhd_device(size_t sps, size_t chans, bool diversity, double offset);
 | 
			
		||||
	~uhd_device();
 | 
			
		||||
 | 
			
		||||
	int open(const std::string &args, bool extref);
 | 
			
		||||
	int open(const std::string &args, bool extref, bool swap_channels);
 | 
			
		||||
	bool start();
 | 
			
		||||
	bool stop();
 | 
			
		||||
	bool restart();
 | 
			
		||||
@@ -473,18 +472,24 @@ void uhd_device::init_gains()
 | 
			
		||||
		tx_gain_min = range.start();
 | 
			
		||||
		tx_gain_max = range.stop();
 | 
			
		||||
	}
 | 
			
		||||
	LOG(INFO) << "Supported Tx gain range [" << tx_gain_min << "; " << tx_gain_max << "]";
 | 
			
		||||
 | 
			
		||||
	range = usrp_dev->get_rx_gain_range();
 | 
			
		||||
	rx_gain_min = range.start();
 | 
			
		||||
	rx_gain_max = range.stop();
 | 
			
		||||
	LOG(INFO) << "Supported Rx gain range [" << rx_gain_min << "; " << rx_gain_max << "]";
 | 
			
		||||
 | 
			
		||||
	for (size_t i = 0; i < tx_gains.size(); i++) {
 | 
			
		||||
		usrp_dev->set_tx_gain((tx_gain_min + tx_gain_max) / 2, i);
 | 
			
		||||
		double gain = (tx_gain_min + tx_gain_max) / 2;
 | 
			
		||||
		LOG(INFO) << "Default setting Tx gain for channel " << i << " to " << gain;
 | 
			
		||||
		usrp_dev->set_tx_gain(gain, i);
 | 
			
		||||
		tx_gains[i] = usrp_dev->get_tx_gain(i);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (size_t i = 0; i < rx_gains.size(); i++) {
 | 
			
		||||
		usrp_dev->set_rx_gain((rx_gain_min + rx_gain_max) / 2, i);
 | 
			
		||||
		double gain = (rx_gain_min + rx_gain_max) / 2;
 | 
			
		||||
		LOG(INFO) << "Default setting Rx gain for channel " << i << " to " << gain;
 | 
			
		||||
		usrp_dev->set_rx_gain(gain, i);
 | 
			
		||||
		rx_gains[i] = usrp_dev->get_rx_gain(i);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -582,7 +587,7 @@ double uhd_device::setTxGain(double db, size_t chan)
 | 
			
		||||
 | 
			
		||||
	tx_gains[chan] = usrp_dev->get_tx_gain(chan);
 | 
			
		||||
 | 
			
		||||
	LOG(INFO) << "Set TX gain to " << tx_gains[chan] << "dB";
 | 
			
		||||
	LOG(INFO) << "Set TX gain to " << tx_gains[chan] << "dB (asked for " << db << "dB)";
 | 
			
		||||
 | 
			
		||||
	return tx_gains[chan];
 | 
			
		||||
}
 | 
			
		||||
@@ -597,7 +602,7 @@ double uhd_device::setRxGain(double db, size_t chan)
 | 
			
		||||
	usrp_dev->set_rx_gain(db, chan);
 | 
			
		||||
	rx_gains[chan] = usrp_dev->get_rx_gain(chan);
 | 
			
		||||
 | 
			
		||||
	LOG(INFO) << "Set RX gain to " << rx_gains[chan] << "dB";
 | 
			
		||||
	LOG(INFO) << "Set RX gain to " << rx_gains[chan] << "dB (asked for " << db << "dB)";
 | 
			
		||||
 | 
			
		||||
	return rx_gains[chan];
 | 
			
		||||
}
 | 
			
		||||
@@ -694,7 +699,7 @@ bool uhd_device::parse_dev_type()
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int uhd_device::open(const std::string &args, bool extref)
 | 
			
		||||
int uhd_device::open(const std::string &args, bool extref, bool swap_channels)
 | 
			
		||||
{
 | 
			
		||||
	// Find UHD devices
 | 
			
		||||
	uhd::device_addr_t addr(args);
 | 
			
		||||
@@ -720,7 +725,7 @@ int uhd_device::open(const std::string &args, bool extref)
 | 
			
		||||
	// Verify and set channels
 | 
			
		||||
	if ((dev_type == B210) && (chans == 2)) {
 | 
			
		||||
	} else if ((dev_type == UMTRX) && (chans == 2)) {
 | 
			
		||||
		uhd::usrp::subdev_spec_t subdev_spec("A:0 B:0");
 | 
			
		||||
		uhd::usrp::subdev_spec_t subdev_spec(swap_channels?"B:0 A:0":"A:0 B:0");
 | 
			
		||||
		usrp_dev->set_tx_subdev_spec(subdev_spec);
 | 
			
		||||
		usrp_dev->set_rx_subdev_spec(subdev_spec);
 | 
			
		||||
	} else if (chans != 1) {
 | 
			
		||||
@@ -1115,7 +1120,7 @@ uhd::tune_request_t uhd_device::select_freq(double freq, size_t chan, bool tx)
 | 
			
		||||
	uhd::tune_request_t treq(freq);
 | 
			
		||||
 | 
			
		||||
	if (dev_type == UMTRX) {
 | 
			
		||||
		if (offset > 0.0)
 | 
			
		||||
		if (offset != 0.0)
 | 
			
		||||
			return uhd::tune_request_t(freq, offset);
 | 
			
		||||
 | 
			
		||||
		// Don't use DSP tuning, because LMS6002D PLL steps are small enough.
 | 
			
		||||
@@ -1126,6 +1131,7 @@ uhd::tune_request_t uhd_device::select_freq(double freq, size_t chan, bool tx)
 | 
			
		||||
		treq.rf_freq = freq;
 | 
			
		||||
		treq.dsp_freq_policy = uhd::tune_request_t::POLICY_MANUAL;
 | 
			
		||||
		treq.dsp_freq = 0.0;
 | 
			
		||||
		return treq;
 | 
			
		||||
	} else if (chans == 1) {
 | 
			
		||||
		if (offset == 0.0)
 | 
			
		||||
			return treq;
 | 
			
		||||
@@ -1430,6 +1436,19 @@ ssize_t smpl_buf::write(void *buf, size_t len, TIMESTAMP timestamp)
 | 
			
		||||
	if ((timestamp + len) <= time_end)
 | 
			
		||||
		return ERROR_TIMESTAMP;
 | 
			
		||||
 | 
			
		||||
	if (timestamp < time_end) {
 | 
			
		||||
		LOG(ERR) << "Overwriting old buffer data: timestamp="<<timestamp<<" time_end="<<time_end;
 | 
			
		||||
		uhd::time_spec_t ts = convert_time(timestamp, clk_rt);
 | 
			
		||||
		LOG(DEBUG) << "Requested timestamp = " << timestamp << " (real_sec=" << std::fixed << ts.get_real_secs() << " = " << convert_time(ts, clk_rt) << ") rate=" << clk_rt;
 | 
			
		||||
		// Do not return error here, because it's a rounding error and is not fatal
 | 
			
		||||
	}
 | 
			
		||||
	if (timestamp > time_end && time_end != 0) {
 | 
			
		||||
		LOG(ERR) << "Skipping buffer data: timestamp="<<timestamp<<" time_end="<<time_end;
 | 
			
		||||
		uhd::time_spec_t ts = convert_time(timestamp, clk_rt);
 | 
			
		||||
		LOG(DEBUG) << "Requested timestamp = " << timestamp << " (real_sec=" << std::fixed << ts.get_real_secs() << " = " << convert_time(ts, clk_rt) << ") rate=" << clk_rt;
 | 
			
		||||
		// Do not return error here, because it's a rounding error and is not fatal
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Starting index
 | 
			
		||||
	size_t write_start = (data_start + (timestamp - time_start)) % buf_len;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -89,7 +89,7 @@ USRPDevice::USRPDevice(size_t sps, size_t, bool)
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int USRPDevice::open(const std::string &, bool)
 | 
			
		||||
int USRPDevice::open(const std::string &, bool, bool)
 | 
			
		||||
{
 | 
			
		||||
  writeLock.unlock();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -99,7 +99,7 @@ private:
 | 
			
		||||
  USRPDevice(size_t sps, size_t chans = 1, bool diversity = false);
 | 
			
		||||
 | 
			
		||||
  /** Instantiate the USRP */
 | 
			
		||||
  int open(const std::string &, bool);
 | 
			
		||||
  int open(const std::string &, bool, bool);
 | 
			
		||||
 | 
			
		||||
  /** Start the USRP */
 | 
			
		||||
  bool start();
 | 
			
		||||
 
 | 
			
		||||
@@ -70,6 +70,8 @@ struct trx_config {
 | 
			
		||||
	Transceiver::FillerType filler;
 | 
			
		||||
	bool diversity;
 | 
			
		||||
	double offset;
 | 
			
		||||
	double rssi_offset;
 | 
			
		||||
	bool swap_channels;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ConfigurationTable gConfig;
 | 
			
		||||
@@ -185,6 +187,8 @@ bool trx_setup_config(struct trx_config *config)
 | 
			
		||||
	ost << "   C0 Filler Table......... " << fillstr << std::endl;
 | 
			
		||||
	ost << "   Diversity............... " << divstr << std::endl;
 | 
			
		||||
	ost << "   Tuning offset........... " << config->offset << std::endl;
 | 
			
		||||
	ost << "   RSSI to dBm offset...... " << config->rssi_offset << std::endl;
 | 
			
		||||
	ost << "   Swap channels........... " << config->swap_channels << std::endl;
 | 
			
		||||
	std::cout << ost << std::endl;
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
@@ -240,7 +244,7 @@ Transceiver *makeTransceiver(struct trx_config *config, RadioInterface *radio)
 | 
			
		||||
	VectorFIFO *fifo;
 | 
			
		||||
 | 
			
		||||
	trx = new Transceiver(config->port, config->addr.c_str(), config->sps,
 | 
			
		||||
			      config->chans, GSM::Time(3,0), radio);
 | 
			
		||||
		config->chans, GSM::Time(3,0), radio, config->rssi_offset);
 | 
			
		||||
	if (!trx->init(config->filler, config->rtsc)) {
 | 
			
		||||
		LOG(ALERT) << "Failed to initialize transceiver";
 | 
			
		||||
		delete trx;
 | 
			
		||||
@@ -292,7 +296,9 @@ static void print_help()
 | 
			
		||||
		"  -c    Number of ARFCN channels (default=1)\n"
 | 
			
		||||
		"  -f    Enable C0 filler table\n"
 | 
			
		||||
		"  -o    Set baseband frequency offset (default=auto)\n"
 | 
			
		||||
		"  -r    Random burst test mode with TSC\n",
 | 
			
		||||
		"  -r    Random burst test mode with TSC\n"
 | 
			
		||||
		"  -R    RSSI to dBm offset in dB (default=0)\n"
 | 
			
		||||
		"  -S    Swap channels (UmTRX only)\n",
 | 
			
		||||
		"EMERG, ALERT, CRT, ERR, WARNING, NOTICE, INFO, DEBUG");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -308,8 +314,10 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
 | 
			
		||||
	config->filler = Transceiver::FILLER_ZERO;
 | 
			
		||||
	config->diversity = false;
 | 
			
		||||
	config->offset = 0.0;
 | 
			
		||||
	config->rssi_offset = 0.0;
 | 
			
		||||
	config->swap_channels = false;
 | 
			
		||||
 | 
			
		||||
	while ((option = getopt(argc, argv, "ha:l:i:p:c:dxfo:s:r:")) != -1) {
 | 
			
		||||
	while ((option = getopt(argc, argv, "ha:l:i:p:c:dxfo:s:r:R:S")) != -1) {
 | 
			
		||||
		switch (option) {
 | 
			
		||||
		case 'h':
 | 
			
		||||
			print_help();
 | 
			
		||||
@@ -349,6 +357,12 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
 | 
			
		||||
			config->rtsc = atoi(optarg);
 | 
			
		||||
			config->filler = Transceiver::FILLER_RAND;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'R':
 | 
			
		||||
			config->rssi_offset = atof(optarg);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'S':
 | 
			
		||||
			config->swap_channels = true;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			print_help();
 | 
			
		||||
			exit(0);
 | 
			
		||||
@@ -393,7 +407,7 @@ int main(int argc, char *argv[])
 | 
			
		||||
	/* Create the low level device object */
 | 
			
		||||
	usrp = RadioDevice::make(config.sps, config.chans,
 | 
			
		||||
				 config.diversity, config.offset);
 | 
			
		||||
	type = usrp->open(config.dev_args, config.extref);
 | 
			
		||||
	type = usrp->open(config.dev_args, config.extref, config.swap_channels);
 | 
			
		||||
	if (type < 0) {
 | 
			
		||||
		LOG(ALERT) << "Failed to create radio device" << std::endl;
 | 
			
		||||
		goto shutdown;
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ class RadioDevice {
 | 
			
		||||
                           bool diversity = false, double offset = 0.0);
 | 
			
		||||
 | 
			
		||||
  /** Initialize the USRP */
 | 
			
		||||
  virtual int open(const std::string &args = "", bool extref = false)=0;
 | 
			
		||||
  virtual int open(const std::string &args = "", bool extref = false, bool swap_channels = false)=0;
 | 
			
		||||
 | 
			
		||||
  virtual ~RadioDevice() { }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,7 @@
 | 
			
		||||
 | 
			
		||||
#include "sigProcLib.h"
 | 
			
		||||
#include "GSMCommon.h"
 | 
			
		||||
#include "Logger.h"
 | 
			
		||||
 | 
			
		||||
extern "C" {
 | 
			
		||||
#include "convolve.h"
 | 
			
		||||
@@ -1284,12 +1285,12 @@ static float computePeakRatio(signalVector *corr,
 | 
			
		||||
  complex *peak;
 | 
			
		||||
  float rms, avg = 0.0;
 | 
			
		||||
 | 
			
		||||
  peak = corr->begin() + (int) rint(toa);
 | 
			
		||||
 | 
			
		||||
  /* Check for bogus results */
 | 
			
		||||
  if ((toa < 0.0) || (toa > corr->size()))
 | 
			
		||||
    return 0.0;
 | 
			
		||||
 | 
			
		||||
  peak = corr->begin() + (int) rint(toa);
 | 
			
		||||
 | 
			
		||||
  for (int i = 2 * sps; i <= 5 * sps; i++) {
 | 
			
		||||
    if (peak - i >= corr->begin()) {
 | 
			
		||||
      avg += (peak - i)->norm2();
 | 
			
		||||
@@ -1372,18 +1373,74 @@ static int detectBurst(signalVector &burst,
 | 
			
		||||
  return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int detectClipping(signalVector &burst, float thresh)
 | 
			
		||||
static float maxAmplitude(signalVector &burst)
 | 
			
		||||
{
 | 
			
		||||
    float max = 0.0;
 | 
			
		||||
    for (size_t i = 0; i < burst.size(); i++) {
 | 
			
		||||
		if (fabs(burst[i].real()) > thresh)
 | 
			
		||||
			return 1;
 | 
			
		||||
		if (fabs(burst[i].imag()) > thresh)
 | 
			
		||||
			return 1;
 | 
			
		||||
        if (fabs(burst[i].real()) > max)
 | 
			
		||||
            max = fabs(burst[i].real());
 | 
			
		||||
        if (fabs(burst[i].imag()) > max)
 | 
			
		||||
            max = fabs(burst[i].imag());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
    return max;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * RACH/Normal burst detection with clipping detection
 | 
			
		||||
 *
 | 
			
		||||
 * Correlation window parameters:
 | 
			
		||||
 *   target: Tail bits + burst length
 | 
			
		||||
 *   head: Search symbols before target
 | 
			
		||||
 *   tail: Search symbols after target
 | 
			
		||||
 */
 | 
			
		||||
int detectGeneralBurst(signalVector &rxBurst,
 | 
			
		||||
                       float thresh,
 | 
			
		||||
                       int sps,
 | 
			
		||||
                       complex &,
 | 
			
		||||
                       float &toa,
 | 
			
		||||
                       int target, int head, int tail,
 | 
			
		||||
                       CorrelationSequence *sync)
 | 
			
		||||
{
 | 
			
		||||
  int rc, start, len;
 | 
			
		||||
  bool clipping = false;
 | 
			
		||||
  signalVector *corr;
 | 
			
		||||
 | 
			
		||||
  if ((sps != 1) && (sps != 4))
 | 
			
		||||
    return -SIGERR_UNSUPPORTED;
 | 
			
		||||
 | 
			
		||||
  // Detect potential clipping
 | 
			
		||||
  // We still may be able to demod the burst, so we'll give it a try
 | 
			
		||||
  // and only report clipping if we can't demod.
 | 
			
		||||
  float maxAmpl = maxAmplitude(rxBurst);
 | 
			
		||||
  if (maxAmpl > CLIP_THRESH) {
 | 
			
		||||
    LOG(DEBUG) << "max burst amplitude: " << maxAmpl << " is above the clipping threshold: " << CLIP_THRESH << std::endl;
 | 
			
		||||
    clipping = true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  start = (target - head) * sps - 1;
 | 
			
		||||
  len = (head + tail) * sps;
 | 
			
		||||
  corr = new signalVector(len);
 | 
			
		||||
 | 
			
		||||
  rc = detectBurst(rxBurst, *corr, sync,
 | 
			
		||||
                   thresh, sps, &, &toa, start, len);
 | 
			
		||||
  delete corr;
 | 
			
		||||
 | 
			
		||||
  if (rc < 0) {
 | 
			
		||||
    return -SIGERR_INTERNAL;
 | 
			
		||||
  } else if (!rc) {
 | 
			
		||||
    amp = 0.0f;
 | 
			
		||||
    toa = 0.0f;
 | 
			
		||||
    return clipping?-SIGERR_CLIP:SIGERR_NONE;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Subtract forward search bits from delay */
 | 
			
		||||
  toa -= head * sps;
 | 
			
		||||
 | 
			
		||||
  return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 * RACH burst detection
 | 
			
		||||
 *
 | 
			
		||||
@@ -1395,51 +1452,21 @@ static int detectClipping(signalVector &burst, float thresh)
 | 
			
		||||
int detectRACHBurst(signalVector &rxBurst,
 | 
			
		||||
            float thresh,
 | 
			
		||||
            int sps,
 | 
			
		||||
		    complex *amp,
 | 
			
		||||
		    float *toa)
 | 
			
		||||
            complex &,
 | 
			
		||||
            float &toa)
 | 
			
		||||
{
 | 
			
		||||
  int rc, start, target, head, tail, len;
 | 
			
		||||
  float _toa;
 | 
			
		||||
  complex _amp;
 | 
			
		||||
  signalVector *corr;
 | 
			
		||||
  int rc, target, head, tail;
 | 
			
		||||
  CorrelationSequence *sync;
 | 
			
		||||
 | 
			
		||||
  if ((sps != 1) && (sps != 4))
 | 
			
		||||
    return -SIGERR_UNSUPPORTED;
 | 
			
		||||
 | 
			
		||||
  if (detectClipping(rxBurst, CLIP_THRESH))
 | 
			
		||||
    return -SIGERR_CLIP;
 | 
			
		||||
 | 
			
		||||
  target = 8 + 40;
 | 
			
		||||
  head = 4;
 | 
			
		||||
  tail = 10;
 | 
			
		||||
 | 
			
		||||
  start = (target - head) * sps - 1;
 | 
			
		||||
  len = (head + tail) * sps;
 | 
			
		||||
  sync = gRACHSequence;
 | 
			
		||||
  corr = new signalVector(len);
 | 
			
		||||
 | 
			
		||||
  rc = detectBurst(rxBurst, *corr, sync,
 | 
			
		||||
                   thresh, sps, &_amp, &_toa, start, len);
 | 
			
		||||
  delete corr;
 | 
			
		||||
  rc = detectGeneralBurst(rxBurst, thresh, sps, amp, toa,
 | 
			
		||||
                          target, head, tail, sync);
 | 
			
		||||
 | 
			
		||||
  if (rc < 0) {
 | 
			
		||||
    return -SIGERR_INTERNAL;
 | 
			
		||||
  } else if (!rc) {
 | 
			
		||||
    if (amp)
 | 
			
		||||
      *amp = 0.0f;
 | 
			
		||||
    if (toa)
 | 
			
		||||
      *toa = 0.0f;
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Subtract forward search bits from delay */
 | 
			
		||||
  if (toa)
 | 
			
		||||
    *toa = _toa - head * sps;
 | 
			
		||||
  if (amp)
 | 
			
		||||
    *amp = _amp;
 | 
			
		||||
 | 
			
		||||
  return 1;
 | 
			
		||||
  return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
@@ -1451,60 +1478,32 @@ int detectRACHBurst(signalVector &rxBurst,
 | 
			
		||||
 *   tail: Search 4 symbols + maximum expected delay
 | 
			
		||||
 */
 | 
			
		||||
int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
 | 
			
		||||
                        int sps, complex *amp, float *toa, unsigned max_toa,
 | 
			
		||||
                        int sps, complex &, float &toa, unsigned max_toa,
 | 
			
		||||
                        bool chan_req, signalVector **chan, float *chan_offset)
 | 
			
		||||
{
 | 
			
		||||
  int rc, start, target, head, tail, len;
 | 
			
		||||
  complex _amp;
 | 
			
		||||
  float _toa;
 | 
			
		||||
  signalVector *corr;
 | 
			
		||||
  int rc, target, head, tail;
 | 
			
		||||
  CorrelationSequence *sync;
 | 
			
		||||
 | 
			
		||||
  if ((tsc < 0) || (tsc > 7) || ((sps != 1) && (sps != 4)))
 | 
			
		||||
  if ((tsc < 0) || (tsc > 7))
 | 
			
		||||
    return -SIGERR_UNSUPPORTED;
 | 
			
		||||
 | 
			
		||||
  if (detectClipping(rxBurst, CLIP_THRESH))
 | 
			
		||||
    return -SIGERR_CLIP;
 | 
			
		||||
 | 
			
		||||
  target = 3 + 58 + 16 + 5;
 | 
			
		||||
  head = 4;
 | 
			
		||||
  tail = 4 + max_toa;
 | 
			
		||||
 | 
			
		||||
  start = (target - head) * sps - 1;
 | 
			
		||||
  len = (head + tail) * sps;
 | 
			
		||||
  sync = gMidambles[tsc];
 | 
			
		||||
  corr = new signalVector(len);
 | 
			
		||||
 | 
			
		||||
  rc = detectBurst(rxBurst, *corr, sync,
 | 
			
		||||
                   thresh, sps, &_amp, &_toa, start, len);
 | 
			
		||||
  delete corr;
 | 
			
		||||
 | 
			
		||||
  if (rc < 0) {
 | 
			
		||||
    return -SIGERR_INTERNAL;
 | 
			
		||||
  } else if (!rc) {
 | 
			
		||||
    if (amp)
 | 
			
		||||
      *amp = 0.0f;
 | 
			
		||||
    if (toa)
 | 
			
		||||
      *toa = 0.0f;
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Subtract forward search bits from delay */
 | 
			
		||||
  _toa -= head * sps;
 | 
			
		||||
  if (toa)
 | 
			
		||||
    *toa = _toa;
 | 
			
		||||
  if (amp)
 | 
			
		||||
    *amp = _amp;
 | 
			
		||||
  rc = detectGeneralBurst(rxBurst, thresh, sps, amp, toa,
 | 
			
		||||
                          target, head, tail, sync);
 | 
			
		||||
 | 
			
		||||
  /* Equalization not currently supported */
 | 
			
		||||
  if (chan_req) {
 | 
			
		||||
  if (rc > 0 && chan_req) {
 | 
			
		||||
    *chan = new signalVector(6 * sps);
 | 
			
		||||
 | 
			
		||||
    if (chan_offset)
 | 
			
		||||
      *chan_offset = 0.0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return 1;
 | 
			
		||||
  return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
signalVector *decimateVector(signalVector &wVector, size_t factor)
 | 
			
		||||
 
 | 
			
		||||
@@ -192,8 +192,8 @@ bool energyDetect(signalVector &rxBurst,
 | 
			
		||||
int detectRACHBurst(signalVector &rxBurst,
 | 
			
		||||
                    float detectThreshold,
 | 
			
		||||
                    int sps,
 | 
			
		||||
                    complex *amplitude,
 | 
			
		||||
                    float* TOA);
 | 
			
		||||
                    complex &litude,
 | 
			
		||||
                    float &TOA);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
        Normal burst correlator, detector, channel estimator.
 | 
			
		||||
@@ -213,8 +213,8 @@ int analyzeTrafficBurst(signalVector &rxBurst,
 | 
			
		||||
                        unsigned TSC,
 | 
			
		||||
                        float detectThreshold,
 | 
			
		||||
                        int sps,
 | 
			
		||||
			complex *amplitude,
 | 
			
		||||
			float *TOA,
 | 
			
		||||
                        complex &litude,
 | 
			
		||||
                        float &TOA,
 | 
			
		||||
                        unsigned maxTOA,
 | 
			
		||||
                        bool requestChannel = false,
 | 
			
		||||
                        signalVector** channelResponse = NULL,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								utils/clockdump.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										3
									
								
								utils/clockdump.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
sudo tcpdump -i lo0 -A udp port 5700
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user