mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-trx.git
				synced 2025-11-04 06:03:17 +00:00 
			
		
		
		
	Compare commits
	
		
			11 Commits
		
	
	
		
			fairwaves/
			...
			ms
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					774a06369a | ||
| 
						 | 
					94ce835050 | ||
| 
						 | 
					09befd7a06 | ||
| 
						 | 
					1303376ad1 | ||
| 
						 | 
					25021dfe5a | ||
| 
						 | 
					e287598e6b | ||
| 
						 | 
					98b1af896c | ||
| 
						 | 
					14bb9c923d | ||
| 
						 | 
					c7f36c282a | ||
| 
						 | 
					f31e4bb089 | ||
| 
						 | 
					1189019c30 | 
@@ -192,7 +192,7 @@ Log::~Log()
 | 
				
			|||||||
	if (mDummyInit) return;
 | 
						if (mDummyInit) return;
 | 
				
			||||||
	// Anything at or above LOG_CRIT is an "alarm".
 | 
						// Anything at or above LOG_CRIT is an "alarm".
 | 
				
			||||||
	// Save alarms in the local list and echo them to stderr.
 | 
						// Save alarms in the local list and echo them to stderr.
 | 
				
			||||||
	if (mPriority <= LOG_ERR) {
 | 
						if (mPriority <= LOG_CRIT) {
 | 
				
			||||||
		if (sLoggerInited) addAlarm(mStream.str().c_str());
 | 
							if (sLoggerInited) addAlarm(mStream.str().c_str());
 | 
				
			||||||
		cerr << mStream.str() << endl;
 | 
							cerr << mStream.str() << endl;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,6 +45,8 @@ const BitVector GSM::gDummyBurst("0001111101101110110000010100100111000001001000
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const BitVector GSM::gRACHSynchSequence("01001011011111111001100110101010001111000");
 | 
					const BitVector GSM::gRACHSynchSequence("01001011011111111001100110101010001111000");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const BitVector GSM::gSCHSynchSequence("1011100101100010000001000000111100101101010001010111011000011011");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int32_t GSM::FNDelta(int32_t v1, int32_t v2)
 | 
					int32_t GSM::FNDelta(int32_t v1, int32_t v2)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,6 +53,8 @@ extern const BitVector gDummyBurst;
 | 
				
			|||||||
/** Random access burst synch. sequence */
 | 
					/** Random access burst synch. sequence */
 | 
				
			||||||
extern const BitVector gRACHSynchSequence;
 | 
					extern const BitVector gRACHSynchSequence;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Synchronization burst sync sequence */
 | 
				
			||||||
 | 
					extern const BitVector gSCHSynchSequence;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**@name Modulus operations for frame numbers. */
 | 
					/**@name Modulus operations for frame numbers. */
 | 
				
			||||||
//@{
 | 
					//@{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,7 +56,8 @@ COMMON_SOURCES = \
 | 
				
			|||||||
	radioClock.cpp \
 | 
						radioClock.cpp \
 | 
				
			||||||
	sigProcLib.cpp \
 | 
						sigProcLib.cpp \
 | 
				
			||||||
	signalVector.cpp \
 | 
						signalVector.cpp \
 | 
				
			||||||
	Transceiver.cpp
 | 
						Transceiver.cpp \
 | 
				
			||||||
 | 
						sch.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
libtransceiver_la_SOURCES = \
 | 
					libtransceiver_la_SOURCES = \
 | 
				
			||||||
	$(COMMON_SOURCES) \
 | 
						$(COMMON_SOURCES) \
 | 
				
			||||||
@@ -87,7 +88,9 @@ osmo_trx_LDADD = \
 | 
				
			|||||||
	libtransceiver.la \
 | 
						libtransceiver.la \
 | 
				
			||||||
	$(ARCH_LA) \
 | 
						$(ARCH_LA) \
 | 
				
			||||||
	$(GSM_LA) \
 | 
						$(GSM_LA) \
 | 
				
			||||||
	$(COMMON_LA) $(SQLITE_LA)
 | 
						$(COMMON_LA) \
 | 
				
			||||||
 | 
						$(SQLITE_LA) \
 | 
				
			||||||
 | 
						$(LIBOSMOCORE_LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if USRP1 
 | 
					if USRP1 
 | 
				
			||||||
libtransceiver_la_SOURCES += USRPDevice.cpp
 | 
					libtransceiver_la_SOURCES += USRPDevice.cpp
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,6 +25,10 @@
 | 
				
			|||||||
#include "Transceiver.h"
 | 
					#include "Transceiver.h"
 | 
				
			||||||
#include <Logger.h>
 | 
					#include <Logger.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#include "sch.h"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					#ifdef HAVE_CONFIG_H
 | 
				
			||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@@ -39,11 +43,16 @@ using namespace GSM;
 | 
				
			|||||||
#  define USB_LATENCY_MIN		1,1
 | 
					#  define USB_LATENCY_MIN		1,1
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Clock indication interval in frames */
 | 
				
			||||||
 | 
					#define CLK_IND_INTERVAL		100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Number of running values use in noise average */
 | 
					/* Number of running values use in noise average */
 | 
				
			||||||
#define NOISE_CNT			20
 | 
					#define NOISE_CNT			20
 | 
				
			||||||
 | 
					#define FREQ_CNT			20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TransceiverState::TransceiverState()
 | 
					TransceiverState::TransceiverState()
 | 
				
			||||||
  : mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT)
 | 
					  : mRetrans(false), mNoiseLev(0.0),
 | 
				
			||||||
 | 
					    mNoises(NOISE_CNT), mFreqOffsets(FREQ_CNT), mode(Transceiver::TRX_MODE_OFF)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  for (int i = 0; i < 8; i++) {
 | 
					  for (int i = 0; i < 8; i++) {
 | 
				
			||||||
    chanType[i] = Transceiver::NONE;
 | 
					    chanType[i] = Transceiver::NONE;
 | 
				
			||||||
@@ -51,6 +60,7 @@ TransceiverState::TransceiverState()
 | 
				
			|||||||
    chanResponse[i] = NULL;
 | 
					    chanResponse[i] = NULL;
 | 
				
			||||||
    DFEForward[i] = NULL;
 | 
					    DFEForward[i] = NULL;
 | 
				
			||||||
    DFEFeedback[i] = NULL;
 | 
					    DFEFeedback[i] = NULL;
 | 
				
			||||||
 | 
					    prevFrame[i] = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (int n = 0; n < 102; n++)
 | 
					    for (int n = 0; n < 102; n++)
 | 
				
			||||||
      fillerTable[n][i] = NULL;
 | 
					      fillerTable[n][i] = NULL;
 | 
				
			||||||
@@ -92,12 +102,11 @@ Transceiver::Transceiver(int wBasePort,
 | 
				
			|||||||
    mTransmitLatency(wTransmitLatency), mClockSocket(NULL),
 | 
					    mTransmitLatency(wTransmitLatency), mClockSocket(NULL),
 | 
				
			||||||
    mRadioInterface(wRadioInterface), mSPSTx(wSPS), mSPSRx(1), mChans(wChans),
 | 
					    mRadioInterface(wRadioInterface), mSPSTx(wSPS), mSPSRx(1), mChans(wChans),
 | 
				
			||||||
    mOn(false), mTxFreq(0.0), mRxFreq(0.0), mPower(-10), mMaxExpectedDelay(0),
 | 
					    mOn(false), mTxFreq(0.0), mRxFreq(0.0), mPower(-10), mMaxExpectedDelay(0),
 | 
				
			||||||
    mTSC(0)
 | 
					    mBSIC(-1)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  GSM::Time startTime(random() % gHyperframe,0);
 | 
					  GSM::Time startTime(random() % gHyperframe,0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  mRxLowerLoopThread = new Thread(32768);
 | 
					  mLowerLoopThread = new Thread(32768);
 | 
				
			||||||
  mTxLowerLoopThread = new Thread(32768);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  mTransmitDeadlineClock = startTime;
 | 
					  mTransmitDeadlineClock = startTime;
 | 
				
			||||||
  mLastClockUpdateTime = startTime;
 | 
					  mLastClockUpdateTime = startTime;
 | 
				
			||||||
@@ -107,11 +116,8 @@ Transceiver::Transceiver(int wBasePort,
 | 
				
			|||||||
  txFullScale = mRadioInterface->fullScaleInputValue();
 | 
					  txFullScale = mRadioInterface->fullScaleInputValue();
 | 
				
			||||||
  rxFullScale = mRadioInterface->fullScaleOutputValue();
 | 
					  rxFullScale = mRadioInterface->fullScaleOutputValue();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (int i = 0; i < 8; i++) {
 | 
					  for (int i = 0; i < 8; i++)
 | 
				
			||||||
    for (int j = 0; j < 8; j++)
 | 
					    mRxSlotMask[i] = 0;
 | 
				
			||||||
      mHandover[i][j] = false;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Transceiver::~Transceiver()
 | 
					Transceiver::~Transceiver()
 | 
				
			||||||
@@ -201,6 +207,9 @@ void Transceiver::addRadioVector(size_t chan, BitVector &bits,
 | 
				
			|||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (mStates[0].mode != TRX_MODE_BTS)
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
 | 
					  burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
 | 
				
			||||||
  scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
 | 
					  scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -228,7 +237,7 @@ void Transceiver::pushRadioVector(GSM::Time &nowTime)
 | 
				
			|||||||
  radioVector *burst;
 | 
					  radioVector *burst;
 | 
				
			||||||
  TransceiverState *state;
 | 
					  TransceiverState *state;
 | 
				
			||||||
  std::vector<signalVector *> bursts(mChans);
 | 
					  std::vector<signalVector *> bursts(mChans);
 | 
				
			||||||
  std::vector<bool> zeros(mChans);
 | 
					  std::vector<bool> zeros(mChans, false);
 | 
				
			||||||
  std::vector<bool> filler(mChans, true);
 | 
					  std::vector<bool> filler(mChans, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (size_t i = 0; i < mChans; i ++) {
 | 
					  for (size_t i = 0; i < mChans; i ++) {
 | 
				
			||||||
@@ -245,7 +254,8 @@ void Transceiver::pushRadioVector(GSM::Time &nowTime)
 | 
				
			|||||||
    modFN = nowTime.FN() % state->fillerModulus[TN];
 | 
					    modFN = nowTime.FN() % state->fillerModulus[TN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bursts[i] = state->fillerTable[modFN][TN];
 | 
					    bursts[i] = state->fillerTable[modFN][TN];
 | 
				
			||||||
    zeros[i] = state->chanType[TN] == NONE;
 | 
					    if (state->mode == TRX_MODE_BTS)
 | 
				
			||||||
 | 
					      zeros[i] = state->chanType[TN] == NONE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
 | 
					    if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
 | 
				
			||||||
      bursts[i] = burst->getVector();
 | 
					      bursts[i] = burst->getVector();
 | 
				
			||||||
@@ -303,15 +313,22 @@ Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
 | 
				
			|||||||
                                                    size_t chan)
 | 
					                                                    size_t chan)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  TransceiverState *state = &mStates[chan];
 | 
					  TransceiverState *state = &mStates[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 };
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
  unsigned burstTN = currTime.TN();
 | 
					  unsigned burstTN = currTime.TN();
 | 
				
			||||||
  unsigned burstFN = currTime.FN();
 | 
					  unsigned burstFN = currTime.FN();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (state->mode == TRX_MODE_MS_TRACK) {
 | 
				
			||||||
 | 
					    /* 102 modulus case currently unhandled */
 | 
				
			||||||
 | 
					    if (state->fillerModulus[burstTN] > 52)
 | 
				
			||||||
 | 
					      return OFF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int modFN = burstFN % state->fillerModulus[burstTN];
 | 
				
			||||||
 | 
					    unsigned long long reg = (unsigned long long) 1 << modFN;
 | 
				
			||||||
 | 
					    if (reg & mRxSlotMask[burstTN])
 | 
				
			||||||
 | 
					      return TSC;
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      return OFF;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  switch (state->chanType[burstTN]) {
 | 
					  switch (state->chanType[burstTN]) {
 | 
				
			||||||
  case NONE:
 | 
					  case NONE:
 | 
				
			||||||
    return OFF;
 | 
					    return OFF;
 | 
				
			||||||
@@ -320,8 +337,6 @@ Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
 | 
				
			|||||||
    return IDLE;
 | 
					    return IDLE;
 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
  case I:
 | 
					  case I:
 | 
				
			||||||
    if (mHandover[burstTN][0])
 | 
					 | 
				
			||||||
      return RACH;
 | 
					 | 
				
			||||||
    return TSC;
 | 
					    return TSC;
 | 
				
			||||||
    /*if (burstFN % 26 == 25) 
 | 
					    /*if (burstFN % 26 == 25) 
 | 
				
			||||||
      return IDLE;
 | 
					      return IDLE;
 | 
				
			||||||
@@ -332,8 +347,6 @@ Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
 | 
				
			|||||||
    return TSC;
 | 
					    return TSC;
 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
  case III:
 | 
					  case III:
 | 
				
			||||||
    if (mHandover[burstTN][tchh_subslot[burstFN % 26]])
 | 
					 | 
				
			||||||
      return RACH;
 | 
					 | 
				
			||||||
    return TSC;
 | 
					    return TSC;
 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
  case IV:
 | 
					  case IV:
 | 
				
			||||||
@@ -348,8 +361,6 @@ Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
 | 
				
			|||||||
      return RACH;
 | 
					      return RACH;
 | 
				
			||||||
    else if ((mod51 == 45) || (mod51 == 46))
 | 
					    else if ((mod51 == 45) || (mod51 == 46))
 | 
				
			||||||
      return RACH;
 | 
					      return RACH;
 | 
				
			||||||
    else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
 | 
					 | 
				
			||||||
      return RACH;
 | 
					 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
      return TSC;
 | 
					      return TSC;
 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
@@ -357,8 +368,6 @@ Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
 | 
				
			|||||||
  case VII:
 | 
					  case VII:
 | 
				
			||||||
    if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
 | 
					    if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
 | 
				
			||||||
      return IDLE;
 | 
					      return IDLE;
 | 
				
			||||||
    else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
 | 
					 | 
				
			||||||
      return RACH;
 | 
					 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
      return TSC;
 | 
					      return TSC;
 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
@@ -397,6 +406,108 @@ bool Transceiver::detectRACH(TransceiverState *state,
 | 
				
			|||||||
  return detectRACHBurst(burst, threshold, mSPSRx, &, &toa);
 | 
					  return detectRACHBurst(burst, threshold, mSPSRx, &, &toa);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Detect SCH synchronization sequence within a burst */
 | 
				
			||||||
 | 
					bool Transceiver::detectSCH(TransceiverState *state,
 | 
				
			||||||
 | 
					                            signalVector &burst,
 | 
				
			||||||
 | 
					                            complex &, float &toa)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  int shift, full;;
 | 
				
			||||||
 | 
					  float mag, threshold = 7.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  full = (state->mode == TRX_MODE_MS_TRACK) ?
 | 
				
			||||||
 | 
						 SCH_DETECT_NARROW : SCH_DETECT_FULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!detectSCHBurst(burst, threshold, mSPSRx, &, &toa, full))
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::cout << "SCH : Timing offset     " << toa << " symbols" << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mag = fabsf(toa);
 | 
				
			||||||
 | 
					  if (mag < 1.0f)
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  shift = (int) (mag / 2.0f);
 | 
				
			||||||
 | 
					  if (!shift)
 | 
				
			||||||
 | 
					    shift++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mRadioInterface->applyOffset(toa > 0 ? shift : -shift);
 | 
				
			||||||
 | 
					  return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SCH_BIT_SCALE	64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Decode SCH burst */
 | 
				
			||||||
 | 
					bool Transceiver::decodeSCH(SoftVector *burst, GSM::Time *time)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  int fn;
 | 
				
			||||||
 | 
					  struct sch_info sch;
 | 
				
			||||||
 | 
					  ubit_t info[GSM_SCH_INFO_LEN];
 | 
				
			||||||
 | 
					  sbit_t data[GSM_SCH_CODED_LEN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (burst->size() < 156) {
 | 
				
			||||||
 | 
					    std::cout << "Invalid SCH burst length" << std::endl;
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  float_to_sbit(&(*burst)[3], &data[0], SCH_BIT_SCALE, 39);
 | 
				
			||||||
 | 
					  float_to_sbit(&(*burst)[106], &data[39], SCH_BIT_SCALE, 39);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!gsm_sch_decode(info, data)) {
 | 
				
			||||||
 | 
					    gsm_sch_parse(info, &sch);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mBSIC = sch.bsic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::cout << "SCH : Decoded values" << std::endl;
 | 
				
			||||||
 | 
					    std::cout << "    BSIC: " << sch.bsic << std::endl;
 | 
				
			||||||
 | 
					    std::cout << "    T1  : " << sch.t1 << std::endl;
 | 
				
			||||||
 | 
					    std::cout << "    T2  : " << sch.t2 << std::endl;
 | 
				
			||||||
 | 
					    std::cout << "    T3p : " << sch.t3p << std::endl;
 | 
				
			||||||
 | 
					    std::cout << "    FN  : " << gsm_sch_to_fn(&sch) << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn = gsm_sch_to_fn(&sch);
 | 
				
			||||||
 | 
					    if (fn < 0) {
 | 
				
			||||||
 | 
					      std::cout << "SCH : Failed to convert FN " << std::endl;
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    time->FN(fn);
 | 
				
			||||||
 | 
					    time->TN(0);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define FCCH_OFFSET_LIMIT	2e3
 | 
				
			||||||
 | 
					#define FCCH_ADJUST_LIMIT	20.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Apply FCCH frequency correction */
 | 
				
			||||||
 | 
					bool Transceiver::correctFCCH(TransceiverState *state, signalVector *burst)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  double offset, avg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!burst)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  offset = gsm_fcch_offset((float *) burst->begin(), burst->size());
 | 
				
			||||||
 | 
					  if (offset > FCCH_OFFSET_LIMIT)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  state->mFreqOffsets.insert(offset);
 | 
				
			||||||
 | 
					  avg = state->mFreqOffsets.avg();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (state->mFreqOffsets.full())
 | 
				
			||||||
 | 
					    std::cout << "FCCH: Frequency offset  " << avg << " Hz" << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (state->mFreqOffsets.full() && (fabs(avg) > FCCH_ADJUST_LIMIT)) {
 | 
				
			||||||
 | 
					    mRadioInterface->tuneRxOffset(-avg);
 | 
				
			||||||
 | 
					    state->mFreqOffsets.reset();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Detect normal burst training sequence midamble. Update equalization
 | 
					 * Detect normal burst training sequence midamble. Update equalization
 | 
				
			||||||
 * state information and channel estimate if necessary. Equalization
 | 
					 * state information and channel estimate if necessary. Equalization
 | 
				
			||||||
@@ -483,18 +594,33 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
 | 
				
			|||||||
  SoftVector *bits = NULL;
 | 
					  SoftVector *bits = NULL;
 | 
				
			||||||
  TransceiverState *state = &mStates[chan];
 | 
					  TransceiverState *state = &mStates[chan];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  GSM::Time sch_time, burst_time, diff_time;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Blocking FIFO read */
 | 
					  /* Blocking FIFO read */
 | 
				
			||||||
  radioVector *radio_burst = mReceiveFIFO[chan]->read();
 | 
					  radioVector *radio_burst = mReceiveFIFO[chan]->read();
 | 
				
			||||||
  if (!radio_burst)
 | 
					  if (!radio_burst)
 | 
				
			||||||
    return NULL;
 | 
					    return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Set time and determine correlation type */
 | 
					  /* Set time and determine correlation type */
 | 
				
			||||||
  GSM::Time time = radio_burst->getTime();
 | 
					  burst_time = radio_burst->getTime();
 | 
				
			||||||
  CorrType type = expectedCorrType(time, chan);
 | 
					  CorrType type = expectedCorrType(burst_time, chan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if ((type == OFF) || (type == IDLE)) {
 | 
					  switch (state->mode) {
 | 
				
			||||||
    delete radio_burst;
 | 
					  case TRX_MODE_MS_ACQUIRE:
 | 
				
			||||||
    return NULL;
 | 
					    type = SCH;
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  case TRX_MODE_MS_TRACK:
 | 
				
			||||||
 | 
					    if (gsm_sch_check_fn(burst_time.FN()))
 | 
				
			||||||
 | 
					      type = SCH;
 | 
				
			||||||
 | 
					    else if (type == OFF)
 | 
				
			||||||
 | 
					      goto release; 
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  case TRX_MODE_BTS:
 | 
				
			||||||
 | 
					    if ((type == TSC) || (type == RACH))
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					  case TRX_MODE_OFF:
 | 
				
			||||||
 | 
					  default:
 | 
				
			||||||
 | 
					    goto release;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Select the diversity channel with highest energy */
 | 
					  /* Select the diversity channel with highest energy */
 | 
				
			||||||
@@ -509,8 +635,7 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  if (max_i < 0) {
 | 
					  if (max_i < 0) {
 | 
				
			||||||
    LOG(ALERT) << "Received empty burst";
 | 
					    LOG(ALERT) << "Received empty burst";
 | 
				
			||||||
    delete radio_burst;
 | 
					    goto release;
 | 
				
			||||||
    return NULL;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Average noise on diversity paths and update global levels */
 | 
					  /* Average noise on diversity paths and update global levels */
 | 
				
			||||||
@@ -520,38 +645,66 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /* Detect normal or RACH bursts */
 | 
					  /* Detect normal or RACH bursts */
 | 
				
			||||||
  if (type == TSC)
 | 
					  if (type == TSC)
 | 
				
			||||||
    success = detectTSC(state, *burst, amp, toa, time);
 | 
					    success = detectTSC(state, *burst, amp, toa, burst_time);
 | 
				
			||||||
  else
 | 
					  else if (type == RACH)
 | 
				
			||||||
    success = detectRACH(state, *burst, amp, toa);
 | 
					    success = detectRACH(state, *burst, amp, toa);
 | 
				
			||||||
 | 
					  else if (type == SCH)
 | 
				
			||||||
 | 
					    success = detectSCH(state, *burst, amp, toa);
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    success = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (success == 0) {
 | 
					  if (!success) {
 | 
				
			||||||
    state->mNoises.insert(avg);
 | 
					    state->mNoises.insert(avg);
 | 
				
			||||||
    delete radio_burst;
 | 
					    goto release;
 | 
				
			||||||
    return NULL;
 | 
					 | 
				
			||||||
  } else if (success < 0) {
 | 
					 | 
				
			||||||
    if (success == -SIGERR_CLIP) {
 | 
					 | 
				
			||||||
      LOG(ALERT) << "Clipping detected on RACH input";
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      LOG(ALERT) << "Unhandled RACH error";
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    delete radio_burst;
 | 
					 | 
				
			||||||
    return NULL;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Demodulate and set output info */
 | 
					  /* Demodulate and set output info */
 | 
				
			||||||
  if (equalize && (type != TSC))
 | 
					  if (equalize && (type != TSC))
 | 
				
			||||||
    equalize = false;
 | 
					    equalize = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (avg - state->mNoiseLev > 0.0)
 | 
					  /* Ignore noise threshold on MS mode for now */
 | 
				
			||||||
    bits = demodulate(state, *burst, amp, toa, time.TN(), equalize);
 | 
					  if ((type == SCH) || (avg - state->mNoiseLev > 0.0))
 | 
				
			||||||
 | 
					    bits = demodulate(state, *burst, amp, toa,
 | 
				
			||||||
 | 
							      burst_time.TN(), equalize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  wTime = time;
 | 
					  /* MS: Decode SCH and adjust GSM clock */
 | 
				
			||||||
 | 
					  if ((state->mode == TRX_MODE_MS_ACQUIRE) ||
 | 
				
			||||||
 | 
					      (state->mode == TRX_MODE_MS_TRACK)) {
 | 
				
			||||||
 | 
					    correctFCCH(state, state->prevFrame[burst_time.TN()]->getVector());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (decodeSCH(bits, &sch_time)) {
 | 
				
			||||||
 | 
					      if (state->mode == TRX_MODE_MS_ACQUIRE) {
 | 
				
			||||||
 | 
					          diff_time = GSM::Time(sch_time.FN() - burst_time.FN(),
 | 
				
			||||||
 | 
					                                -burst_time.TN());
 | 
				
			||||||
 | 
					          mRadioInterface->adjustClock(diff_time);
 | 
				
			||||||
 | 
					          mTransmitDeadlineClock = RadioClock::adjust(
 | 
				
			||||||
 | 
										mTransmitDeadlineClock,
 | 
				
			||||||
 | 
										diff_time);
 | 
				
			||||||
 | 
					          state->mode = TRX_MODE_MS_TRACK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          std::cout << "SCH : Locking GSM clock " << std::endl;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        std::cout << "SCH : Read SCH at FN " << burst_time.FN()
 | 
				
			||||||
 | 
					                  << " FN51 " << burst_time.FN() % 51 << std::endl;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    goto release;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  wTime = burst_time;
 | 
				
			||||||
  RSSI = (int) floor(20.0 * log10(rxFullScale / avg));
 | 
					  RSSI = (int) floor(20.0 * log10(rxFullScale / avg));
 | 
				
			||||||
  timingOffset = (int) round(toa * 256.0 / mSPSRx);
 | 
					  timingOffset = (int) round(toa * 256.0 / mSPSRx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  delete radio_burst;
 | 
					  delete state->prevFrame[burst_time.TN()];
 | 
				
			||||||
 | 
					  state->prevFrame[burst_time.TN()] = radio_burst;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return bits;
 | 
					  return bits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					release:
 | 
				
			||||||
 | 
					  delete state->prevFrame[burst_time.TN()];
 | 
				
			||||||
 | 
					  state->prevFrame[burst_time.TN()] = radio_burst;
 | 
				
			||||||
 | 
					  delete bits;
 | 
				
			||||||
 | 
					  return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Transceiver::start()
 | 
					void Transceiver::start()
 | 
				
			||||||
@@ -612,20 +765,14 @@ void Transceiver::driveControl(size_t chan)
 | 
				
			|||||||
      sprintf(response,"RSP POWERON 1");
 | 
					      sprintf(response,"RSP POWERON 1");
 | 
				
			||||||
    else {
 | 
					    else {
 | 
				
			||||||
      sprintf(response,"RSP POWERON 0");
 | 
					      sprintf(response,"RSP POWERON 0");
 | 
				
			||||||
      for (int i = 0; i < 8; i++) {
 | 
					 | 
				
			||||||
       for (int j = 0; j < 8; j++)
 | 
					 | 
				
			||||||
         mHandover[i][j] = false;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      if (!chan && !mOn) {
 | 
					      if (!chan && !mOn) {
 | 
				
			||||||
        // Prepare for thread start
 | 
					        // Prepare for thread start
 | 
				
			||||||
        mPower = -20;
 | 
					        mPower = -20;
 | 
				
			||||||
        mRadioInterface->start();
 | 
					        mRadioInterface->start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Start radio interface threads.
 | 
					        // Start radio interface threads.
 | 
				
			||||||
        mTxLowerLoopThread->start((void * (*)(void*))
 | 
					        mLowerLoopThread->start((void * (*)(void*))
 | 
				
			||||||
                                  TxLowerLoopAdapter,(void*) this);
 | 
					                                LowerLoopAdapter,(void*) this);
 | 
				
			||||||
        mRxLowerLoopThread->start((void * (*)(void*))
 | 
					 | 
				
			||||||
                                  RxLowerLoopAdapter,(void*) this);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (size_t i = 0; i < mChans; i++) {
 | 
					        for (size_t i = 0; i < mChans; i++) {
 | 
				
			||||||
          TransceiverChannel *chan = new TransceiverChannel(this, i);
 | 
					          TransceiverChannel *chan = new TransceiverChannel(this, i);
 | 
				
			||||||
@@ -642,20 +789,6 @@ void Transceiver::driveControl(size_t chan)
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  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) {
 | 
					  else if (strcmp(command,"SETMAXDLY")==0) {
 | 
				
			||||||
    //set expected maximum time-of-arrival
 | 
					    //set expected maximum time-of-arrival
 | 
				
			||||||
    int maxDelay;
 | 
					    int maxDelay;
 | 
				
			||||||
@@ -732,7 +865,7 @@ void Transceiver::driveControl(size_t chan)
 | 
				
			|||||||
    // set TSC
 | 
					    // set TSC
 | 
				
			||||||
    unsigned TSC;
 | 
					    unsigned TSC;
 | 
				
			||||||
    sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
 | 
					    sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
 | 
				
			||||||
    if (mOn || (TSC<0) || (TSC>7))
 | 
					    if (mOn)
 | 
				
			||||||
      sprintf(response, "RSP SETTSC 1 %d", TSC);
 | 
					      sprintf(response, "RSP SETTSC 1 %d", TSC);
 | 
				
			||||||
    else if (chan && (TSC != mTSC))
 | 
					    else if (chan && (TSC != mTSC))
 | 
				
			||||||
      sprintf(response, "RSP SETTSC 1 %d", TSC);
 | 
					      sprintf(response, "RSP SETTSC 1 %d", TSC);
 | 
				
			||||||
@@ -742,8 +875,14 @@ void Transceiver::driveControl(size_t chan)
 | 
				
			|||||||
      sprintf(response,"RSP SETTSC 0 %d", TSC);
 | 
					      sprintf(response,"RSP SETTSC 0 %d", TSC);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  else if (!strcmp(command,"GETBSIC")) {
 | 
				
			||||||
 | 
					    if (mBSIC < 0)
 | 
				
			||||||
 | 
					      sprintf(response, "RSP GETBSIC 1");
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      sprintf(response, "RSP GETBSIC 0 %d", mBSIC);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  else if (strcmp(command,"SETSLOT")==0) {
 | 
					  else if (strcmp(command,"SETSLOT")==0) {
 | 
				
			||||||
    // set slot type
 | 
					    // set TSC 
 | 
				
			||||||
    int  corrCode;
 | 
					    int  corrCode;
 | 
				
			||||||
    int  timeslot;
 | 
					    int  timeslot;
 | 
				
			||||||
    sscanf(buffer,"%3s %s %d %d",cmdcheck,command,×lot,&corrCode);
 | 
					    sscanf(buffer,"%3s %s %d %d",cmdcheck,command,×lot,&corrCode);
 | 
				
			||||||
@@ -755,11 +894,24 @@ void Transceiver::driveControl(size_t chan)
 | 
				
			|||||||
    mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
 | 
					    mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
 | 
				
			||||||
    setModulus(timeslot, chan);
 | 
					    setModulus(timeslot, chan);
 | 
				
			||||||
    sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
 | 
					    sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else if (!strcmp(command,"SETRXMASK")) {
 | 
				
			||||||
 | 
					    int slot;
 | 
				
			||||||
 | 
					    unsigned long long mask;
 | 
				
			||||||
 | 
					    sscanf(buffer,"%3s %s %d 0x%llx", cmdcheck, command, &slot, &mask);
 | 
				
			||||||
 | 
					    if ((slot < 0) || (slot > 7)) {
 | 
				
			||||||
 | 
					      sprintf(response, "RSP SETRXMASK 1");
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      mRxSlotMask[slot] = mask;
 | 
				
			||||||
 | 
					      sprintf(response, "RSP SETRXMASK 0 %d 0x%llx", slot, mask);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else if (!strcmp(command, "SYNC")) {
 | 
				
			||||||
 | 
					    mStates[0].mode = TRX_MODE_MS_ACQUIRE;
 | 
				
			||||||
 | 
					    sprintf(response,"RSP SYNC 0");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  else {
 | 
					  else {
 | 
				
			||||||
    LOG(WARNING) << "bogus command " << command << " on control interface.";
 | 
					    LOG(WARNING) << "bogus command " << command << " on control interface.";
 | 
				
			||||||
    sprintf(response,"RSP ERR 1");
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  mCtrlSockets[chan]->write(response, strlen(response) + 1);
 | 
					  mCtrlSockets[chan]->write(response, strlen(response) + 1);
 | 
				
			||||||
@@ -782,15 +934,6 @@ bool Transceiver::driveTxPriorityQueue(size_t chan)
 | 
				
			|||||||
  for (int i = 0; i < 4; i++)
 | 
					  for (int i = 0; i < 4; i++)
 | 
				
			||||||
    frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
 | 
					    frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // periodically update GSM core clock
 | 
					 | 
				
			||||||
  LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock
 | 
					 | 
				
			||||||
		<< " mLastClockUpdateTime " << mLastClockUpdateTime;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!chan) {
 | 
					 | 
				
			||||||
    if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
 | 
					 | 
				
			||||||
      writeClockInterface();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
 | 
					  LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  int RSSI = (int) buffer[5];
 | 
					  int RSSI = (int) buffer[5];
 | 
				
			||||||
@@ -896,7 +1039,13 @@ void Transceiver::driveTxFIFO()
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      // time to push burst to transmit FIFO
 | 
					      // time to push burst to transmit FIFO
 | 
				
			||||||
      pushRadioVector(mTransmitDeadlineClock);
 | 
					      pushRadioVector(mTransmitDeadlineClock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      mTransmitDeadlineClock.incTN();
 | 
					      mTransmitDeadlineClock.incTN();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!mTransmitDeadlineClock.TN() &&
 | 
				
			||||||
 | 
					          !(mTransmitDeadlineClock.FN() % CLK_IND_INTERVAL)) {
 | 
				
			||||||
 | 
					        writeClockInterface();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -935,22 +1084,12 @@ void *RxUpperLoopAdapter(TransceiverChannel *chan)
 | 
				
			|||||||
  return NULL;
 | 
					  return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void *RxLowerLoopAdapter(Transceiver *transceiver)
 | 
					void *LowerLoopAdapter(Transceiver *transceiver)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  transceiver->setPriority(0.45);
 | 
					  transceiver->setPriority(0.45);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  while (1) {
 | 
					  while (1) {
 | 
				
			||||||
    transceiver->driveReceiveRadio();
 | 
					    transceiver->driveReceiveRadio();
 | 
				
			||||||
    pthread_testcancel();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void *TxLowerLoopAdapter(Transceiver *transceiver)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  transceiver->setPriority(0.44);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  while (1) {
 | 
					 | 
				
			||||||
    transceiver->driveTxFIFO();
 | 
					    transceiver->driveTxFIFO();
 | 
				
			||||||
    pthread_testcancel();
 | 
					    pthread_testcancel();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -80,7 +80,14 @@ struct TransceiverState {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /* Received noise energy levels */
 | 
					  /* Received noise energy levels */
 | 
				
			||||||
  float mNoiseLev;
 | 
					  float mNoiseLev;
 | 
				
			||||||
  noiseVector mNoises;
 | 
					  avgVector mNoises;
 | 
				
			||||||
 | 
					  avgVector mFreqOffsets;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Store pointers to previous frame */
 | 
				
			||||||
 | 
					  radioVector *prevFrame[8];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Transceiver mode */
 | 
				
			||||||
 | 
					  int mode;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** The Transceiver class, responsible for physical layer of basestation */
 | 
					/** The Transceiver class, responsible for physical layer of basestation */
 | 
				
			||||||
@@ -99,8 +106,7 @@ private:
 | 
				
			|||||||
  std::vector<VectorFIFO *>  mReceiveFIFO;      ///< radioInterface FIFO of receive bursts
 | 
					  std::vector<VectorFIFO *>  mReceiveFIFO;      ///< radioInterface FIFO of receive bursts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::vector<Thread *> mRxServiceLoopThreads;  ///< thread to pull bursts into receive FIFO
 | 
					  std::vector<Thread *> mRxServiceLoopThreads;  ///< thread to pull bursts into receive FIFO
 | 
				
			||||||
  Thread *mRxLowerLoopThread;                   ///< thread to pull bursts into receive FIFO
 | 
					  Thread *mLowerLoopThread;                   ///< thread to pull bursts into receive FIFO
 | 
				
			||||||
  Thread *mTxLowerLoopThread;                   ///< thread to push bursts into transmit FIFO
 | 
					 | 
				
			||||||
  std::vector<Thread *> mControlServiceLoopThreads;         ///< thread to process control messages from GSM core
 | 
					  std::vector<Thread *> mControlServiceLoopThreads;         ///< thread to process control messages from GSM core
 | 
				
			||||||
  std::vector<Thread *> mTxPriorityQueueServiceLoopThreads; ///< thread to process transmit bursts from GSM core
 | 
					  std::vector<Thread *> mTxPriorityQueueServiceLoopThreads; ///< thread to process transmit bursts from GSM core
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -116,6 +122,7 @@ private:
 | 
				
			|||||||
    OFF,               ///< timeslot is off
 | 
					    OFF,               ///< timeslot is off
 | 
				
			||||||
    TSC,	       ///< timeslot should contain a normal burst
 | 
					    TSC,	       ///< timeslot should contain a normal burst
 | 
				
			||||||
    RACH,	       ///< timeslot should contain an access burst
 | 
					    RACH,	       ///< timeslot should contain an access burst
 | 
				
			||||||
 | 
					    SCH,	       ///< timeslot should contain a SCH burst
 | 
				
			||||||
    IDLE	       ///< timeslot is an idle (or dummy) burst
 | 
					    IDLE	       ///< timeslot is an idle (or dummy) burst
 | 
				
			||||||
  } CorrType;
 | 
					  } CorrType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -147,6 +154,13 @@ private:
 | 
				
			|||||||
                  signalVector &burst,
 | 
					                  signalVector &burst,
 | 
				
			||||||
                  complex &, float &toa);
 | 
					                  complex &, float &toa);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool detectSCH(TransceiverState *state,
 | 
				
			||||||
 | 
					                  signalVector &burst,
 | 
				
			||||||
 | 
					                  complex &, float &toa);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool decodeSCH(SoftVector *burst, GSM::Time *time);
 | 
				
			||||||
 | 
					  bool correctFCCH(TransceiverState *state, signalVector *burst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Detect normal bursts */
 | 
					  /** Detect normal bursts */
 | 
				
			||||||
  bool detectTSC(TransceiverState *state,
 | 
					  bool detectTSC(TransceiverState *state,
 | 
				
			||||||
                 signalVector &burst,
 | 
					                 signalVector &burst,
 | 
				
			||||||
@@ -163,12 +177,13 @@ private:
 | 
				
			|||||||
  size_t mChans;
 | 
					  size_t mChans;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool mOn;			       ///< flag to indicate that transceiver is powered on
 | 
					  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 mTxFreq;                      ///< the transmit frequency
 | 
				
			||||||
  double mRxFreq;                      ///< the receive frequency
 | 
					  double mRxFreq;                      ///< the receive frequency
 | 
				
			||||||
  int mPower;                          ///< the transmit power in dB
 | 
					  int mPower;                          ///< the transmit power in dB
 | 
				
			||||||
  unsigned mTSC;                       ///< the midamble sequence code
 | 
					  unsigned mTSC;                       ///< the midamble sequence code
 | 
				
			||||||
  unsigned mMaxExpectedDelay;            ///< maximum expected time-of-arrival offset in GSM symbols
 | 
					  unsigned mMaxExpectedDelay;          ///< maximum TOA offset in GSM symbols
 | 
				
			||||||
 | 
					  unsigned long long mRxSlotMask[8];   ///< MS - enabled multiframe slot mask
 | 
				
			||||||
 | 
					  int mBSIC;                           ///< MS - detected BSIC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::vector<TransceiverState> mStates;
 | 
					  std::vector<TransceiverState> mStates;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -227,6 +242,13 @@ public:
 | 
				
			|||||||
    LOOPBACK            ///< similar go VII, used in loopback testing
 | 
					    LOOPBACK            ///< similar go VII, used in loopback testing
 | 
				
			||||||
  } ChannelCombination;
 | 
					  } ChannelCombination;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  enum {
 | 
				
			||||||
 | 
					    TRX_MODE_OFF,
 | 
				
			||||||
 | 
					    TRX_MODE_BTS,
 | 
				
			||||||
 | 
					    TRX_MODE_MS_ACQUIRE,
 | 
				
			||||||
 | 
					    TRX_MODE_MS_TRACK,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
  /** drive lower receive I/O and burst generation */
 | 
					  /** drive lower receive I/O and burst generation */
 | 
				
			||||||
  void driveReceiveRadio();
 | 
					  void driveReceiveRadio();
 | 
				
			||||||
@@ -250,9 +272,7 @@ protected:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  friend void *TxUpperLoopAdapter(TransceiverChannel *);
 | 
					  friend void *TxUpperLoopAdapter(TransceiverChannel *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  friend void *RxLowerLoopAdapter(Transceiver *);
 | 
					  friend void *LowerLoopAdapter(Transceiver *);
 | 
				
			||||||
 | 
					 | 
				
			||||||
  friend void *TxLowerLoopAdapter(Transceiver *);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  friend void *ControlServiceLoopAdapter(TransceiverChannel *);
 | 
					  friend void *ControlServiceLoopAdapter(TransceiverChannel *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -267,8 +287,7 @@ protected:
 | 
				
			|||||||
void *RxUpperLoopAdapter(TransceiverChannel *);
 | 
					void *RxUpperLoopAdapter(TransceiverChannel *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Main drive threads */
 | 
					/** Main drive threads */
 | 
				
			||||||
void *RxLowerLoopAdapter(Transceiver *);
 | 
					void *LowerLoopAdapter(Transceiver *);
 | 
				
			||||||
void *TxLowerLoopAdapter(Transceiver *);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** control message handler thread loop */
 | 
					/** control message handler thread loop */
 | 
				
			||||||
void *ControlServiceLoopAdapter(TransceiverChannel *);
 | 
					void *ControlServiceLoopAdapter(TransceiverChannel *);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,12 +37,9 @@
 | 
				
			|||||||
#define B2XX_BASE_RT     GSMRATE
 | 
					#define B2XX_BASE_RT     GSMRATE
 | 
				
			||||||
#define B100_BASE_RT     400000
 | 
					#define B100_BASE_RT     400000
 | 
				
			||||||
#define USRP2_BASE_RT    390625
 | 
					#define USRP2_BASE_RT    390625
 | 
				
			||||||
#define USRP_TX_AMPL     0.3
 | 
					#define TX_AMPL          0.3
 | 
				
			||||||
#define UMTRX_TX_AMPL    0.7
 | 
					 | 
				
			||||||
#define SAMPLE_BUF_SZ    (1 << 20)
 | 
					#define SAMPLE_BUF_SZ    (1 << 20)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define UMTRX_VGA1_DEF   -18
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum uhd_dev_type {
 | 
					enum uhd_dev_type {
 | 
				
			||||||
	USRP1,
 | 
						USRP1,
 | 
				
			||||||
	USRP2,
 | 
						USRP2,
 | 
				
			||||||
@@ -61,6 +58,11 @@ struct uhd_dev_offset {
 | 
				
			|||||||
	const std::string desc;
 | 
						const std::string desc;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct tune_result {
 | 
				
			||||||
 | 
						uhd::tune_result_t uhd;
 | 
				
			||||||
 | 
						double freq;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Tx / Rx sample offset values. In a perfect world, there is no group delay
 | 
					 * Tx / Rx sample offset values. In a perfect world, there is no group delay
 | 
				
			||||||
 * though analog components, and behaviour through digital filters exactly
 | 
					 * though analog components, and behaviour through digital filters exactly
 | 
				
			||||||
@@ -285,11 +287,12 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	bool setTxFreq(double wFreq, size_t chan);
 | 
						bool setTxFreq(double wFreq, size_t chan);
 | 
				
			||||||
	bool setRxFreq(double wFreq, size_t chan);
 | 
						bool setRxFreq(double wFreq, size_t chan);
 | 
				
			||||||
 | 
						bool setRxOffset(double wOffset, size_t chan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inline TIMESTAMP initialWriteTimestamp() { return ts_initial * sps; }
 | 
						inline TIMESTAMP initialWriteTimestamp() { return ts_initial * sps; }
 | 
				
			||||||
	inline TIMESTAMP initialReadTimestamp() { return ts_initial; }
 | 
						inline TIMESTAMP initialReadTimestamp() { return ts_initial; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inline double fullScaleInputValue() { return (dev_type==UMTRX) ? (32000 * UMTRX_TX_AMPL) : (32000 * USRP_TX_AMPL); }
 | 
						inline double fullScaleInputValue() { return 32000 * TX_AMPL; }
 | 
				
			||||||
	inline double fullScaleOutputValue() { return 32000; }
 | 
						inline double fullScaleOutputValue() { return 32000; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	double setRxGain(double db, size_t chan);
 | 
						double setRxGain(double db, size_t chan);
 | 
				
			||||||
@@ -335,7 +338,7 @@ private:
 | 
				
			|||||||
	double offset;
 | 
						double offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::vector<double> tx_gains, rx_gains;
 | 
						std::vector<double> tx_gains, rx_gains;
 | 
				
			||||||
	std::vector<double> tx_freqs, rx_freqs;
 | 
						std::vector<tune_result> tx_freqs, rx_freqs;
 | 
				
			||||||
	size_t tx_spp, rx_spp;
 | 
						size_t tx_spp, rx_spp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool started;
 | 
						bool started;
 | 
				
			||||||
@@ -424,43 +427,21 @@ void uhd_device::init_gains()
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	uhd::gain_range_t range;
 | 
						uhd::gain_range_t range;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dev_type == UMTRX) {
 | 
						range = usrp_dev->get_tx_gain_range();
 | 
				
			||||||
		std::vector<std::string> gain_stages = usrp_dev->get_tx_gain_names(0);
 | 
						tx_gain_min = range.start();
 | 
				
			||||||
		if (gain_stages[0] == "VGA") {
 | 
						tx_gain_max = range.stop();
 | 
				
			||||||
			LOG(WARNING) << "Update your UHD version for a proper Tx gain support";
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (gain_stages[0] == "VGA" || gain_stages[0] == "PA") {
 | 
					 | 
				
			||||||
			range = usrp_dev->get_tx_gain_range();
 | 
					 | 
				
			||||||
			tx_gain_min = range.start();
 | 
					 | 
				
			||||||
			tx_gain_max = range.stop();
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			range = usrp_dev->get_tx_gain_range("VGA2");
 | 
					 | 
				
			||||||
			tx_gain_min = UMTRX_VGA1_DEF + range.start();
 | 
					 | 
				
			||||||
			tx_gain_max = UMTRX_VGA1_DEF + range.stop();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		range = usrp_dev->get_tx_gain_range();
 | 
					 | 
				
			||||||
		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();
 | 
						range = usrp_dev->get_rx_gain_range();
 | 
				
			||||||
	rx_gain_min = range.start();
 | 
						rx_gain_min = range.start();
 | 
				
			||||||
	rx_gain_max = range.stop();
 | 
						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++) {
 | 
						for (size_t i = 0; i < tx_gains.size(); i++) {
 | 
				
			||||||
		double gain = (tx_gain_min + tx_gain_max) / 2;
 | 
							usrp_dev->set_tx_gain((tx_gain_min + tx_gain_max) / 2, i);
 | 
				
			||||||
		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);
 | 
							tx_gains[i] = usrp_dev->get_tx_gain(i);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (size_t i = 0; i < rx_gains.size(); i++) {
 | 
						for (size_t i = 0; i < rx_gains.size(); i++) {
 | 
				
			||||||
		double gain = (rx_gain_min + rx_gain_max) / 2;
 | 
							usrp_dev->set_rx_gain((rx_gain_min + rx_gain_max) / 2, i);
 | 
				
			||||||
		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);
 | 
							rx_gains[i] = usrp_dev->get_rx_gain(i);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -539,27 +520,10 @@ double uhd_device::setTxGain(double db, size_t chan)
 | 
				
			|||||||
		return 0.0f;
 | 
							return 0.0f;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dev_type == UMTRX) {
 | 
						usrp_dev->set_tx_gain(db, chan);
 | 
				
			||||||
		std::vector<std::string> gain_stages = usrp_dev->get_tx_gain_names(0);
 | 
						tx_gains[chan] = usrp_dev->get_tx_gain(chan);
 | 
				
			||||||
		if (gain_stages[0] == "VGA" || gain_stages[0] == "PA") {
 | 
					 | 
				
			||||||
			usrp_dev->set_tx_gain(db, chan);
 | 
					 | 
				
			||||||
			tx_gains[chan] = usrp_dev->get_tx_gain(chan);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			// New UHD versions support split configuration of
 | 
					 | 
				
			||||||
			// Tx gain stages. We utilize this to set the gain
 | 
					 | 
				
			||||||
			// configuration, optimal for the Tx signal quality.
 | 
					 | 
				
			||||||
			// From our measurements, VGA1 must be 18dB plus-minus
 | 
					 | 
				
			||||||
			// one and VGA2 is the best when 23dB or lower.
 | 
					 | 
				
			||||||
			usrp_dev->set_tx_gain(UMTRX_VGA1_DEF, "VGA1", chan);
 | 
					 | 
				
			||||||
			usrp_dev->set_tx_gain(db-UMTRX_VGA1_DEF, "VGA2", chan);
 | 
					 | 
				
			||||||
			tx_gains[chan] = usrp_dev->get_tx_gain(chan);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		usrp_dev->set_tx_gain(db, chan);
 | 
					 | 
				
			||||||
		tx_gains[chan] = usrp_dev->get_tx_gain(chan);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOG(INFO) << "Set TX gain to " << tx_gains[chan] << "dB (asked for " << db << "dB)";
 | 
						LOG(INFO) << "Set TX gain to " << tx_gains[chan] << "dB";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return tx_gains[chan];
 | 
						return tx_gains[chan];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -574,7 +538,7 @@ double uhd_device::setRxGain(double db, size_t chan)
 | 
				
			|||||||
	usrp_dev->set_rx_gain(db, chan);
 | 
						usrp_dev->set_rx_gain(db, chan);
 | 
				
			||||||
	rx_gains[chan] = usrp_dev->get_rx_gain(chan);
 | 
						rx_gains[chan] = usrp_dev->get_rx_gain(chan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOG(INFO) << "Set RX gain to " << rx_gains[chan] << "dB (asked for " << db << "dB)";
 | 
						LOG(INFO) << "Set RX gain to " << rx_gains[chan] << "dB";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return rx_gains[chan];
 | 
						return rx_gains[chan];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -672,7 +636,7 @@ int uhd_device::open(const std::string &args, bool extref)
 | 
				
			|||||||
	// Use the first found device
 | 
						// Use the first found device
 | 
				
			||||||
	LOG(INFO) << "Using discovered UHD device " << dev_addrs[0].to_string();
 | 
						LOG(INFO) << "Using discovered UHD device " << dev_addrs[0].to_string();
 | 
				
			||||||
	try {
 | 
						try {
 | 
				
			||||||
		usrp_dev = uhd::usrp::multi_usrp::make(addr);
 | 
							usrp_dev = uhd::usrp::multi_usrp::make(dev_addrs[0]);
 | 
				
			||||||
	} catch(...) {
 | 
						} catch(...) {
 | 
				
			||||||
		LOG(ALERT) << "UHD make failed, device " << dev_addrs[0].to_string();
 | 
							LOG(ALERT) << "UHD make failed, device " << dev_addrs[0].to_string();
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
@@ -715,16 +679,6 @@ int uhd_device::open(const std::string &args, bool extref)
 | 
				
			|||||||
	if (set_rates(_tx_rate, _rx_rate) < 0)
 | 
						if (set_rates(_tx_rate, _rx_rate) < 0)
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Set RF frontend bandwidth
 | 
					 | 
				
			||||||
	if (dev_type == UMTRX) {
 | 
					 | 
				
			||||||
		// Setting LMS6002D LPF to 500kHz gives us the best signal quality
 | 
					 | 
				
			||||||
		for (size_t i = 0; i < chans; i++) {
 | 
					 | 
				
			||||||
			usrp_dev->set_tx_bandwidth(500*1000*2, i);
 | 
					 | 
				
			||||||
			if (!diversity)
 | 
					 | 
				
			||||||
				usrp_dev->set_rx_bandwidth(500*1000*2, i);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Create TX and RX streamers */
 | 
						/* Create TX and RX streamers */
 | 
				
			||||||
	uhd::stream_args_t stream_args("sc16");
 | 
						uhd::stream_args_t stream_args("sc16");
 | 
				
			||||||
	for (size_t i = 0; i < chans; i++)
 | 
						for (size_t i = 0; i < chans; i++)
 | 
				
			||||||
@@ -875,7 +829,6 @@ void uhd_device::setPriority(float prio)
 | 
				
			|||||||
int uhd_device::check_rx_md_err(uhd::rx_metadata_t &md, ssize_t num_smpls)
 | 
					int uhd_device::check_rx_md_err(uhd::rx_metadata_t &md, ssize_t num_smpls)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uhd::time_spec_t ts;
 | 
						uhd::time_spec_t ts;
 | 
				
			||||||
	static int err_count = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!num_smpls) {
 | 
						if (!num_smpls) {
 | 
				
			||||||
		LOG(ERR) << str_code(md);
 | 
							LOG(ERR) << str_code(md);
 | 
				
			||||||
@@ -883,11 +836,6 @@ int uhd_device::check_rx_md_err(uhd::rx_metadata_t &md, ssize_t num_smpls)
 | 
				
			|||||||
		switch (md.error_code) {
 | 
							switch (md.error_code) {
 | 
				
			||||||
		case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT:
 | 
							case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT:
 | 
				
			||||||
			LOG(ALERT) << "UHD: Receive timed out";
 | 
								LOG(ALERT) << "UHD: Receive timed out";
 | 
				
			||||||
			if (err_count > 100) {
 | 
					 | 
				
			||||||
				err_count = 0;
 | 
					 | 
				
			||||||
				return ERROR_UNRECOVERABLE;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			err_count++;
 | 
					 | 
				
			||||||
		case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW:
 | 
							case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW:
 | 
				
			||||||
		case uhd::rx_metadata_t::ERROR_CODE_LATE_COMMAND:
 | 
							case uhd::rx_metadata_t::ERROR_CODE_LATE_COMMAND:
 | 
				
			||||||
		case uhd::rx_metadata_t::ERROR_CODE_BROKEN_CHAIN:
 | 
							case uhd::rx_metadata_t::ERROR_CODE_BROKEN_CHAIN:
 | 
				
			||||||
@@ -944,7 +892,7 @@ int uhd_device::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
 | 
				
			|||||||
	if (rc < 0) {
 | 
						if (rc < 0) {
 | 
				
			||||||
		LOG(ERR) << rx_buffers[0]->str_code(rc);
 | 
							LOG(ERR) << rx_buffers[0]->str_code(rc);
 | 
				
			||||||
		LOG(ERR) << rx_buffers[0]->str_status();
 | 
							LOG(ERR) << rx_buffers[0]->str_status();
 | 
				
			||||||
		return 0;
 | 
							return len;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Create vector buffer
 | 
						// Create vector buffer
 | 
				
			||||||
@@ -1054,30 +1002,20 @@ int uhd_device::writeSamples(std::vector<short *> &bufs, int len, bool *underrun
 | 
				
			|||||||
	return num_smpls;
 | 
						return num_smpls;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool uhd_device::updateAlignment(TIMESTAMP timestamp)
 | 
					bool uhd_device::updateAlignment(TIMESTAMP)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						aligned = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uhd::tune_request_t uhd_device::select_freq(double freq, size_t chan, bool tx)
 | 
					uhd::tune_request_t uhd_device::select_freq(double freq, size_t chan, bool tx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	double rf_spread, rf_freq;
 | 
						double rf_spread, rf_freq;
 | 
				
			||||||
	std::vector<double> freqs;
 | 
						std::vector<tune_result> freqs;
 | 
				
			||||||
	uhd::tune_request_t treq(freq);
 | 
						uhd::tune_request_t treq(freq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dev_type == UMTRX) {
 | 
						if ((chans == 1) || ((chans == 2) && dev_type == UMTRX)) {
 | 
				
			||||||
		if (offset > 0.0)
 | 
					 | 
				
			||||||
			return uhd::tune_request_t(freq, offset);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Don't use DSP tuning, because LMS6002D PLL steps are small enough.
 | 
					 | 
				
			||||||
		// We end up with DSP tuning just for 2-3Hz, which is meaningless and
 | 
					 | 
				
			||||||
		// only distort the signal (because cordic is not ideal).
 | 
					 | 
				
			||||||
		treq.target_freq = freq;
 | 
					 | 
				
			||||||
		treq.rf_freq_policy = uhd::tune_request_t::POLICY_MANUAL;
 | 
					 | 
				
			||||||
		treq.rf_freq = freq;
 | 
					 | 
				
			||||||
		treq.dsp_freq_policy = uhd::tune_request_t::POLICY_MANUAL;
 | 
					 | 
				
			||||||
		treq.dsp_freq = 0.0;
 | 
					 | 
				
			||||||
	} else if (chans == 1) {
 | 
					 | 
				
			||||||
		if (offset == 0.0)
 | 
							if (offset == 0.0)
 | 
				
			||||||
			return treq;
 | 
								return treq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1093,17 +1031,17 @@ uhd::tune_request_t uhd_device::select_freq(double freq, size_t chan, bool tx)
 | 
				
			|||||||
		freqs = rx_freqs;
 | 
							freqs = rx_freqs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Tune directly if other channel isn't tuned */
 | 
						/* Tune directly if other channel isn't tuned */
 | 
				
			||||||
	if (freqs[!chan] < 10.0)
 | 
						if (freqs[!chan].freq < 10.0)
 | 
				
			||||||
		return treq;
 | 
							return treq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Find center frequency between channels */
 | 
						/* Find center frequency between channels */
 | 
				
			||||||
	rf_spread = fabs(freqs[!chan] - freq);
 | 
						rf_spread = fabs(freqs[!chan].freq - freq);
 | 
				
			||||||
	if (rf_spread > B2XX_CLK_RT) {
 | 
						if (rf_spread > B2XX_CLK_RT) {
 | 
				
			||||||
		LOG(ALERT) << rf_spread << "Hz tuning spread not supported\n";
 | 
							LOG(ALERT) << rf_spread << "Hz tuning spread not supported\n";
 | 
				
			||||||
		return treq;
 | 
							return treq;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rf_freq = (freqs[!chan] + freq) / 2.0f;
 | 
						rf_freq = (freqs[!chan].freq + freq) / 2.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	treq.rf_freq_policy = uhd::tune_request_t::POLICY_MANUAL;
 | 
						treq.rf_freq_policy = uhd::tune_request_t::POLICY_MANUAL;
 | 
				
			||||||
	treq.target_freq = freq;
 | 
						treq.target_freq = freq;
 | 
				
			||||||
@@ -1120,10 +1058,12 @@ bool uhd_device::set_freq(double freq, size_t chan, bool tx)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (tx) {
 | 
						if (tx) {
 | 
				
			||||||
		tres = usrp_dev->set_tx_freq(treq, chan);
 | 
							tres = usrp_dev->set_tx_freq(treq, chan);
 | 
				
			||||||
		tx_freqs[chan] = usrp_dev->get_tx_freq(chan);
 | 
							tx_freqs[chan].uhd = tres;
 | 
				
			||||||
 | 
							tx_freqs[chan].freq = usrp_dev->get_tx_freq(chan);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		tres = usrp_dev->set_rx_freq(treq, chan);
 | 
							tres = usrp_dev->set_rx_freq(treq, chan);
 | 
				
			||||||
		rx_freqs[chan] = usrp_dev->get_rx_freq(chan);
 | 
							rx_freqs[chan].uhd = tres;
 | 
				
			||||||
 | 
							rx_freqs[chan].freq = usrp_dev->get_rx_freq(chan);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	LOG(INFO) << "\n" << tres.to_pp_string() << std::endl;
 | 
						LOG(INFO) << "\n" << tres.to_pp_string() << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1136,13 +1076,15 @@ bool uhd_device::set_freq(double freq, size_t chan, bool tx)
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (treq.rf_freq_policy == uhd::tune_request_t::POLICY_MANUAL) {
 | 
						if (treq.rf_freq_policy == uhd::tune_request_t::POLICY_MANUAL) {
 | 
				
			||||||
		if (tx) {
 | 
							if (tx) {
 | 
				
			||||||
			treq = select_freq(tx_freqs[!chan], !chan, true);
 | 
								treq = select_freq(tx_freqs[!chan].freq, !chan, true);
 | 
				
			||||||
			tres = usrp_dev->set_tx_freq(treq, !chan);
 | 
								tres = usrp_dev->set_tx_freq(treq, !chan);
 | 
				
			||||||
			tx_freqs[!chan] = usrp_dev->get_tx_freq(!chan);
 | 
								tx_freqs[!chan].uhd = tres;
 | 
				
			||||||
 | 
								tx_freqs[!chan].freq = usrp_dev->get_tx_freq(!chan);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			treq = select_freq(rx_freqs[!chan], !chan, false);
 | 
								treq = select_freq(rx_freqs[!chan].freq, !chan, false);
 | 
				
			||||||
			tres = usrp_dev->set_rx_freq(treq, !chan);
 | 
								tres = usrp_dev->set_rx_freq(treq, !chan);
 | 
				
			||||||
			rx_freqs[!chan] = usrp_dev->get_rx_freq(!chan);
 | 
								rx_freqs[!chan].uhd = tres;
 | 
				
			||||||
 | 
								rx_freqs[!chan].freq = usrp_dev->get_rx_freq(!chan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		LOG(INFO) << "\n" << tres.to_pp_string() << std::endl;
 | 
							LOG(INFO) << "\n" << tres.to_pp_string() << std::endl;
 | 
				
			||||||
@@ -1161,6 +1103,20 @@ bool uhd_device::setTxFreq(double wFreq, size_t chan)
 | 
				
			|||||||
	return set_freq(wFreq, chan, true);
 | 
						return set_freq(wFreq, chan, true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool uhd_device::setRxOffset(double wOffset, size_t chan)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uhd::tune_result_t tres;
 | 
				
			||||||
 | 
						uhd::tune_request_t treq(rx_freqs[chan].freq - wOffset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						treq.rf_freq_policy = uhd::tune_request_t::POLICY_MANUAL;
 | 
				
			||||||
 | 
						treq.rf_freq = rx_freqs[chan].uhd.actual_rf_freq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tres = usrp_dev->set_rx_freq(treq, chan);
 | 
				
			||||||
 | 
						rx_freqs[chan].freq = usrp_dev->get_rx_freq(chan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool uhd_device::setRxFreq(double wFreq, size_t chan)
 | 
					bool uhd_device::setRxFreq(double wFreq, size_t chan)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (chan >= rx_freqs.size()) {
 | 
						if (chan >= rx_freqs.size()) {
 | 
				
			||||||
@@ -1178,7 +1134,7 @@ double uhd_device::getTxFreq(size_t chan)
 | 
				
			|||||||
		return 0.0;
 | 
							return 0.0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return tx_freqs[chan];
 | 
						return tx_freqs[chan].freq;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
double uhd_device::getRxFreq(size_t chan)
 | 
					double uhd_device::getRxFreq(size_t chan)
 | 
				
			||||||
@@ -1188,7 +1144,7 @@ double uhd_device::getRxFreq(size_t chan)
 | 
				
			|||||||
		return 0.0;
 | 
							return 0.0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return rx_freqs[chan];
 | 
						return rx_freqs[chan].freq;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool uhd_device::recv_async_msg()
 | 
					bool uhd_device::recv_async_msg()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -68,6 +68,7 @@ struct trx_config {
 | 
				
			|||||||
	bool extref;
 | 
						bool extref;
 | 
				
			||||||
	bool filler;
 | 
						bool filler;
 | 
				
			||||||
	bool diversity;
 | 
						bool diversity;
 | 
				
			||||||
 | 
						bool ms;
 | 
				
			||||||
	double offset;
 | 
						double offset;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -118,7 +119,7 @@ bool testConfig()
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
bool trx_setup_config(struct trx_config *config)
 | 
					bool trx_setup_config(struct trx_config *config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	std::string refstr, fillstr, divstr;
 | 
						std::string refstr, fillstr, divstr, msstr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!testConfig())
 | 
						if (!testConfig())
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
@@ -167,6 +168,7 @@ bool trx_setup_config(struct trx_config *config)
 | 
				
			|||||||
	refstr = config->extref ? "Enabled" : "Disabled";
 | 
						refstr = config->extref ? "Enabled" : "Disabled";
 | 
				
			||||||
	fillstr = config->filler ? "Enabled" : "Disabled";
 | 
						fillstr = config->filler ? "Enabled" : "Disabled";
 | 
				
			||||||
	divstr = config->diversity ? "Enabled" : "Disabled";
 | 
						divstr = config->diversity ? "Enabled" : "Disabled";
 | 
				
			||||||
 | 
						msstr = config->ms ? "Enabled" : "Disabled";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::ostringstream ost("");
 | 
						std::ostringstream ost("");
 | 
				
			||||||
	ost << "Config Settings" << std::endl;
 | 
						ost << "Config Settings" << std::endl;
 | 
				
			||||||
@@ -179,6 +181,7 @@ bool trx_setup_config(struct trx_config *config)
 | 
				
			|||||||
	ost << "   External Reference...... " << refstr << std::endl;
 | 
						ost << "   External Reference...... " << refstr << std::endl;
 | 
				
			||||||
	ost << "   C0 Filler Table......... " << fillstr << std::endl;
 | 
						ost << "   C0 Filler Table......... " << fillstr << std::endl;
 | 
				
			||||||
	ost << "   Diversity............... " << divstr << std::endl;
 | 
						ost << "   Diversity............... " << divstr << std::endl;
 | 
				
			||||||
 | 
						ost << "   MS Mode................. " << msstr << std::endl;
 | 
				
			||||||
	ost << "   Tuning offset........... " << config->offset << std::endl;
 | 
						ost << "   Tuning offset........... " << config->offset << std::endl;
 | 
				
			||||||
	std::cout << ost << std::endl;
 | 
						std::cout << ost << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -196,10 +199,22 @@ RadioInterface *makeRadioInterface(struct trx_config *config,
 | 
				
			|||||||
                                   RadioDevice *usrp, int type)
 | 
					                                   RadioDevice *usrp, int type)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	RadioInterface *radio = NULL;
 | 
						RadioInterface *radio = NULL;
 | 
				
			||||||
 | 
						size_t div = 1;
 | 
				
			||||||
 | 
						int offset = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (config->ms) {
 | 
				
			||||||
 | 
							if (type != RadioDevice::NORMAL) {
 | 
				
			||||||
 | 
								LOG(ALERT) << "Unsupported configuration";
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							offset *= -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (type) {
 | 
						switch (type) {
 | 
				
			||||||
	case RadioDevice::NORMAL:
 | 
						case RadioDevice::NORMAL:
 | 
				
			||||||
		radio = new RadioInterface(usrp, config->sps, config->chans);
 | 
							radio = new RadioInterface(usrp, config->sps,
 | 
				
			||||||
 | 
										   config->chans, div, offset);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case RadioDevice::RESAMP_64M:
 | 
						case RadioDevice::RESAMP_64M:
 | 
				
			||||||
	case RadioDevice::RESAMP_100M:
 | 
						case RadioDevice::RESAMP_100M:
 | 
				
			||||||
@@ -286,6 +301,7 @@ static void print_help()
 | 
				
			|||||||
		"  -s    Samples-per-symbol (1 or 4)\n"
 | 
							"  -s    Samples-per-symbol (1 or 4)\n"
 | 
				
			||||||
		"  -c    Number of ARFCN channels (default=1)\n"
 | 
							"  -c    Number of ARFCN channels (default=1)\n"
 | 
				
			||||||
		"  -f    Enable C0 filler table\n"
 | 
							"  -f    Enable C0 filler table\n"
 | 
				
			||||||
 | 
							"  -m    Enable MS mode\n"
 | 
				
			||||||
		"  -o    Set baseband frequency offset (default=auto)\n",
 | 
							"  -o    Set baseband frequency offset (default=auto)\n",
 | 
				
			||||||
		"EMERG, ALERT, CRT, ERR, WARNING, NOTICE, INFO, DEBUG");
 | 
							"EMERG, ALERT, CRT, ERR, WARNING, NOTICE, INFO, DEBUG");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -300,9 +316,10 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
 | 
				
			|||||||
	config->extref = false;
 | 
						config->extref = false;
 | 
				
			||||||
	config->filler = false;
 | 
						config->filler = false;
 | 
				
			||||||
	config->diversity = false;
 | 
						config->diversity = false;
 | 
				
			||||||
 | 
						config->ms = false;
 | 
				
			||||||
	config->offset = 0.0;
 | 
						config->offset = 0.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while ((option = getopt(argc, argv, "ha:l:i:p:c:dxfo:s:")) != -1) {
 | 
						while ((option = getopt(argc, argv, "ha:l:i:p:c:dxfo:ms:")) != -1) {
 | 
				
			||||||
		switch (option) {
 | 
							switch (option) {
 | 
				
			||||||
		case 'h':
 | 
							case 'h':
 | 
				
			||||||
			print_help();
 | 
								print_help();
 | 
				
			||||||
@@ -335,6 +352,9 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
 | 
				
			|||||||
		case 'o':
 | 
							case 'o':
 | 
				
			||||||
			config->offset = atof(optarg);
 | 
								config->offset = atof(optarg);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
							case 'm':
 | 
				
			||||||
 | 
								config->ms = true;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		case 's':
 | 
							case 's':
 | 
				
			||||||
			config->sps = atoi(optarg);
 | 
								config->sps = atoi(optarg);
 | 
				
			||||||
			if ((config->sps != 1) && (config->sps != 4)) {
 | 
								if ((config->sps != 1) && (config->sps != 4)) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,6 +29,40 @@ void RadioClock::set(const GSM::Time& wTime)
 | 
				
			|||||||
	mLock.unlock();
 | 
						mLock.unlock();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GSM::Time RadioClock::adjust(GSM::Time &wBase, GSM::Time &wOffset)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int tn_diff, fn_diff = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Modulo TN adustment */
 | 
				
			||||||
 | 
						tn_diff = wBase.TN() + wOffset.TN();
 | 
				
			||||||
 | 
						if (tn_diff < 0) {
 | 
				
			||||||
 | 
							tn_diff += 8;
 | 
				
			||||||
 | 
							fn_diff--;
 | 
				
			||||||
 | 
						} else if (tn_diff >= 8) {
 | 
				
			||||||
 | 
							tn_diff -= 8;
 | 
				
			||||||
 | 
							fn_diff++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Modulo FN adjustment */
 | 
				
			||||||
 | 
						fn_diff += wBase.FN() + wOffset.FN();
 | 
				
			||||||
 | 
						if (fn_diff < 0)
 | 
				
			||||||
 | 
							fn_diff += GSM::gHyperframe;
 | 
				
			||||||
 | 
						else if ((unsigned) fn_diff >= GSM::gHyperframe)
 | 
				
			||||||
 | 
							fn_diff = fn_diff - GSM::gHyperframe;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return GSM::Time(fn_diff, tn_diff);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RadioClock::adjust(GSM::Time& wOffset)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						mLock.lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mClock = adjust(mClock, wOffset); 
 | 
				
			||||||
 | 
						updateSignal.signal();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mLock.unlock();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void RadioClock::incTN()
 | 
					void RadioClock::incTN()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	mLock.lock();
 | 
						mLock.lock();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,7 +26,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class RadioClock {
 | 
					class RadioClock {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
						static GSM::Time adjust(GSM::Time &base, GSM::Time &offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void set(const GSM::Time& wTime);
 | 
						void set(const GSM::Time& wTime);
 | 
				
			||||||
 | 
						void adjust(GSM::Time &wOffset);
 | 
				
			||||||
	void incTN();
 | 
						void incTN();
 | 
				
			||||||
	GSM::Time get();
 | 
						GSM::Time get();
 | 
				
			||||||
	void wait();
 | 
						void wait();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -91,6 +91,9 @@ class RadioDevice {
 | 
				
			|||||||
  /** Set the receiver frequency */
 | 
					  /** Set the receiver frequency */
 | 
				
			||||||
  virtual bool setRxFreq(double wFreq, size_t chan = 0) = 0;
 | 
					  virtual bool setRxFreq(double wFreq, size_t chan = 0) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Adjust the receiver offset */
 | 
				
			||||||
 | 
					  virtual bool setRxOffset(double wOffset, size_t chan = 0) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Returns the starting write Timestamp*/
 | 
					  /** Returns the starting write Timestamp*/
 | 
				
			||||||
  virtual TIMESTAMP initialWriteTimestamp(void)=0;
 | 
					  virtual TIMESTAMP initialWriteTimestamp(void)=0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,7 +38,8 @@ RadioInterface::RadioInterface(RadioDevice *wRadio,
 | 
				
			|||||||
                               int wReceiveOffset, GSM::Time wStartTime)
 | 
					                               int wReceiveOffset, GSM::Time wStartTime)
 | 
				
			||||||
  : mRadio(wRadio), mSPSTx(sps), mSPSRx(1), mChans(chans), mMIMO(diversity),
 | 
					  : mRadio(wRadio), mSPSTx(sps), mSPSRx(1), mChans(chans), mMIMO(diversity),
 | 
				
			||||||
    sendCursor(0), recvCursor(0), underrun(false), overrun(false),
 | 
					    sendCursor(0), recvCursor(0), underrun(false), overrun(false),
 | 
				
			||||||
    receiveOffset(wReceiveOffset), mOn(false)
 | 
					    receiveOffset(wReceiveOffset), shiftOffset(0), shiftUpdate(false),
 | 
				
			||||||
 | 
					    mOn(false)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  mClock.set(wStartTime);
 | 
					  mClock.set(wStartTime);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -157,6 +158,11 @@ int RadioInterface::unRadioifyVector(float *floatVector,
 | 
				
			|||||||
  return newVector.size();
 | 
					  return newVector.size();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RadioInterface::adjustClock(GSM::Time &offset)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  mClock.adjust(offset);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool RadioInterface::tuneTx(double freq, size_t chan)
 | 
					bool RadioInterface::tuneTx(double freq, size_t chan)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  return mRadio->setTxFreq(freq, chan);
 | 
					  return mRadio->setTxFreq(freq, chan);
 | 
				
			||||||
@@ -167,6 +173,10 @@ bool RadioInterface::tuneRx(double freq, size_t chan)
 | 
				
			|||||||
  return mRadio->setRxFreq(freq, chan);
 | 
					  return mRadio->setRxFreq(freq, chan);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool RadioInterface::tuneRxOffset(double offset, size_t chan)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  return mRadio->setRxOffset(offset, chan);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void RadioInterface::start()
 | 
					void RadioInterface::start()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -228,7 +238,11 @@ bool RadioInterface::driveReceiveRadio()
 | 
				
			|||||||
  pullBuffer();
 | 
					  pullBuffer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  GSM::Time rcvClock = mClock.get();
 | 
					  GSM::Time rcvClock = mClock.get();
 | 
				
			||||||
  rcvClock.decTN(receiveOffset);
 | 
					  if (receiveOffset < 0)
 | 
				
			||||||
 | 
					    rcvClock.incTN(-receiveOffset);
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    rcvClock.decTN(receiveOffset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  unsigned tN = rcvClock.TN();
 | 
					  unsigned tN = rcvClock.TN();
 | 
				
			||||||
  int recvSz = recvCursor;
 | 
					  int recvSz = recvCursor;
 | 
				
			||||||
  int readSz = 0;
 | 
					  int readSz = 0;
 | 
				
			||||||
@@ -292,6 +306,12 @@ bool RadioInterface::isUnderrun()
 | 
				
			|||||||
  return retVal;
 | 
					  return retVal;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RadioInterface::applyOffset(int offset)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  shiftOffset += offset;
 | 
				
			||||||
 | 
					  shiftUpdate = true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VectorFIFO* RadioInterface::receiveFIFO(size_t chan)
 | 
					VectorFIFO* RadioInterface::receiveFIFO(size_t chan)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if (chan >= mReceiveFIFO.size())
 | 
					  if (chan >= mReceiveFIFO.size())
 | 
				
			||||||
@@ -330,7 +350,7 @@ void RadioInterface::pullBuffer()
 | 
				
			|||||||
  num_recv = mRadio->readSamples(convertRecvBuffer,
 | 
					  num_recv = mRadio->readSamples(convertRecvBuffer,
 | 
				
			||||||
                                 CHUNK,
 | 
					                                 CHUNK,
 | 
				
			||||||
                                 &overrun,
 | 
					                                 &overrun,
 | 
				
			||||||
                                 readTimestamp,
 | 
					                                 readTimestamp + shiftOffset,
 | 
				
			||||||
                                 &local_underrun);
 | 
					                                 &local_underrun);
 | 
				
			||||||
  if (num_recv != CHUNK) {
 | 
					  if (num_recv != CHUNK) {
 | 
				
			||||||
          LOG(ALERT) << "Receive error " << num_recv;
 | 
					          LOG(ALERT) << "Receive error " << num_recv;
 | 
				
			||||||
@@ -365,11 +385,16 @@ void RadioInterface::pushBuffer()
 | 
				
			|||||||
                        powerScaling[i], 2 * sendCursor);
 | 
					                        powerScaling[i], 2 * sendCursor);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (shiftUpdate) {
 | 
				
			||||||
 | 
					    mRadio->updateAlignment(0);
 | 
				
			||||||
 | 
					    shiftUpdate = false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Send the all samples in the send buffer */ 
 | 
					  /* Send the all samples in the send buffer */ 
 | 
				
			||||||
  num_sent = mRadio->writeSamples(convertSendBuffer,
 | 
					  num_sent = mRadio->writeSamples(convertSendBuffer,
 | 
				
			||||||
                                  sendCursor,
 | 
					                                  sendCursor,
 | 
				
			||||||
                                  &underrun,
 | 
					                                  &underrun,
 | 
				
			||||||
                                  writeTimestamp);
 | 
					                                  writeTimestamp + mSPSTx * shiftOffset);
 | 
				
			||||||
  writeTimestamp += num_sent;
 | 
					  writeTimestamp += num_sent;
 | 
				
			||||||
  sendCursor = 0;
 | 
					  sendCursor = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,7 +56,8 @@ protected:
 | 
				
			|||||||
  RadioClock mClock;                          ///< the basestation clock!
 | 
					  RadioClock mClock;                          ///< the basestation clock!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int receiveOffset;                          ///< offset b/w transmit and receive GSM timestamps, in timeslots
 | 
					  int receiveOffset;                          ///< offset b/w transmit and receive GSM timestamps, in timeslots
 | 
				
			||||||
 | 
					  int shiftOffset;
 | 
				
			||||||
 | 
					  bool shiftUpdate;
 | 
				
			||||||
  bool mOn;				      ///< indicates radio is on
 | 
					  bool mOn;				      ///< indicates radio is on
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
@@ -94,6 +95,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /** check for underrun, resets underrun value */
 | 
					  /** check for underrun, resets underrun value */
 | 
				
			||||||
  bool isUnderrun();
 | 
					  bool isUnderrun();
 | 
				
			||||||
 | 
					  void applyOffset(int offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** return the receive FIFO */
 | 
					  /** return the receive FIFO */
 | 
				
			||||||
  VectorFIFO* receiveFIFO(size_t chan = 0);
 | 
					  VectorFIFO* receiveFIFO(size_t chan = 0);
 | 
				
			||||||
@@ -101,12 +103,18 @@ public:
 | 
				
			|||||||
  /** return the basestation clock */
 | 
					  /** return the basestation clock */
 | 
				
			||||||
  RadioClock* getClock(void) { return &mClock;};
 | 
					  RadioClock* getClock(void) { return &mClock;};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** apply an offset to the main clock */
 | 
				
			||||||
 | 
					  void adjustClock(GSM::Time &offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** set transmit frequency */
 | 
					  /** set transmit frequency */
 | 
				
			||||||
  bool tuneTx(double freq, size_t chan = 0);
 | 
					  bool tuneTx(double freq, size_t chan = 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** set receive frequency */
 | 
					  /** set receive frequency */
 | 
				
			||||||
  virtual bool tuneRx(double freq, size_t chan = 0);
 | 
					  virtual bool tuneRx(double freq, size_t chan = 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** set frequency correction */
 | 
				
			||||||
 | 
					  virtual bool tuneRxOffset(double offset, size_t chan = 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** set receive gain */
 | 
					  /** set receive gain */
 | 
				
			||||||
  double setRxGain(double dB, size_t chan = 0);
 | 
					  double setRxGain(double dB, size_t chan = 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -189,7 +189,7 @@ void RadioInterfaceDiversity::pullBuffer()
 | 
				
			|||||||
	num = mRadio->readSamples(convertRecvBuffer,
 | 
						num = mRadio->readSamples(convertRecvBuffer,
 | 
				
			||||||
				  resamp_outchunk,
 | 
									  resamp_outchunk,
 | 
				
			||||||
				  &overrun,
 | 
									  &overrun,
 | 
				
			||||||
				  readTimestamp,
 | 
									  readTimestamp + shiftOffset,
 | 
				
			||||||
				  &local_underrun);
 | 
									  &local_underrun);
 | 
				
			||||||
	if ((size_t) num != resamp_outchunk) {
 | 
						if ((size_t) num != resamp_outchunk) {
 | 
				
			||||||
		LOG(ALERT) << "Receive error " << num;
 | 
							LOG(ALERT) << "Receive error " << num;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -188,7 +188,7 @@ void RadioInterfaceResamp::pullBuffer()
 | 
				
			|||||||
	num_recv = mRadio->readSamples(convertRecvBuffer,
 | 
						num_recv = mRadio->readSamples(convertRecvBuffer,
 | 
				
			||||||
				       resamp_outchunk,
 | 
									       resamp_outchunk,
 | 
				
			||||||
				       &overrun,
 | 
									       &overrun,
 | 
				
			||||||
				       readTimestamp,
 | 
									       readTimestamp + shiftOffset,
 | 
				
			||||||
				       &local_underrun);
 | 
									       &local_underrun);
 | 
				
			||||||
	if (num_recv != (int) resamp_outchunk) {
 | 
						if (num_recv != (int) resamp_outchunk) {
 | 
				
			||||||
		LOG(ALERT) << "Receive error " << num_recv;
 | 
							LOG(ALERT) << "Receive error " << num_recv;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -74,25 +74,31 @@ bool radioVector::setVector(signalVector *vector, size_t chan)
 | 
				
			|||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
noiseVector::noiseVector(size_t size)
 | 
					avgVector::avgVector(size_t max)
 | 
				
			||||||
	: std::vector<float>(size), itr(0)
 | 
						: std::vector<float>(0), itr(0)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						this->max = max;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
float noiseVector::avg() const
 | 
					float avgVector::avg() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	float val = 0.0;
 | 
						float val = 0.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!size())
 | 
				
			||||||
 | 
							return 0.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (size_t i = 0; i < size(); i++)
 | 
						for (size_t i = 0; i < size(); i++)
 | 
				
			||||||
		val += (*this)[i];
 | 
							val += (*this)[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return val / (float) size();
 | 
						return val / (float) size();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool noiseVector::insert(float val)
 | 
					bool avgVector::insert(float val)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!size())
 | 
						if (size() < max) {
 | 
				
			||||||
		return false;
 | 
							push_back(val);
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (itr >= this->size())
 | 
						if (itr >= this->size())
 | 
				
			||||||
		itr = 0;
 | 
							itr = 0;
 | 
				
			||||||
@@ -102,6 +108,16 @@ bool noiseVector::insert(float val)
 | 
				
			|||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool avgVector::full() const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return size() >= max;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void avgVector::reset()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						resize(0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GSM::Time VectorQueue::nextTime() const
 | 
					GSM::Time VectorQueue::nextTime() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	GSM::Time retVal;
 | 
						GSM::Time retVal;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,14 +46,17 @@ private:
 | 
				
			|||||||
	GSM::Time mTime;
 | 
						GSM::Time mTime;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class noiseVector : std::vector<float> {
 | 
					class avgVector : std::vector<float> {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	noiseVector(size_t size = 0);
 | 
						avgVector(size_t size = 0);
 | 
				
			||||||
	bool insert(float val);
 | 
						bool insert(float val);
 | 
				
			||||||
 | 
						bool full() const;
 | 
				
			||||||
	float avg() const;
 | 
						float avg() const;
 | 
				
			||||||
 | 
						void reset();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	size_t itr;
 | 
						size_t itr;
 | 
				
			||||||
 | 
						size_t max;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class VectorFIFO : public InterthreadQueue<radioVector> { };
 | 
					class VectorFIFO : public InterthreadQueue<radioVector> { };
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										219
									
								
								Transceiver52M/sch.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										219
									
								
								Transceiver52M/sch.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,219 @@
 | 
				
			|||||||
 | 
					#include <complex.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <math.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/bits.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/conv.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/crcgen.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "sch.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* GSM 04.08, 9.1.30 Synchronization channel information */
 | 
				
			||||||
 | 
					struct sch_packed_info {
 | 
				
			||||||
 | 
						ubit_t t1_hi[2];
 | 
				
			||||||
 | 
						ubit_t bsic[6];
 | 
				
			||||||
 | 
						ubit_t t1_md[8];
 | 
				
			||||||
 | 
						ubit_t t3p_hi[2];
 | 
				
			||||||
 | 
						ubit_t t2[5];
 | 
				
			||||||
 | 
						ubit_t t1_lo[1];
 | 
				
			||||||
 | 
						ubit_t t3p_lo[1];
 | 
				
			||||||
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sch_burst {
 | 
				
			||||||
 | 
						sbit_t tail0[3];
 | 
				
			||||||
 | 
						sbit_t data0[39];
 | 
				
			||||||
 | 
						sbit_t etsc[64];
 | 
				
			||||||
 | 
						sbit_t data1[39];
 | 
				
			||||||
 | 
						sbit_t tail1[3];
 | 
				
			||||||
 | 
						sbit_t guard[8];
 | 
				
			||||||
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const uint8_t sch_next_output[][2] = {
 | 
				
			||||||
 | 
						{ 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
 | 
				
			||||||
 | 
						{ 3, 0 }, { 2, 1 }, { 3, 0 }, { 2, 1 },
 | 
				
			||||||
 | 
						{ 3, 0 }, { 2, 1 }, { 3, 0 }, { 2, 1 },
 | 
				
			||||||
 | 
						{ 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const uint8_t sch_next_state[][2] = {
 | 
				
			||||||
 | 
						{  0,  1 }, {  2,  3 }, {  4,  5 }, {  6,  7 },
 | 
				
			||||||
 | 
						{  8,  9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
 | 
				
			||||||
 | 
						{  0,  1 }, {  2,  3 }, {  4,  5 }, {  6,  7 },
 | 
				
			||||||
 | 
						{  8,  9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct osmo_conv_code gsm_conv_sch = {
 | 
				
			||||||
 | 
						.N = 2,
 | 
				
			||||||
 | 
						.K = 5,
 | 
				
			||||||
 | 
						.len = GSM_SCH_UNCODED_LEN,
 | 
				
			||||||
 | 
						.next_output = sch_next_output,
 | 
				
			||||||
 | 
						.next_state  = sch_next_state,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct osmo_crc16gen_code gsm0503_sch_crc10 = {
 | 
				
			||||||
 | 
						.bits = 10,
 | 
				
			||||||
 | 
						.poly = 0x175,
 | 
				
			||||||
 | 
						.init = 0x000,
 | 
				
			||||||
 | 
						.remainder = 0x3ff,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define GSM_MAX_BURST_LEN	157
 | 
				
			||||||
 | 
					#define GSM_SYM_RATE		(1625e3 / 6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Pre-generated FCCH measurement tone */
 | 
				
			||||||
 | 
					static complex float fcch_ref[GSM_MAX_BURST_LEN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int float_to_sbit(const float *in, sbit_t *out, float scale, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < len; i++) {
 | 
				
			||||||
 | 
							out[i] = (in[i] - 0.5f) * scale;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Check if FN contains a SCH burst */
 | 
				
			||||||
 | 
					int gsm_sch_check_fn(int fn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int fn51 = fn % 51;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (fn51) {
 | 
				
			||||||
 | 
						case 1:
 | 
				
			||||||
 | 
						case 11:
 | 
				
			||||||
 | 
						case 21:
 | 
				
			||||||
 | 
						case 31:
 | 
				
			||||||
 | 
						case 41:
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* SCH (T1, T2, T3p) to full FN value */
 | 
				
			||||||
 | 
					int gsm_sch_to_fn(struct sch_info *sch)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int t1 = sch->t1;
 | 
				
			||||||
 | 
						int t2 = sch->t2;
 | 
				
			||||||
 | 
						int t3p = sch->t3p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((t1 < 0) || (t2 < 0) || (t3p < 0))
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						int tt;
 | 
				
			||||||
 | 
						int t3 = t3p * 10 + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (t3 < t2)
 | 
				
			||||||
 | 
							tt = (t3 + 26) - t2;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							tt = (t3 - t2) % 26;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return t1 * 51 * 26 + tt * 51 + t3;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Parse encoded SCH message */
 | 
				
			||||||
 | 
					int gsm_sch_parse(const uint8_t *info, struct sch_info *desc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct sch_packed_info *p = (struct sch_packed_info *) info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						desc->bsic = (p->bsic[0] << 0) | (p->bsic[1] << 1) |
 | 
				
			||||||
 | 
							     (p->bsic[2] << 2) | (p->bsic[3] << 3) |
 | 
				
			||||||
 | 
							     (p->bsic[4] << 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						desc->t1 = (p->t1_lo[0] << 0) | (p->t1_md[0] << 1) |
 | 
				
			||||||
 | 
							   (p->t1_md[1] << 2) | (p->t1_md[2] << 3) |
 | 
				
			||||||
 | 
							   (p->t1_md[3] << 4) | (p->t1_md[4] << 5) |
 | 
				
			||||||
 | 
							   (p->t1_md[5] << 6) | (p->t1_md[6] << 7) |
 | 
				
			||||||
 | 
							   (p->t1_md[7] << 8) | (p->t1_hi[0] << 9) |
 | 
				
			||||||
 | 
							   (p->t1_hi[1] << 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						desc->t2 = (p->t2[0] << 0) | (p->t2[1] << 1) |
 | 
				
			||||||
 | 
							   (p->t2[2] << 2) | (p->t2[3] << 3) |
 | 
				
			||||||
 | 
							   (p->t2[4] << 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						desc->t3p = (p->t3p_lo[0] << 0) | (p->t3p_hi[0] << 1) |
 | 
				
			||||||
 | 
							    (p->t3p_hi[1] << 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* From osmo-bts */
 | 
				
			||||||
 | 
					int gsm_sch_decode(uint8_t *info, sbit_t *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						ubit_t uncoded[GSM_SCH_UNCODED_LEN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_conv_decode(&gsm_conv_sch, data, uncoded);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = osmo_crc16gen_check_bits(&gsm0503_sch_crc10,
 | 
				
			||||||
 | 
									      uncoded, GSM_SCH_INFO_LEN,
 | 
				
			||||||
 | 
									      uncoded + GSM_SCH_INFO_LEN);
 | 
				
			||||||
 | 
						if (rc)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(info, uncoded, GSM_SCH_INFO_LEN * sizeof(ubit_t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define FCCH_TAIL_BITS_LEN	3
 | 
				
			||||||
 | 
					#define FCCH_DATA_LEN		142
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Compute FCCH frequency offset */
 | 
				
			||||||
 | 
					double gsm_fcch_offset(float *burst, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i, start, end;
 | 
				
			||||||
 | 
						float a, b, c, d, ang, avg = 0.0f;
 | 
				
			||||||
 | 
						double freq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (len > GSM_MAX_BURST_LEN)
 | 
				
			||||||
 | 
							len = GSM_MAX_BURST_LEN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < len; i++) {
 | 
				
			||||||
 | 
							a = burst[2 * i + 0];
 | 
				
			||||||
 | 
							b = burst[2 * i + 1];
 | 
				
			||||||
 | 
							c = crealf(fcch_ref[i]);
 | 
				
			||||||
 | 
							d = cimagf(fcch_ref[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							burst[2 * i + 0] = a * c - b * d;
 | 
				
			||||||
 | 
							burst[2 * i + 1] = a * d + b * c;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						start = FCCH_TAIL_BITS_LEN;
 | 
				
			||||||
 | 
						end = start + FCCH_DATA_LEN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = start; i < end; i++) {
 | 
				
			||||||
 | 
							a = cargf(burst[2 * (i - 1) + 0] +
 | 
				
			||||||
 | 
								  burst[2 * (i - 1) + 1] * I);
 | 
				
			||||||
 | 
							b = cargf(burst[2 * i + 0] +
 | 
				
			||||||
 | 
								  burst[2 * i + 1] * I);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ang = b - a;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ang > M_PI)
 | 
				
			||||||
 | 
								ang -= 2 * M_PI;
 | 
				
			||||||
 | 
							else if (ang < -M_PI)
 | 
				
			||||||
 | 
								ang += 2 * M_PI;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							avg += ang;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						avg /= (float) (end - start);
 | 
				
			||||||
 | 
						freq = avg / (2 * M_PI) * GSM_SYM_RATE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return freq;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Generate FCCH measurement tone */
 | 
				
			||||||
 | 
					static __attribute__((constructor)) void init()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						double freq = 0.25;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < GSM_MAX_BURST_LEN; i++) {
 | 
				
			||||||
 | 
							fcch_ref[i] = sin(2 * M_PI * freq * (double) i) +
 | 
				
			||||||
 | 
								      cos(2 * M_PI * freq * (double) i) * I;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										26
									
								
								Transceiver52M/sch.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								Transceiver52M/sch.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					#ifndef _SCH_H_
 | 
				
			||||||
 | 
					#define _SCH_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/bits.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sch_info  {
 | 
				
			||||||
 | 
						int bsic;
 | 
				
			||||||
 | 
						int t1;
 | 
				
			||||||
 | 
						int t2;
 | 
				
			||||||
 | 
						int t3p;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define GSM_SCH_INFO_LEN		25
 | 
				
			||||||
 | 
					#define GSM_SCH_UNCODED_LEN		35
 | 
				
			||||||
 | 
					#define GSM_SCH_CODED_LEN		78
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int gsm_sch_decode(uint8_t *sb_info, sbit_t *burst);
 | 
				
			||||||
 | 
					int gsm_sch_parse(const uint8_t *sb_info, struct sch_info *desc);
 | 
				
			||||||
 | 
					int gsm_sch_to_fn(struct sch_info *sch);
 | 
				
			||||||
 | 
					int gsm_sch_check_fn(int fn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					double gsm_fcch_offset(float *burst, int len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int float_to_sbit(const float *in, sbit_t *out, float scale, int len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* _SCH_H_ */
 | 
				
			||||||
@@ -34,8 +34,6 @@ extern "C" {
 | 
				
			|||||||
#include "scale.h"
 | 
					#include "scale.h"
 | 
				
			||||||
#include "mult.h"
 | 
					#include "mult.h"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
/* Clipping detection threshold */
 | 
					 | 
				
			||||||
#define CLIP_THRESH     30000.0f
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace GSM;
 | 
					using namespace GSM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -80,6 +78,7 @@ struct CorrelationSequence {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  signalVector *sequence;
 | 
					  signalVector *sequence;
 | 
				
			||||||
  void         *buffer;
 | 
					  void         *buffer;
 | 
				
			||||||
 | 
					  void         *history;
 | 
				
			||||||
  float        toa;
 | 
					  float        toa;
 | 
				
			||||||
  complex      gain;
 | 
					  complex      gain;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -113,6 +112,7 @@ struct PulseSequence {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
 | 
					CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
 | 
				
			||||||
CorrelationSequence *gRACHSequence = NULL;
 | 
					CorrelationSequence *gRACHSequence = NULL;
 | 
				
			||||||
 | 
					CorrelationSequence *gSCHSequence = NULL;
 | 
				
			||||||
PulseSequence *GSMPulse = NULL;
 | 
					PulseSequence *GSMPulse = NULL;
 | 
				
			||||||
PulseSequence *GSMPulse1 = NULL;
 | 
					PulseSequence *GSMPulse1 = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -133,6 +133,7 @@ void sigProcLibDestroy()
 | 
				
			|||||||
  delete GMSKRotation1;
 | 
					  delete GMSKRotation1;
 | 
				
			||||||
  delete GMSKReverseRotation1;
 | 
					  delete GMSKReverseRotation1;
 | 
				
			||||||
  delete gRACHSequence;
 | 
					  delete gRACHSequence;
 | 
				
			||||||
 | 
					  delete gSCHSequence;
 | 
				
			||||||
  delete GSMPulse;
 | 
					  delete GSMPulse;
 | 
				
			||||||
  delete GSMPulse1;
 | 
					  delete GSMPulse1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -141,6 +142,7 @@ void sigProcLibDestroy()
 | 
				
			|||||||
  GMSKReverseRotationN = NULL;
 | 
					  GMSKReverseRotationN = NULL;
 | 
				
			||||||
  GMSKReverseRotation1 = NULL;
 | 
					  GMSKReverseRotation1 = NULL;
 | 
				
			||||||
  gRACHSequence = NULL;
 | 
					  gRACHSequence = NULL;
 | 
				
			||||||
 | 
					  gSCHSequence = NULL;
 | 
				
			||||||
  GSMPulse = NULL;
 | 
					  GSMPulse = NULL;
 | 
				
			||||||
  GSMPulse1 = NULL;
 | 
					  GSMPulse1 = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -397,8 +399,10 @@ signalVector *convolve(const signalVector *x,
 | 
				
			|||||||
    break;
 | 
					    break;
 | 
				
			||||||
  case CUSTOM:
 | 
					  case CUSTOM:
 | 
				
			||||||
    if (start < h->size() - 1) {
 | 
					    if (start < h->size() - 1) {
 | 
				
			||||||
      head = h->size() - start;
 | 
					      if (x->getStart() < h->size() - 1) {
 | 
				
			||||||
      append = true;
 | 
					        head = h->size() - start;
 | 
				
			||||||
 | 
					        append = true;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (start + len > x->size()) {
 | 
					    if (start + len > x->size()) {
 | 
				
			||||||
      tail = start + len - x->size();
 | 
					      tail = start + len - x->size();
 | 
				
			||||||
@@ -1276,6 +1280,69 @@ release:
 | 
				
			|||||||
  return status;
 | 
					  return status;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool generateSCHSequence(int sps)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  bool status = true;
 | 
				
			||||||
 | 
					  float toa;
 | 
				
			||||||
 | 
					  complex *data = NULL;
 | 
				
			||||||
 | 
					  signalVector *autocorr = NULL;
 | 
				
			||||||
 | 
					  signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  delete gSCHSequence;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  seq0 = modulateBurst(gSCHSynchSequence, 0, sps, false);
 | 
				
			||||||
 | 
					  if (!seq0)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  seq1 = modulateBurst(gSCHSynchSequence, 0, sps, true);
 | 
				
			||||||
 | 
					  if (!seq1) {
 | 
				
			||||||
 | 
					    status = false;
 | 
				
			||||||
 | 
					    goto release;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  conjugateVector(*seq1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
 | 
				
			||||||
 | 
					  data = (complex *) convolve_h_alloc(seq1->size());
 | 
				
			||||||
 | 
					  _seq1 = new signalVector(data, 0, seq1->size());
 | 
				
			||||||
 | 
					  _seq1->setAligned(true);
 | 
				
			||||||
 | 
					  memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
 | 
				
			||||||
 | 
					  if (!autocorr) {
 | 
				
			||||||
 | 
					    status = false;
 | 
				
			||||||
 | 
					    goto release;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  gSCHSequence = new CorrelationSequence;
 | 
				
			||||||
 | 
					  gSCHSequence->sequence = _seq1;
 | 
				
			||||||
 | 
					  gSCHSequence->buffer = data;
 | 
				
			||||||
 | 
					  gSCHSequence->gain = peakDetect(*autocorr, &toa, NULL);
 | 
				
			||||||
 | 
					  gSCHSequence->history = new complex[_seq1->size()];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* For 1 sps only
 | 
				
			||||||
 | 
					   *     (Half of correlation length - 1) + midpoint of pulse shaping filer
 | 
				
			||||||
 | 
					   *     20.5 = (64 / 2 - 1) + 1.5
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  if (sps == 1)
 | 
				
			||||||
 | 
					    gSCHSequence->toa = toa - 32.5;
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    gSCHSequence->toa = 0.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					release:
 | 
				
			||||||
 | 
					  delete autocorr;
 | 
				
			||||||
 | 
					  delete seq0;
 | 
				
			||||||
 | 
					  delete seq1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!status) {
 | 
				
			||||||
 | 
					    delete _seq1;
 | 
				
			||||||
 | 
					    free(data);
 | 
				
			||||||
 | 
					    gSCHSequence = NULL;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return status;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static float computePeakRatio(signalVector *corr,
 | 
					static float computePeakRatio(signalVector *corr,
 | 
				
			||||||
                              int sps, float toa, complex amp)
 | 
					                              int sps, float toa, complex amp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -1342,7 +1409,7 @@ static int detectBurst(signalVector &burst,
 | 
				
			|||||||
  /* Correlate */
 | 
					  /* Correlate */
 | 
				
			||||||
  if (!convolve(&burst, sync->sequence, &corr,
 | 
					  if (!convolve(&burst, sync->sequence, &corr,
 | 
				
			||||||
                CUSTOM, start, len, sps, 0)) {
 | 
					                CUSTOM, start, len, sps, 0)) {
 | 
				
			||||||
    return -SIGERR_INTERNAL;
 | 
					    return -1;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Peak detection - place restrictions at correlation edges */
 | 
					  /* Peak detection - place restrictions at correlation edges */
 | 
				
			||||||
@@ -1371,18 +1438,6 @@ static int detectBurst(signalVector &burst,
 | 
				
			|||||||
  return 1;
 | 
					  return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int detectClipping(signalVector &burst, float thresh)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	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;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* 
 | 
					/* 
 | 
				
			||||||
 * RACH burst detection
 | 
					 * RACH burst detection
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -1404,10 +1459,7 @@ int detectRACHBurst(signalVector &rxBurst,
 | 
				
			|||||||
  CorrelationSequence *sync;
 | 
					  CorrelationSequence *sync;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if ((sps != 1) && (sps != 4))
 | 
					  if ((sps != 1) && (sps != 4))
 | 
				
			||||||
    return -SIGERR_UNSUPPORTED;
 | 
					    return -1;
 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (detectClipping(rxBurst, CLIP_THRESH))
 | 
					 | 
				
			||||||
    return -SIGERR_CLIP;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  target = 8 + 40;
 | 
					  target = 8 + 40;
 | 
				
			||||||
  head = 4;
 | 
					  head = 4;
 | 
				
			||||||
@@ -1441,6 +1493,71 @@ int detectRACHBurst(signalVector &rxBurst,
 | 
				
			|||||||
  return 1;
 | 
					  return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int detectSCHBurst(signalVector &burst,
 | 
				
			||||||
 | 
							    float thresh,
 | 
				
			||||||
 | 
							    int sps,
 | 
				
			||||||
 | 
							    complex *amp,
 | 
				
			||||||
 | 
							    float *toa, int state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  int rc, start, target, head, tail, len;
 | 
				
			||||||
 | 
					  float _toa;
 | 
				
			||||||
 | 
					  complex _amp;
 | 
				
			||||||
 | 
					  signalVector *corr, *_burst;
 | 
				
			||||||
 | 
					  CorrelationSequence *sync;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if ((sps != 1) && (sps != 4))
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  target = 3 + 39 + 64;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  switch (state) {
 | 
				
			||||||
 | 
					  case SCH_DETECT_NARROW:
 | 
				
			||||||
 | 
					    head = 4;
 | 
				
			||||||
 | 
					    tail = 4;
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  case SCH_DETECT_FULL:
 | 
				
			||||||
 | 
					  default:
 | 
				
			||||||
 | 
					    head = target - 1;
 | 
				
			||||||
 | 
					    tail = 39 + 3 + 9;
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  start = (target - head) * sps - 1;
 | 
				
			||||||
 | 
					  len = (head + tail) * sps;
 | 
				
			||||||
 | 
					  sync = gSCHSequence;
 | 
				
			||||||
 | 
					  corr = new signalVector(len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _burst = new signalVector(burst, sync->sequence->size(), 5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  memcpy(_burst->begin() - sync->sequence->size(), sync->history,
 | 
				
			||||||
 | 
					         sync->sequence->size() * sizeof(complex));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  memcpy(sync->history, &burst.begin()[burst.size() - sync->sequence->size()],
 | 
				
			||||||
 | 
					         sync->sequence->size() * sizeof(complex));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  rc = detectBurst(*_burst, *corr, sync,
 | 
				
			||||||
 | 
					                   thresh, sps, &_amp, &_toa, start, len);
 | 
				
			||||||
 | 
					  delete corr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (rc < 0) {
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  } 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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 
 | 
					/* 
 | 
				
			||||||
 * Normal burst detection
 | 
					 * Normal burst detection
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -1460,7 +1577,7 @@ int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
 | 
				
			|||||||
  CorrelationSequence *sync;
 | 
					  CorrelationSequence *sync;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if ((tsc < 0) || (tsc > 7) || ((sps != 1) && (sps != 4)))
 | 
					  if ((tsc < 0) || (tsc > 7) || ((sps != 1) && (sps != 4)))
 | 
				
			||||||
    return -SIGERR_UNSUPPORTED;
 | 
					    return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  target = 3 + 58 + 16 + 5;
 | 
					  target = 3 + 58 + 16 + 5;
 | 
				
			||||||
  head = 4;
 | 
					  head = 4;
 | 
				
			||||||
@@ -1476,7 +1593,7 @@ int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
 | 
				
			|||||||
  delete corr;
 | 
					  delete corr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (rc < 0) {
 | 
					  if (rc < 0) {
 | 
				
			||||||
    return -SIGERR_INTERNAL;
 | 
					    return -1;
 | 
				
			||||||
  } else if (!rc) {
 | 
					  } else if (!rc) {
 | 
				
			||||||
    if (amp)
 | 
					    if (amp)
 | 
				
			||||||
      *amp = 0.0f;
 | 
					      *amp = 0.0f;
 | 
				
			||||||
@@ -1734,6 +1851,11 @@ bool sigProcLibSetup(int sps)
 | 
				
			|||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!generateSCHSequence(1)) {
 | 
				
			||||||
 | 
					    sigProcLibDestroy();
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  generateDelayFilters();
 | 
					  generateDelayFilters();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,14 +28,6 @@ enum ConvType {
 | 
				
			|||||||
  UNDEFINED,
 | 
					  UNDEFINED,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum signalError {
 | 
					 | 
				
			||||||
  SIGERR_NONE,
 | 
					 | 
				
			||||||
  SIGERR_BOUNDS,
 | 
					 | 
				
			||||||
  SIGERR_CLIP,
 | 
					 | 
				
			||||||
  SIGERR_UNSUPPORTED,
 | 
					 | 
				
			||||||
  SIGERR_INTERNAL,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** Convert a linear number to a dB value */
 | 
					/** Convert a linear number to a dB value */
 | 
				
			||||||
float dB(float x);
 | 
					float dB(float x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -166,6 +158,7 @@ bool generateMidamble(int sps, int tsc);
 | 
				
			|||||||
        @return Success.
 | 
					        @return Success.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
bool generateRACHSequence(int sps);
 | 
					bool generateRACHSequence(int sps);
 | 
				
			||||||
 | 
					bool generateSCHSequence(int sps);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
        Energy detector, checks to see if received burst energy is above a threshold.
 | 
					        Energy detector, checks to see if received burst energy is above a threshold.
 | 
				
			||||||
@@ -195,6 +188,17 @@ int detectRACHBurst(signalVector &rxBurst,
 | 
				
			|||||||
                    complex *amplitude,
 | 
					                    complex *amplitude,
 | 
				
			||||||
                    float* TOA);
 | 
					                    float* TOA);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						SCH_DETECT_FULL,
 | 
				
			||||||
 | 
						SCH_DETECT_NARROW,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int detectSCHBurst(signalVector &rxBurst,
 | 
				
			||||||
 | 
					                    float detectThreshold,
 | 
				
			||||||
 | 
					                    int sps,
 | 
				
			||||||
 | 
					                    complex *amplitude,
 | 
				
			||||||
 | 
					                    float* TOA, int state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
        Normal burst correlator, detector, channel estimator.
 | 
					        Normal burst correlator, detector, channel estimator.
 | 
				
			||||||
        @param rxBurst The received GSM burst of interest.
 | 
					        @param rxBurst The received GSM burst of interest.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,6 +58,9 @@ AC_TYPE_SIZE_T
 | 
				
			|||||||
AC_HEADER_TIME
 | 
					AC_HEADER_TIME
 | 
				
			||||||
AC_C_BIGENDIAN
 | 
					AC_C_BIGENDIAN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dnl checks for libraries
 | 
				
			||||||
 | 
					PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore  >= 0.3.9)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AC_ARG_WITH(usrp1, [
 | 
					AC_ARG_WITH(usrp1, [
 | 
				
			||||||
    AS_HELP_STRING([--with-usrp1],
 | 
					    AS_HELP_STRING([--with-usrp1],
 | 
				
			||||||
        [enable USRP1 gnuradio based transceiver])
 | 
					        [enable USRP1 gnuradio based transceiver])
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										5
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@@ -1,5 +0,0 @@
 | 
				
			|||||||
osmo-trx (0.1.8) precise; urgency=low
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     * Initial release (Closes: #nnnn) <nnnn is the bug number of your ITP
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 -- Ivan Klyuchnikov <Ivan.Kluchnikov@fairwaves.ru>  Sun, 9 Mar 2014 14:10:10 +0400
 | 
					 | 
				
			||||||
							
								
								
									
										1
									
								
								debian/compat
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								debian/compat
									
									
									
									
										vendored
									
									
								
							@@ -1 +0,0 @@
 | 
				
			|||||||
9
 | 
					 | 
				
			||||||
							
								
								
									
										24
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@@ -1,24 +0,0 @@
 | 
				
			|||||||
Source: osmo-trx
 | 
					 | 
				
			||||||
Maintainer: Ivan Klyuchnikov <ivan.kluchnikov@fairwaves.ru>
 | 
					 | 
				
			||||||
Section: net
 | 
					 | 
				
			||||||
Priority: optional
 | 
					 | 
				
			||||||
Standards-Version: 3.9.3
 | 
					 | 
				
			||||||
Build-Depends: debhelper (>= 9), autotools-dev, libdbd-sqlite3, pkg-config, dh-autoreconf, uhd, umtrx-uhd, libusb-1.0-0-dev, libboost-all-dev
 | 
					 | 
				
			||||||
Homepage: http://openbsc.osmocom.org/trac/wiki/OsmoTRX
 | 
					 | 
				
			||||||
Vcs-Git: git://git.osmocom.org/osmo-trx
 | 
					 | 
				
			||||||
Vcs-Browser: http://cgit.osmocom.org/osmo-trx
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Package: osmo-trx
 | 
					 | 
				
			||||||
Architecture: any
 | 
					 | 
				
			||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libdbd-sqlite3
 | 
					 | 
				
			||||||
Description: OsmoTRX is a software-defined radio transceiver that implements the Layer 1 physical layer of a BTS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Package: osmo-trx-dbg
 | 
					 | 
				
			||||||
Architecture: any
 | 
					 | 
				
			||||||
Section: debug
 | 
					 | 
				
			||||||
Priority: extra
 | 
					 | 
				
			||||||
Depends: osmo-trx (= ${binary:Version}), ${misc:Depends}
 | 
					 | 
				
			||||||
Description: Debug symbols for the osmo-trx
 | 
					 | 
				
			||||||
 Make debugging possible
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
							
								
								
									
										25
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
								
							@@ -1,25 +0,0 @@
 | 
				
			|||||||
The Debian packaging is:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Copyright (C) 2014 Max <max.suraev@fairwaves.ru>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
It was downloaded from:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    git://git.osmocom.org/osmo-trx
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Upstream Authors:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Thomas Tsou <tom@tsou.cc>
 | 
					 | 
				
			||||||
    David A. Burgess <dburgess@kestrelsp.com>
 | 
					 | 
				
			||||||
    Harvind S. Samra <hssamra@kestrelsp.com>
 | 
					 | 
				
			||||||
    Raffi Sevlian <raffisev@gmail.com>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Copyright:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     Copyright (C) 2012-2013 Thomas Tsou <tom@tsou.cc>
 | 
					 | 
				
			||||||
     Copyright (C) 2011 Range Networks, Inc.
 | 
					 | 
				
			||||||
     Copyright (C) 2008-2011 Free Software Foundation, Inc.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
License:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    GNU Affero General Public License, Version 3
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
							
								
								
									
										1
									
								
								debian/osmo-trx.install
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								debian/osmo-trx.install
									
									
									
									
										vendored
									
									
								
							@@ -1 +0,0 @@
 | 
				
			|||||||
/usr/bin/osmo-trx
 | 
					 | 
				
			||||||
							
								
								
									
										13
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							@@ -1,13 +0,0 @@
 | 
				
			|||||||
#!/usr/bin/make -f
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export DEB_BUILD_HARDENING=1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%:
 | 
					 | 
				
			||||||
	dh $@ --with autoreconf
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
override_dh_shlibdeps:
 | 
					 | 
				
			||||||
    dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
override_dh_strip:
 | 
					 | 
				
			||||||
    dh_strip --dbg-package=osmo-trx-dbg
 | 
					 | 
				
			||||||
							
								
								
									
										1
									
								
								debian/source/format
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								debian/source/format
									
									
									
									
										vendored
									
									
								
							@@ -1 +0,0 @@
 | 
				
			|||||||
3.0 (native)
 | 
					 | 
				
			||||||
		Reference in New Issue
	
	Block a user