mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-trx.git
				synced 2025-11-04 06:03:17 +00:00 
			
		
		
		
	Compare commits
	
		
			7 Commits
		
	
	
		
			0.4.0
			...
			fairwaves/
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					2061843c3d | ||
| 
						 | 
					63d0f2a496 | ||
| 
						 | 
					6459ddc55c | ||
| 
						 | 
					7a33c7221b | ||
| 
						 | 
					dd62d4baa0 | ||
| 
						 | 
					09130c81a7 | ||
| 
						 | 
					0c4e24d197 | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -3,6 +3,8 @@
 | 
				
			|||||||
*.lo
 | 
					*.lo
 | 
				
			||||||
*.la
 | 
					*.la
 | 
				
			||||||
Transceiver52M/osmo-trx
 | 
					Transceiver52M/osmo-trx
 | 
				
			||||||
 | 
					Transceiver52M/osmo-trx-gen
 | 
				
			||||||
 | 
					Transceiver52M/osmo-trx-dec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# tests
 | 
					# tests
 | 
				
			||||||
CommonLibs/BitVectorTest
 | 
					CommonLibs/BitVectorTest
 | 
				
			||||||
@@ -15,6 +17,7 @@ CommonLibs/SocketsTest
 | 
				
			|||||||
CommonLibs/TimevalTest
 | 
					CommonLibs/TimevalTest
 | 
				
			||||||
CommonLibs/URLEncodeTest
 | 
					CommonLibs/URLEncodeTest
 | 
				
			||||||
CommonLibs/VectorTest
 | 
					CommonLibs/VectorTest
 | 
				
			||||||
 | 
					CommonLibs/PRBSTest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# automake/autoconf
 | 
					# automake/autoconf
 | 
				
			||||||
*.in
 | 
					*.in
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,6 +42,7 @@ libcommon_la_SOURCES = \
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
noinst_PROGRAMS = \
 | 
					noinst_PROGRAMS = \
 | 
				
			||||||
	BitVectorTest \
 | 
						BitVectorTest \
 | 
				
			||||||
 | 
						PRBSTest \
 | 
				
			||||||
	InterthreadTest \
 | 
						InterthreadTest \
 | 
				
			||||||
	SocketsTest \
 | 
						SocketsTest \
 | 
				
			||||||
	TimevalTest \
 | 
						TimevalTest \
 | 
				
			||||||
@@ -53,6 +54,7 @@ noinst_PROGRAMS = \
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
noinst_HEADERS = \
 | 
					noinst_HEADERS = \
 | 
				
			||||||
	BitVector.h \
 | 
						BitVector.h \
 | 
				
			||||||
 | 
						PRBS.h \
 | 
				
			||||||
	Interthread.h \
 | 
						Interthread.h \
 | 
				
			||||||
	LinkedLists.h \
 | 
						LinkedLists.h \
 | 
				
			||||||
	Sockets.h \
 | 
						Sockets.h \
 | 
				
			||||||
@@ -66,6 +68,8 @@ noinst_HEADERS = \
 | 
				
			|||||||
BitVectorTest_SOURCES = BitVectorTest.cpp
 | 
					BitVectorTest_SOURCES = BitVectorTest.cpp
 | 
				
			||||||
BitVectorTest_LDADD = libcommon.la $(SQLITE3_LIBS)
 | 
					BitVectorTest_LDADD = libcommon.la $(SQLITE3_LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PRBSTest_SOURCES = PRBSTest.cpp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
InterthreadTest_SOURCES = InterthreadTest.cpp
 | 
					InterthreadTest_SOURCES = InterthreadTest.cpp
 | 
				
			||||||
InterthreadTest_LDADD = libcommon.la
 | 
					InterthreadTest_LDADD = libcommon.la
 | 
				
			||||||
InterthreadTest_LDFLAGS = -lpthread
 | 
					InterthreadTest_LDFLAGS = -lpthread
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										110
									
								
								CommonLibs/PRBS.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								CommonLibs/PRBS.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2017 Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					 * modify it under the terms of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License as published by the Free Software Foundation; either
 | 
				
			||||||
 | 
					 * version 2.1 of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * Lesser General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License along with this library; if not, write to the Free Software
 | 
				
			||||||
 | 
					 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef PRBS_H
 | 
				
			||||||
 | 
					#define PRBS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Pseudo-random binary sequence (PRBS) generator (a Galois LFSR implementation). */
 | 
				
			||||||
 | 
					class PRBS {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PRBS(unsigned wLen, uint64_t wCoeff, uint64_t wState = 0x01)
 | 
				
			||||||
 | 
					    : mCoeff(wCoeff), mStartState(wState), mState(wState), mLen(wLen)
 | 
				
			||||||
 | 
					  { assert(wLen<=64); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**@name Accessors */
 | 
				
			||||||
 | 
					  //@{
 | 
				
			||||||
 | 
					  uint64_t coeff() const { return mCoeff; }
 | 
				
			||||||
 | 
					  uint64_t state() const { return mState; }
 | 
				
			||||||
 | 
					  void state(uint64_t state) { mState = state & mask(); }
 | 
				
			||||||
 | 
					  unsigned size() const { return mLen; }
 | 
				
			||||||
 | 
					  //@}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					    Calculate one bit of a PRBS
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					  unsigned generateBit()
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    const unsigned result = mState & 0x01;
 | 
				
			||||||
 | 
					    processBit(result);
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					    Update the generator state by one bit.
 | 
				
			||||||
 | 
					    If you want to synchronize your PRBS to a known state, call this function
 | 
				
			||||||
 | 
					    size() times passing your PRBS to it bit by bit.
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					  void processBit(unsigned inBit)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    mState >>= 1;
 | 
				
			||||||
 | 
					    if (inBit) mState ^= mCoeff;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Return true when PRBS is wrapping through initial state */
 | 
				
			||||||
 | 
					  bool isFinished() const { return mStartState == mState; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint64_t mCoeff;      ///< polynomial coefficients. LSB is zero exponent.
 | 
				
			||||||
 | 
					  uint64_t mStartState; ///< initial shift register state.
 | 
				
			||||||
 | 
					  uint64_t mState;      ///< shift register state.
 | 
				
			||||||
 | 
					  unsigned mLen;        ///< number of bits used in shift register
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Return mask for the state register */
 | 
				
			||||||
 | 
					  uint64_t mask() const { return (mLen==64)?0xFFFFFFFFFFFFFFFFUL:((1<<mLen)-1); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  A standard 9-bit based pseudorandom binary sequence (PRBS) generator.
 | 
				
			||||||
 | 
					  Polynomial: x^9 + x^5 + 1
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					class PRBS9 : public PRBS {
 | 
				
			||||||
 | 
					  public:
 | 
				
			||||||
 | 
					  PRBS9(uint64_t wState = 0x01)
 | 
				
			||||||
 | 
					  : PRBS(9, 0x0110, wState)
 | 
				
			||||||
 | 
					  {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  A standard 15-bit based pseudorandom binary sequence (PRBS) generator.
 | 
				
			||||||
 | 
					  Polynomial: x^15 + x^14 + 1
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					class PRBS15 : public PRBS {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					  PRBS15(uint64_t wState = 0x01)
 | 
				
			||||||
 | 
					  : PRBS(15, 0x6000, wState)
 | 
				
			||||||
 | 
					  {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  A standard 64-bit based pseudorandom binary sequence (PRBS) generator.
 | 
				
			||||||
 | 
					  Polynomial: x^64 + x^63 + x^61 + x^60 + 1
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					class PRBS64 : public PRBS {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					  PRBS64(uint64_t wState = 0x01)
 | 
				
			||||||
 | 
					  : PRBS(64, 0xD800000000000000ULL, wState)
 | 
				
			||||||
 | 
					  {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // PRBS_H
 | 
				
			||||||
							
								
								
									
										42
									
								
								CommonLibs/PRBSTest.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								CommonLibs/PRBSTest.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2017 Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					 * modify it under the terms of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License as published by the Free Software Foundation; either
 | 
				
			||||||
 | 
					 * version 2.1 of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * Lesser General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License along with this library; if not, write to the Free Software
 | 
				
			||||||
 | 
					 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "PRBS.h"
 | 
				
			||||||
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <cstdlib>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void testPrbs(PRBS &prbs, uint64_t expectedPeriod)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  uint64_t period = 0;
 | 
				
			||||||
 | 
					  do {
 | 
				
			||||||
 | 
					    std::cout << prbs.generateBit();
 | 
				
			||||||
 | 
					    period++;
 | 
				
			||||||
 | 
					  } while (!prbs.isFinished());
 | 
				
			||||||
 | 
					  std::cout << std::endl;
 | 
				
			||||||
 | 
					  std::cout << "Period: " << period << std::endl;
 | 
				
			||||||
 | 
					  assert(period == expectedPeriod);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  PRBS9 prbs9(0x01);
 | 
				
			||||||
 | 
					  testPrbs(prbs9, (1<<9)-1);
 | 
				
			||||||
 | 
					  PRBS15 prbs15(0x01);
 | 
				
			||||||
 | 
					  testPrbs(prbs15, (1<<15)-1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -69,7 +69,10 @@ libtransceiver_la_SOURCES = \
 | 
				
			|||||||
	radioInterfaceResamp.cpp \
 | 
						radioInterfaceResamp.cpp \
 | 
				
			||||||
	radioInterfaceMulti.cpp
 | 
						radioInterfaceMulti.cpp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bin_PROGRAMS = osmo-trx
 | 
					bin_PROGRAMS = \
 | 
				
			||||||
 | 
						osmo-trx \
 | 
				
			||||||
 | 
						osmo-trx-gen \
 | 
				
			||||||
 | 
						osmo-trx-dec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
noinst_HEADERS = \
 | 
					noinst_HEADERS = \
 | 
				
			||||||
	Complex.h \
 | 
						Complex.h \
 | 
				
			||||||
@@ -99,6 +102,20 @@ osmo_trx_LDADD = \
 | 
				
			|||||||
	$(GSM_LA) \
 | 
						$(GSM_LA) \
 | 
				
			||||||
	$(COMMON_LA) $(SQLITE3_LIBS)
 | 
						$(COMMON_LA) $(SQLITE3_LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo_trx_gen_SOURCES = osmo-trx-gen.cpp
 | 
				
			||||||
 | 
					osmo_trx_gen_LDADD = \
 | 
				
			||||||
 | 
						libtransceiver.la \
 | 
				
			||||||
 | 
						$(ARCH_LA) \
 | 
				
			||||||
 | 
						$(GSM_LA) \
 | 
				
			||||||
 | 
						$(COMMON_LA) $(SQLITE_LA)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo_trx_dec_SOURCES = osmo-trx-dec.cpp
 | 
				
			||||||
 | 
					osmo_trx_dec_LDADD = \
 | 
				
			||||||
 | 
						libtransceiver.la \
 | 
				
			||||||
 | 
						$(ARCH_LA) \
 | 
				
			||||||
 | 
						$(GSM_LA) \
 | 
				
			||||||
 | 
						$(COMMON_LA) $(SQLITE_LA)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if USRP1 
 | 
					if USRP1 
 | 
				
			||||||
libtransceiver_la_SOURCES += USRPDevice.cpp
 | 
					libtransceiver_la_SOURCES += USRPDevice.cpp
 | 
				
			||||||
osmo_trx_LDADD += $(USRP_LIBS)
 | 
					osmo_trx_LDADD += $(USRP_LIBS)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -85,7 +85,7 @@ bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc, un
 | 
				
			|||||||
        burst = generateDummyBurst(sps, n);
 | 
					        burst = generateDummyBurst(sps, n);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      case Transceiver::FILLER_NORM_RAND:
 | 
					      case Transceiver::FILLER_NORM_RAND:
 | 
				
			||||||
        burst = genRandNormalBurst(rtsc, sps, n);
 | 
					        burst = genRandNormalBurst(rtsc, sps, n, mPrbs);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      case Transceiver::FILLER_EDGE_RAND:
 | 
					      case Transceiver::FILLER_EDGE_RAND:
 | 
				
			||||||
        burst = generateEdgeBurst(rtsc);
 | 
					        burst = generateEdgeBurst(rtsc);
 | 
				
			||||||
@@ -607,7 +607,7 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &i
 | 
				
			|||||||
  avg = sqrt(avg / radio_burst->chans());
 | 
					  avg = sqrt(avg / radio_burst->chans());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  wTime = time;
 | 
					  wTime = time;
 | 
				
			||||||
  RSSI = 20.0 * log10(rxFullScale / avg);
 | 
					  RSSI = 20.0 * log10(avg / rxFullScale);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* RSSI estimation are valid */
 | 
					  /* RSSI estimation are valid */
 | 
				
			||||||
  isRssiValid = true;
 | 
					  isRssiValid = true;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -84,6 +84,9 @@ struct TransceiverState {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /* Shadowed downlink attenuation */
 | 
					  /* Shadowed downlink attenuation */
 | 
				
			||||||
  int mPower;
 | 
					  int mPower;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Pseudorandom bit sequence */
 | 
				
			||||||
 | 
					  PRBS9 mPrbs;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** The Transceiver class, responsible for physical layer of basestation */
 | 
					/** The Transceiver class, responsible for physical layer of basestation */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										520
									
								
								Transceiver52M/osmo-trx-dec.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										520
									
								
								Transceiver52M/osmo-trx-dec.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,520 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2016-2017 Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					 * modify it under the terms of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License as published by the Free Software Foundation; either
 | 
				
			||||||
 | 
					 * version 2.1 of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * Lesser General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License along with this library; if not, write to the Free Software
 | 
				
			||||||
 | 
					 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_CONFIG_H
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					#include <iomanip>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "Logger.h"
 | 
				
			||||||
 | 
					#include "sigProcLib.h"
 | 
				
			||||||
 | 
					#include "signalVector.h"
 | 
				
			||||||
 | 
					#include "Transceiver.h"
 | 
				
			||||||
 | 
					#include "Configuration.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#include "convolve.h"
 | 
				
			||||||
 | 
					#include "convert.h"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DEFAULT_RX_SPS        1
 | 
				
			||||||
 | 
					#define DEFAULT_SEARCH_WINDOW 30
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Tail + data + stealing + midamble + guard (without the last 0.25)
 | 
				
			||||||
 | 
					#define BURST_LEN_FULL        156
 | 
				
			||||||
 | 
					// Tail + data + stealing + midamble
 | 
				
			||||||
 | 
					#define BURST_LEN_ACTIVE      148
 | 
				
			||||||
 | 
					// Tail + data + stealing + midamble - 2*0.5
 | 
				
			||||||
 | 
					#define BURST_LEN_USEFUL      147
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Size of a sample in bytes as stores in a file
 | 
				
			||||||
 | 
					#define SAMPLE_SIZE_BYTES     (2 * sizeof(float))
 | 
				
			||||||
 | 
					// Burst length in bytes as stored in a file
 | 
				
			||||||
 | 
					#define BURST_LEN_BYTES       (BURST_LEN_FULL * SAMPLE_SIZE_BYTES)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ConfigurationTable gConfig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct trx_config {
 | 
				
			||||||
 | 
					  std::string log_level;
 | 
				
			||||||
 | 
					  unsigned sps;
 | 
				
			||||||
 | 
					  unsigned tsc;
 | 
				
			||||||
 | 
					  unsigned max_expected_delay_nb;
 | 
				
			||||||
 | 
					  unsigned max_expected_delay_ab;
 | 
				
			||||||
 | 
					  double full_scale;
 | 
				
			||||||
 | 
					  bool edge;
 | 
				
			||||||
 | 
					  CorrType type;
 | 
				
			||||||
 | 
					  std::string filename;
 | 
				
			||||||
 | 
					  unsigned ber_burst_avg;           ///< Average BER over this many bursts.
 | 
				
			||||||
 | 
					                                    ///< Set to 0 to average for the whole duration.
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NormalBurstSoftbitMask {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					  NormalBurstSoftbitMask(SoftVector &softBits)
 | 
				
			||||||
 | 
					  : mSoftBits(softBits)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  SoftVector &bits() { return mSoftBits; }
 | 
				
			||||||
 | 
					  SoftVector tailBitsL() { return mSoftBits.segment(0,3); }
 | 
				
			||||||
 | 
					  SoftVector dataBitsL() { return mSoftBits.segment(3,57); }
 | 
				
			||||||
 | 
					  SoftVector stealingBitsL() { return mSoftBits.segment(60, 1); }
 | 
				
			||||||
 | 
					  SoftVector midambleBits() { return mSoftBits.segment(61, 26); }
 | 
				
			||||||
 | 
					  SoftVector stealingBitsR() { return mSoftBits.segment(87, 1); }
 | 
				
			||||||
 | 
					  SoftVector dataBitsR() { return mSoftBits.segment(88,57); }
 | 
				
			||||||
 | 
					  SoftVector tailBitsR() { return mSoftBits.segment(145,3); }
 | 
				
			||||||
 | 
					  SoftVector guardBits() { return mSoftBits.segment(148,8); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
					  SoftVector &mSoftBits;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SoftBurst {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					  SoftBurst(SoftVector *softBits, double toa=0)
 | 
				
			||||||
 | 
					  : mSoftBits(softBits), mTOA(toa)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    assert(mSoftBits != NULL);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ~SoftBurst()
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    delete mSoftBits;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void TOA(double TOA) { mTOA = TOA; }
 | 
				
			||||||
 | 
					  double TOA() { return mTOA; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  NormalBurstSoftbitMask normalBurstMask() { return NormalBurstSoftbitMask(*mSoftBits); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
					  SoftVector *mSoftBits;
 | 
				
			||||||
 | 
					  double mTOA;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BEREstimator {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					  BEREstimator(const PRBS& prbs)
 | 
				
			||||||
 | 
					  : mPRBS(prbs), mTotalBits(0), mErrorBits(0), mSynchronized(false)
 | 
				
			||||||
 | 
					  {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  unsigned synchronize(const BitVector &bits)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    for (unsigned i=0; i<mPRBS.size(); i++) {
 | 
				
			||||||
 | 
					      mPRBS.processBit(bits[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    mSynchronized = true;
 | 
				
			||||||
 | 
					    return mPRBS.size();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void process(const BitVector &bits, size_t start_from = 0)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    for (size_t i=start_from; i<bits.size(); i++) {
 | 
				
			||||||
 | 
					      mTotalBits++;
 | 
				
			||||||
 | 
					      if (mPRBS.generateBit() != bits.bit(i)) {
 | 
				
			||||||
 | 
					        mErrorBits++;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void sync_and_process(const BitVector &bits)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    unsigned skip = 0;
 | 
				
			||||||
 | 
					    if (!mSynchronized) {
 | 
				
			||||||
 | 
					      skip = synchronize(bits);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    process(bits, skip);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void skip(size_t num)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    for (size_t i=0; i<num; i++) {
 | 
				
			||||||
 | 
					      mTotalBits++;
 | 
				
			||||||
 | 
					      mErrorBits++;
 | 
				
			||||||
 | 
					      mPRBS.generateBit();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void reset()
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    mTotalBits = 0;
 | 
				
			||||||
 | 
					    mErrorBits = 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  unsigned totalBits() const { return mTotalBits; }
 | 
				
			||||||
 | 
					  unsigned errorBits() const { return mErrorBits; }
 | 
				
			||||||
 | 
					  double BER() const { return mErrorBits/(double)mTotalBits; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool isSynchronized() const {return mSynchronized; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
					  PRBS mPRBS;
 | 
				
			||||||
 | 
					  unsigned mTotalBits;
 | 
				
			||||||
 | 
					  unsigned mErrorBits;
 | 
				
			||||||
 | 
					  bool mSynchronized;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					double getBurstRSSI(const signalVector &burst, unsigned sps, double full_scale)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  /* Calculate average power of the burst */
 | 
				
			||||||
 | 
					  float avg = energyDetect(burst, 20 * sps);
 | 
				
			||||||
 | 
					  return 20.0 * log10(sqrt(avg) / full_scale);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void printDetectionResult(int rc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  if (rc > 0) {
 | 
				
			||||||
 | 
					    std::cout << "Detected correlation type: " << (CorrType)rc << std::endl;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    if (rc == -SIGERR_CLIP) {
 | 
				
			||||||
 | 
					      std::cout << "Clipping detected on received RACH or Normal Burst" << std::endl;
 | 
				
			||||||
 | 
					    } else if (rc != SIGERR_NONE) {
 | 
				
			||||||
 | 
					      std::cout << "Unhandled RACH or Normal Burst detection error" << std::endl;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					//      std::cout << "No burst detected" << std::endl;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SoftVector *demodulateBurst(const signalVector &burst,
 | 
				
			||||||
 | 
					                            CorrType expected_type,
 | 
				
			||||||
 | 
					                            unsigned sps, unsigned tsc,
 | 
				
			||||||
 | 
					                            unsigned max_expected_delay,
 | 
				
			||||||
 | 
					                            double &timingOffset)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  complex amp;
 | 
				
			||||||
 | 
					  float toa;
 | 
				
			||||||
 | 
					  int rc;
 | 
				
			||||||
 | 
					  CorrType detected_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Detect normal or RACH bursts */
 | 
				
			||||||
 | 
					  rc = detectAnyBurst(burst, tsc, BURST_THRESH, sps, expected_type, amp, toa,
 | 
				
			||||||
 | 
					                      max_expected_delay);
 | 
				
			||||||
 | 
					  printDetectionResult(rc);
 | 
				
			||||||
 | 
					  if (rc <= 0) {
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Convert samples to symbols
 | 
				
			||||||
 | 
					  timingOffset = toa / sps;
 | 
				
			||||||
 | 
					  // rc > 0 means it's a detected CorrType
 | 
				
			||||||
 | 
					  detected_type = (CorrType)rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return demodAnyBurst(burst, sps, amp, toa, detected_type);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool processBurst(const trx_config &config, signalVector &burst,
 | 
				
			||||||
 | 
					                         unsigned max_expected_delay,
 | 
				
			||||||
 | 
					                         double &RSSI,
 | 
				
			||||||
 | 
					                         double &timingOffset,
 | 
				
			||||||
 | 
					                         BEREstimator &berEstimator)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  RSSI = getBurstRSSI(burst, config.sps, config.full_scale);
 | 
				
			||||||
 | 
					  SoftVector *softBits = demodulateBurst(burst, config.type, config.sps,config.tsc,
 | 
				
			||||||
 | 
					                                         max_expected_delay, timingOffset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Print burst information and content */
 | 
				
			||||||
 | 
					  if (softBits == NULL) {
 | 
				
			||||||
 | 
					    std::cout << "Skipped frame" << std::endl;
 | 
				
			||||||
 | 
					    // TODO: This is different for EDGE
 | 
				
			||||||
 | 
					    berEstimator.skip(57*2);
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  SoftBurst softBurst(softBits, timingOffset);
 | 
				
			||||||
 | 
					  NormalBurstSoftbitMask nb = softBurst.normalBurstMask();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  berEstimator.sync_and_process(nb.dataBitsL().sliced());
 | 
				
			||||||
 | 
					  berEstimator.sync_and_process(nb.dataBitsR().sliced());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::cout << "TOA:  " << softBurst.TOA() << " symbols" << std::endl;
 | 
				
			||||||
 | 
					  // Exclude tail and guard bits from the energy calculation
 | 
				
			||||||
 | 
					  std::cout << "Energy:  " << softBits->segment(3,142).getEnergy() << std::endl;
 | 
				
			||||||
 | 
					  //std::cout << "Demodulated burst: " << *softBits << std::endl;
 | 
				
			||||||
 | 
					  std::cout << "                  tail|--------------------------data---------------------------|f|--------midamble----------|f|--------------------------data---------------------------|tai|-guard--" << std::endl;
 | 
				
			||||||
 | 
					  //           "                   000 010001011011110011101001100100000001010001011000100100010 0 11101111000100101110111100 0 011010111011101010011010111000101100001110101011011001011 000 1''..---"
 | 
				
			||||||
 | 
					  std::cout << "Demodulated burst:"
 | 
				
			||||||
 | 
					            << " " << nb.tailBitsL()
 | 
				
			||||||
 | 
					            << " " << nb.dataBitsL()
 | 
				
			||||||
 | 
					            << " " << nb.stealingBitsL()
 | 
				
			||||||
 | 
					            << " " << nb.midambleBits()
 | 
				
			||||||
 | 
					            << " " << nb.stealingBitsR()
 | 
				
			||||||
 | 
					            << " " << nb.dataBitsR()
 | 
				
			||||||
 | 
					            << " " << nb.tailBitsR()
 | 
				
			||||||
 | 
					            << " " << nb.guardBits()
 | 
				
			||||||
 | 
					            << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Setup configuration values
 | 
				
			||||||
 | 
					static void print_config(struct trx_config *config)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  std::ostringstream ost("");
 | 
				
			||||||
 | 
					  ost << "Config Settings" << std::endl;
 | 
				
			||||||
 | 
					  ost << "   Source file name............. " << config->filename << std::endl;
 | 
				
			||||||
 | 
					  ost << "   Log Level.................... " << config->log_level << std::endl;
 | 
				
			||||||
 | 
					  ost << "   Rx Samples-per-Symbol........ " << config->sps << std::endl;
 | 
				
			||||||
 | 
					  ost << "   EDGE support................. " << (config->edge ? "Enabled" : "Disabled") << std::endl;
 | 
				
			||||||
 | 
					  ost << "   Burst type................... " << config->type << std::endl;
 | 
				
			||||||
 | 
					  ost << "   Burst TSC.................... " << config->tsc << std::endl;
 | 
				
			||||||
 | 
					  ost << "   Normal Burst search window... " << config->max_expected_delay_nb << std::endl;
 | 
				
			||||||
 | 
					  ost << "   Access Burst search window... " << config->max_expected_delay_ab << std::endl;
 | 
				
			||||||
 | 
					  ost << "   Signal full scale............ " << config->full_scale << std::endl;
 | 
				
			||||||
 | 
					  ost << "   BER average window (bursts).. " << config->ber_burst_avg << std::endl;
 | 
				
			||||||
 | 
					  std::cout << ost << std::endl;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void print_help()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  fprintf(stdout, "Options:\n"
 | 
				
			||||||
 | 
					          "  -h          This text\n"
 | 
				
			||||||
 | 
					          "  -l LEVEL    Logging level (%s)\n"
 | 
				
			||||||
 | 
					          "  -e          Enable EDGE receiver\n"
 | 
				
			||||||
 | 
					          "  -s SPS      Samples-per-symbol (1 or 4, default: %d)\n"
 | 
				
			||||||
 | 
					          "  -t TSC      Burst training sequence (0 to 7, default: 0)\n"
 | 
				
			||||||
 | 
					          "  -f FILE     File to read\n"
 | 
				
			||||||
 | 
					          "  -w SYMBOLS  Normal Burst search window (0 to 156, default: %d)\n"
 | 
				
			||||||
 | 
					          "  -W SYMBOLS  Access Burst search window (0 to 156, default: %d)\n"
 | 
				
			||||||
 | 
					          "  -b BURSTS   BER average window. Set to 0 to average over the whole file (default: 1)\n",
 | 
				
			||||||
 | 
					          "EMERG, ALERT, CRT, ERR, WARNING, NOTICE, INFO, DEBUG",
 | 
				
			||||||
 | 
					          DEFAULT_RX_SPS,
 | 
				
			||||||
 | 
					          DEFAULT_SEARCH_WINDOW, DEFAULT_SEARCH_WINDOW);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool handle_options(int argc, char **argv, struct trx_config *config)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  int option;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  config->log_level = "NOTICE";
 | 
				
			||||||
 | 
					  config->sps = DEFAULT_RX_SPS;
 | 
				
			||||||
 | 
					  config->tsc = 0;
 | 
				
			||||||
 | 
					  config->max_expected_delay_nb = DEFAULT_SEARCH_WINDOW;
 | 
				
			||||||
 | 
					  config->max_expected_delay_ab = DEFAULT_SEARCH_WINDOW;
 | 
				
			||||||
 | 
					  config->full_scale = SHRT_MAX;
 | 
				
			||||||
 | 
					  config->edge = false;
 | 
				
			||||||
 | 
					  config->type = TSC;
 | 
				
			||||||
 | 
					  config->ber_burst_avg = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while ((option = getopt(argc, argv, "ls:et:f:w:W:b:h")) != -1) {
 | 
				
			||||||
 | 
					    switch (option) {
 | 
				
			||||||
 | 
					    case 'l':
 | 
				
			||||||
 | 
					      config->log_level = optarg;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case 's':
 | 
				
			||||||
 | 
					      config->sps = atoi(optarg);
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case 'e':
 | 
				
			||||||
 | 
					      config->edge = true;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case 't':
 | 
				
			||||||
 | 
					      config->tsc = atoi(optarg);
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case 'f':
 | 
				
			||||||
 | 
					      config->filename = optarg;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case 'w':
 | 
				
			||||||
 | 
					      config->max_expected_delay_nb = atoi(optarg);
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case 'W':
 | 
				
			||||||
 | 
					      config->max_expected_delay_ab = atoi(optarg);
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case 'b':
 | 
				
			||||||
 | 
					      config->ber_burst_avg = atoi(optarg);
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case 'h':
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      print_help();
 | 
				
			||||||
 | 
					      exit(0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if ((config->sps != 1) && (config->sps != 4)) {
 | 
				
			||||||
 | 
					    printf("ERROR: Unsupported samples-per-symbol %i\n\n", config->sps);
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (config->edge && (config->sps != 4)) {
 | 
				
			||||||
 | 
					    printf("ERROR: EDGE only supported at 4 samples per symbol\n\n");
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (config->tsc > 7) {
 | 
				
			||||||
 | 
					    printf("ERROR: Invalid training sequence %i\n\n", config->tsc);
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (config->filename.length() == 0) {
 | 
				
			||||||
 | 
					    printf("ERROR: No input file specified\n\n");
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (config->max_expected_delay_nb > 156 || config->max_expected_delay_nb < 0 ||
 | 
				
			||||||
 | 
					      config->max_expected_delay_ab > 156 || config->max_expected_delay_ab < 0) {
 | 
				
			||||||
 | 
					    printf("ERROR: Invalid search window size, must be withit [1..156] range\n\n");
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  struct trx_config config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_SSE3
 | 
				
			||||||
 | 
					  printf("Info: SSE3 support compiled in");
 | 
				
			||||||
 | 
					  if (__builtin_cpu_supports("sse3"))
 | 
				
			||||||
 | 
					    printf(" and supported by CPU\n");
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    printf(", but not supported by CPU\n");
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_SSE4_1
 | 
				
			||||||
 | 
					  printf("Info: SSE4.1 support compiled in");
 | 
				
			||||||
 | 
					  if (__builtin_cpu_supports("sse4.1"))
 | 
				
			||||||
 | 
					    printf(" and supported by CPU\n");
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    printf(", but not supported by CPU\n");
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  convolve_init();
 | 
				
			||||||
 | 
					  convert_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Process command line options and print config to screen
 | 
				
			||||||
 | 
					  if (!handle_options(argc, argv, &config)) {
 | 
				
			||||||
 | 
					    print_help();
 | 
				
			||||||
 | 
					    exit(0);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  print_config(&config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  gLogInit("transceiver", config.log_level.c_str(), LOG_LOCAL7);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!sigProcLibSetup()) {
 | 
				
			||||||
 | 
					    LOG(ALERT) << "Failed to initialize signal processing library";
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  double RSSI;
 | 
				
			||||||
 | 
					  double timingOffset, timingOffsetPrev = 0.0;
 | 
				
			||||||
 | 
					  signalVector burst(2*BURST_LEN_FULL);
 | 
				
			||||||
 | 
					  GSM::Time gsmTime;
 | 
				
			||||||
 | 
					  bool syncedTo157bits = false; // We should syncronize to 156-157 frame structure only once
 | 
				
			||||||
 | 
					  bool burst156_157 = false;    // Set to true to enable 156-156-156-157 frame
 | 
				
			||||||
 | 
					  int bitsReadExtra = 0; // set to 1 every 4 bursts and when TOA>1.0
 | 
				
			||||||
 | 
					  int bitsToSkip = 0;    // set to 1 when TOA<0.0
 | 
				
			||||||
 | 
					  unsigned berBurstsAveraged = 0;
 | 
				
			||||||
 | 
					  PRBS9 prbs;
 | 
				
			||||||
 | 
					  BEREstimator berEstimator(prbs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Configure output stream
 | 
				
			||||||
 | 
					  std::cout << std::fixed;
 | 
				
			||||||
 | 
					  std::cout << std::setprecision(2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::ifstream file (config.filename.c_str(), std::ifstream::binary);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Read the first burst, but do not process it, because we need at least two bursts
 | 
				
			||||||
 | 
					  // worth of data for reliable initial detection.
 | 
				
			||||||
 | 
					  file.read((char*)burst.begin(), config.sps * BURST_LEN_BYTES);
 | 
				
			||||||
 | 
					  {signalVector t = burst.segment(0, BURST_LEN_FULL); scaleVector(t, complex(SHRT_MAX)); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
					    /* Distort signal */
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      signalVector burst_read = burst.segment(85,156);
 | 
				
			||||||
 | 
					      std::ifstream file (config.filename.c_str(), std::ifstream::binary);
 | 
				
			||||||
 | 
					      file.read((char*)burst_read.begin(), burst_read.size() * 2 * sizeof(float));
 | 
				
			||||||
 | 
					      file.close();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#if 1
 | 
				
			||||||
 | 
					  // Read more data and try burst detection until successful
 | 
				
			||||||
 | 
					  while(file.read((char*)(burst.begin()+config.sps*BURST_LEN_FULL), config.sps*BURST_LEN_BYTES))
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    {signalVector t = burst.segment(BURST_LEN_FULL, BURST_LEN_FULL); scaleVector(t, complex(SHRT_MAX)); }
 | 
				
			||||||
 | 
					    bool found = processBurst(config, burst, BURST_LEN_FULL, RSSI, timingOffset, berEstimator);
 | 
				
			||||||
 | 
					    std::cout << "RSSI: " << RSSI << " dBFS" << std::endl;
 | 
				
			||||||
 | 
					    if (found) {
 | 
				
			||||||
 | 
					      gsmTime.incTN();
 | 
				
			||||||
 | 
					      berBurstsAveraged++;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    burst.segmentMove(config.sps*BURST_LEN_FULL, 0, config.sps*BURST_LEN_FULL);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Align stream to burst
 | 
				
			||||||
 | 
					  int offsetInt = (int)timingOffset;
 | 
				
			||||||
 | 
					  burst.segmentMove(config.sps*(BURST_LEN_FULL+offsetInt), 0, config.sps*(BURST_LEN_FULL-offsetInt));
 | 
				
			||||||
 | 
					  {signalVector t = burst.segment(0, BURST_LEN_FULL-offsetInt); scaleVector(t, complex(1.0/SHRT_MAX)); }
 | 
				
			||||||
 | 
					  file.read((char*)(burst.begin()+config.sps*(BURST_LEN_FULL-offsetInt)), config.sps*offsetInt*SAMPLE_SIZE_BYTES);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Resize burst vector to hold only one burst, because demodulation code
 | 
				
			||||||
 | 
					  // always decode the full vector size.
 | 
				
			||||||
 | 
					  burst.shrink(BURST_LEN_FULL+1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Process the rest of the stream
 | 
				
			||||||
 | 
					  do {
 | 
				
			||||||
 | 
					    {signalVector t = burst.segment(0, BURST_LEN_FULL); scaleVector(t, complex(SHRT_MAX)); }
 | 
				
			||||||
 | 
					    processBurst(config, burst, (config.type==RACH)?config.max_expected_delay_ab:config.max_expected_delay_ab,
 | 
				
			||||||
 | 
					                 RSSI, timingOffset, berEstimator);
 | 
				
			||||||
 | 
					    if (burst156_157 && !syncedTo157bits && timingOffset - timingOffsetPrev > .75) {
 | 
				
			||||||
 | 
					      std::cout << "TOA adjust: Found a 157-bit burst, reset TN to mark it" << std::endl;
 | 
				
			||||||
 | 
					      gsmTime.TN(2);
 | 
				
			||||||
 | 
					      timingOffset -= 1.0;
 | 
				
			||||||
 | 
					      // Make sure we do this adjustment only once.
 | 
				
			||||||
 | 
					      syncedTo157bits = true;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      gsmTime.incTN();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    bitsToSkip = 0;
 | 
				
			||||||
 | 
					    bitsReadExtra = 0;
 | 
				
			||||||
 | 
					    if (timingOffset < 0.0) {
 | 
				
			||||||
 | 
					      std::cout << "TOA adjust: skip a bit" << std::endl;
 | 
				
			||||||
 | 
					      burst[0] = 0;
 | 
				
			||||||
 | 
					      bitsToSkip = 1;
 | 
				
			||||||
 | 
					      bitsReadExtra--;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    bitsReadExtra += (gsmTime.TN()%4 == 0);
 | 
				
			||||||
 | 
					    if (timingOffset > 1.1) {
 | 
				
			||||||
 | 
					      std::cout << "TOA adjust: add extra bit" << std::endl;
 | 
				
			||||||
 | 
					      bitsReadExtra++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    std::cout << "Clock: " << gsmTime;
 | 
				
			||||||
 | 
					    std::cout << " RSSI: " << RSSI << " dBFS";
 | 
				
			||||||
 | 
					    std::cout << " Error bits: " << berEstimator.errorBits() << " Total bits: " << berEstimator.totalBits()
 | 
				
			||||||
 | 
					              << " BER: " << 100.0*berEstimator.errorBits() / berEstimator.totalBits() << "%" << std::endl;
 | 
				
			||||||
 | 
					    berBurstsAveraged++;
 | 
				
			||||||
 | 
					    // Never reset if config.ber_burst_avg is 0
 | 
				
			||||||
 | 
					    if (config.ber_burst_avg > 0 && berBurstsAveraged >= config.ber_burst_avg) {
 | 
				
			||||||
 | 
					        berBurstsAveraged = 0;
 | 
				
			||||||
 | 
					        berEstimator.reset();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    std::cout << "bitsReadExtra: " << bitsReadExtra << " bitsToSkip: " << bitsToSkip << std::endl;
 | 
				
			||||||
 | 
					    timingOffsetPrev = timingOffset;
 | 
				
			||||||
 | 
					  } while(file.read((char*)(burst.begin()+bitsToSkip), config.sps*(BURST_LEN_BYTES+SAMPLE_SIZE_BYTES*bitsReadExtra)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::cout << "End of file reached" << std::endl;
 | 
				
			||||||
 | 
					  file.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										334
									
								
								Transceiver52M/osmo-trx-gen.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										334
									
								
								Transceiver52M/osmo-trx-gen.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,334 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2017 Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					 * modify it under the terms of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License as published by the Free Software Foundation; either
 | 
				
			||||||
 | 
					 * version 2.1 of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * Lesser General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License along with this library; if not, write to the Free Software
 | 
				
			||||||
 | 
					 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_CONFIG_H
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					#include <iomanip>
 | 
				
			||||||
 | 
					#include <endian.h> // for byte order manipulation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "Logger.h"
 | 
				
			||||||
 | 
					#include "sigProcLib.h"
 | 
				
			||||||
 | 
					#include "GSMCommon.h"
 | 
				
			||||||
 | 
					#include "BitVector.h"
 | 
				
			||||||
 | 
					#include "Configuration.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#include "convolve.h"
 | 
				
			||||||
 | 
					#include "convert.h"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DEFAULT_SPS           4
 | 
				
			||||||
 | 
					#define DEFAULT_SEARCH_WINDOW 30
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Tail + data + stealing + midamble + guard (without the last 0.25)
 | 
				
			||||||
 | 
					#define BURST_LEN_FULL        156
 | 
				
			||||||
 | 
					// Tail + data + stealing + midamble
 | 
				
			||||||
 | 
					#define BURST_LEN_ACTIVE      148
 | 
				
			||||||
 | 
					// Tail + data + stealing + midamble - 2*0.5
 | 
				
			||||||
 | 
					#define BURST_LEN_USEFUL      147
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Size of a sample in bytes as stores in a file
 | 
				
			||||||
 | 
					#define SAMPLE_SIZE_BYTES     (2 * sizeof(float))
 | 
				
			||||||
 | 
					// Burst length in bytes as stored in a file
 | 
				
			||||||
 | 
					#define BURST_LEN_BYTES       (BURST_LEN_FULL * SAMPLE_SIZE_BYTES)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ConfigurationTable gConfig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum FileType {
 | 
				
			||||||
 | 
					  FLOAT_NORM_LE,  ///< Float -1..+1 Little Endian
 | 
				
			||||||
 | 
					  FLOAT16_LE,     ///< Float -32767..+32767 Little Endian
 | 
				
			||||||
 | 
					  SIGNED16_LE,    ///< Integer -32767..+32767 Little Endian
 | 
				
			||||||
 | 
					  SIGNED16_BE,    ///< Integer -32767..+32767 Big Endian (Keysight waveform format)
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct trx_config {
 | 
				
			||||||
 | 
					  std::string log_level;
 | 
				
			||||||
 | 
					  unsigned sps;
 | 
				
			||||||
 | 
					  unsigned tsc;
 | 
				
			||||||
 | 
					  double full_scale;
 | 
				
			||||||
 | 
					  bool edge;
 | 
				
			||||||
 | 
					  CorrType type;
 | 
				
			||||||
 | 
					  std::string filename;
 | 
				
			||||||
 | 
					  FileType file_type;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::ostream& operator<<(std::ostream& os, FileType ftype)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  switch(ftype)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					  case FLOAT_NORM_LE:
 | 
				
			||||||
 | 
					    os << "float";
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  case FLOAT16_LE:
 | 
				
			||||||
 | 
					    os << "float16";
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  case SIGNED16_LE:
 | 
				
			||||||
 | 
					    os << "signed16";
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  case SIGNED16_BE:
 | 
				
			||||||
 | 
					    os << "signed16be";
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  default:
 | 
				
			||||||
 | 
					    assert(!"unknown file type");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
						return os;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void writeBurstFloatNorm(std::ofstream& os, const signalVector& v)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  os.write((char*)v.begin(), v.size() * 2 * sizeof(float));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void writeBurstFloat16LE(std::ofstream& os, const signalVector& v)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  const complex *c = v.begin();
 | 
				
			||||||
 | 
					  for (size_t i=0; i<v.size(); i++, c++) {
 | 
				
			||||||
 | 
					    float iq[2];
 | 
				
			||||||
 | 
					    iq[0] = c->real()*SHRT_MAX;
 | 
				
			||||||
 | 
					    iq[1] = c->imag()*SHRT_MAX;
 | 
				
			||||||
 | 
					    os.write((char*)&iq, 2*sizeof(float));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void writeBurstSigned16LE(std::ofstream& os, const signalVector& v)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  const complex *c = v.begin();
 | 
				
			||||||
 | 
					  for (size_t i=0; i<v.size(); i++, c++) {
 | 
				
			||||||
 | 
					    int16_t iq[2];
 | 
				
			||||||
 | 
					    iq[0] = c->real()*SHRT_MAX;
 | 
				
			||||||
 | 
					    iq[1] = c->imag()*SHRT_MAX;
 | 
				
			||||||
 | 
					    iq[0] = htole16(iq[0]);
 | 
				
			||||||
 | 
					    iq[1] = htole16(iq[1]);
 | 
				
			||||||
 | 
					    os.write((char*)&iq, 2*sizeof(int16_t));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void writeBurstSigned16BE(std::ofstream& os, const signalVector& v)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  const complex *c = v.begin();
 | 
				
			||||||
 | 
					  for (size_t i=0; i<v.size(); i++, c++) {
 | 
				
			||||||
 | 
					    int16_t iq[2];
 | 
				
			||||||
 | 
					    iq[0] = c->real()*SHRT_MAX;
 | 
				
			||||||
 | 
					    iq[1] = c->imag()*SHRT_MAX;
 | 
				
			||||||
 | 
					    iq[0] = htobe16(iq[0]);
 | 
				
			||||||
 | 
					    iq[1] = htobe16(iq[1]);
 | 
				
			||||||
 | 
					    os.write((char*)&iq, 2*sizeof(int16_t));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void writeBurst(std::ofstream& os, const signalVector& v, FileType ftype)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  switch(ftype)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					  case FLOAT_NORM_LE:
 | 
				
			||||||
 | 
					    writeBurstFloatNorm(os, v);
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  case FLOAT16_LE:
 | 
				
			||||||
 | 
					    writeBurstFloat16LE(os, v);
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  case SIGNED16_LE:
 | 
				
			||||||
 | 
					    writeBurstSigned16LE(os, v);
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  case SIGNED16_BE:
 | 
				
			||||||
 | 
					    writeBurstSigned16BE(os, v);
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  default:
 | 
				
			||||||
 | 
					    assert(!"unknown file type");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Setup configuration values
 | 
				
			||||||
 | 
					static void print_config(struct trx_config *config)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  std::ostringstream ost("");
 | 
				
			||||||
 | 
					  ost << "Config Settings" << std::endl;
 | 
				
			||||||
 | 
					  ost << "   Destination file name........ " << config->filename << std::endl;
 | 
				
			||||||
 | 
					  ost << "   Destination file type........ " << config->file_type << std::endl;
 | 
				
			||||||
 | 
					  ost << "   Log Level.................... " << config->log_level << std::endl;
 | 
				
			||||||
 | 
					  ost << "   Tx Samples-per-Symbol........ " << config->sps << std::endl;
 | 
				
			||||||
 | 
					  ost << "   EDGE support................. " << (config->edge ? "Enabled" : "Disabled") << std::endl;
 | 
				
			||||||
 | 
					  ost << "   Burst type................... " << config->type << std::endl;
 | 
				
			||||||
 | 
					  ost << "   Burst TSC.................... " << config->tsc << std::endl;
 | 
				
			||||||
 | 
					  ost << "   Signal full scale............ " << config->full_scale << std::endl;
 | 
				
			||||||
 | 
					  std::cout << ost << std::endl;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void print_help()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  fprintf(stdout,
 | 
				
			||||||
 | 
					          "This utility generates waveform files aka IQ binary files in a number of formats"
 | 
				
			||||||
 | 
					          "to use them as input to osmo-trx-dec or load them into signal generators.\n"
 | 
				
			||||||
 | 
					          "\n"
 | 
				
			||||||
 | 
					          "Options:\n"
 | 
				
			||||||
 | 
					          "  -h          This text\n"
 | 
				
			||||||
 | 
					          "  -l LEVEL    Logging level (%s)\n"
 | 
				
			||||||
 | 
					          "  -e          Enable EDGE receiver\n"
 | 
				
			||||||
 | 
					          "  -s SPS      Samples-per-symbol (1 or 4, default: %d)\n"
 | 
				
			||||||
 | 
					          "  -t TSC      Burst training sequence (0 to 7, default: 0)\n"
 | 
				
			||||||
 | 
					          "  -f FILE     File to write generated bursts to\n"
 | 
				
			||||||
 | 
					          "  -F FILETYPE Format of the file - float, float16, signed16, signed16be (default: f16)\n"
 | 
				
			||||||
 | 
					          "              Note: Keysight waveform format is signed16be. osmo-trx-dec accepts float16.\n",
 | 
				
			||||||
 | 
					          "EMERG, ALERT, CRT, ERR, WARNING, NOTICE, INFO, DEBUG",
 | 
				
			||||||
 | 
					          DEFAULT_SPS);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FileType option_to_file_type(const std::string &optarg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  if (optarg == "float") {
 | 
				
			||||||
 | 
					    return FLOAT_NORM_LE;
 | 
				
			||||||
 | 
					  } else if (optarg == "float16") {
 | 
				
			||||||
 | 
					    return FLOAT16_LE;
 | 
				
			||||||
 | 
					  } else if (optarg == "signed16") {
 | 
				
			||||||
 | 
					    return SIGNED16_LE;
 | 
				
			||||||
 | 
					  } else if (optarg == "signed16be") {
 | 
				
			||||||
 | 
					    return SIGNED16_BE;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    return (FileType)-1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool handle_options(int argc, char **argv, struct trx_config *config)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  int option;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  config->log_level = "NOTICE";
 | 
				
			||||||
 | 
					  config->sps = DEFAULT_SPS;
 | 
				
			||||||
 | 
					  config->tsc = 0;
 | 
				
			||||||
 | 
					  config->full_scale = SHRT_MAX;
 | 
				
			||||||
 | 
					  config->edge = false;
 | 
				
			||||||
 | 
					  config->type = TSC;
 | 
				
			||||||
 | 
					  config->file_type = FLOAT16_LE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while ((option = getopt(argc, argv, "ls:et:f:F:h")) != -1) {
 | 
				
			||||||
 | 
					    switch (option) {
 | 
				
			||||||
 | 
					    case 'l':
 | 
				
			||||||
 | 
					      config->log_level = optarg;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case 's':
 | 
				
			||||||
 | 
					      config->sps = atoi(optarg);
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case 'e':
 | 
				
			||||||
 | 
					      config->edge = true;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case 't':
 | 
				
			||||||
 | 
					      config->tsc = atoi(optarg);
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case 'f':
 | 
				
			||||||
 | 
					      config->filename = optarg;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case 'F':
 | 
				
			||||||
 | 
					      config->file_type = option_to_file_type(optarg);
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case 'h':
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      print_help();
 | 
				
			||||||
 | 
					      exit(0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if ((config->sps != 1) && (config->sps != 4)) {
 | 
				
			||||||
 | 
					    printf("ERROR: Unsupported samples-per-symbol %i\n\n", config->sps);
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (config->edge && (config->sps != 4)) {
 | 
				
			||||||
 | 
					    printf("ERROR: EDGE only supported at 4 samples per symbol\n\n");
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (config->tsc > 7) {
 | 
				
			||||||
 | 
					    printf("ERROR: Invalid training sequence %i\n\n", config->tsc);
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (config->filename.length() == 0) {
 | 
				
			||||||
 | 
					    printf("ERROR: No output file name specified\n\n");
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (config->file_type < 0) {
 | 
				
			||||||
 | 
					    printf("ERROR: Wrong output file format\n\n");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  struct trx_config config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_SSE3
 | 
				
			||||||
 | 
					  printf("Info: SSE3 support compiled in");
 | 
				
			||||||
 | 
					  if (__builtin_cpu_supports("sse3"))
 | 
				
			||||||
 | 
					    printf(" and supported by CPU\n");
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    printf(", but not supported by CPU\n");
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_SSE4_1
 | 
				
			||||||
 | 
					  printf("Info: SSE4.1 support compiled in");
 | 
				
			||||||
 | 
					  if (__builtin_cpu_supports("sse4.1"))
 | 
				
			||||||
 | 
					    printf(" and supported by CPU\n");
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    printf(", but not supported by CPU\n");
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  convolve_init();
 | 
				
			||||||
 | 
					  convert_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Process command line options and print config to screen
 | 
				
			||||||
 | 
					  if (!handle_options(argc, argv, &config)) {
 | 
				
			||||||
 | 
					    print_help();
 | 
				
			||||||
 | 
					    exit(0);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  print_config(&config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  gLogInit("transceiver", config.log_level.c_str(), LOG_LOCAL7);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!sigProcLibSetup()) {
 | 
				
			||||||
 | 
					    LOG(ALERT) << "Failed to initialize signal processing library";
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  signalVector burst(2*BURST_LEN_FULL);
 | 
				
			||||||
 | 
					  GSM::Time gsmTime;
 | 
				
			||||||
 | 
					  PRBS9 prbs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Configure output stream
 | 
				
			||||||
 | 
					  std::cout << std::fixed;
 | 
				
			||||||
 | 
					  std::cout << std::setprecision(2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::ofstream file (config.filename.c_str(), std::ifstream::binary);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (int i=0; i<511; i++) {
 | 
				
			||||||
 | 
					    signalVector *signal = genRandNormalBurst(config.tsc, config.sps, gsmTime.TN(), prbs);
 | 
				
			||||||
 | 
					    writeBurst(file, *signal, config.file_type);
 | 
				
			||||||
 | 
					    gsmTime.incTN();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  file.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::cout << "Done!" << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -256,7 +256,8 @@ static void print_help()
 | 
				
			|||||||
		"  -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"
 | 
				
			||||||
		"  -o    Set baseband frequency offset (default=auto)\n"
 | 
							"  -o    Set baseband frequency offset (default=auto)\n"
 | 
				
			||||||
		"  -r    Random Normal Burst test mode with TSC\n"
 | 
							"  -r    Random GMSK Normal Burst test mode with given TSC\n"
 | 
				
			||||||
 | 
							"  -E    Random 8-PSK Normal Burst test mode with given TSC\n"
 | 
				
			||||||
		"  -A    Random Access Burst test mode with delay\n"
 | 
							"  -A    Random Access Burst test mode with delay\n"
 | 
				
			||||||
		"  -R    RSSI to dBm offset in dB (default=0)\n"
 | 
							"  -R    RSSI to dBm offset in dB (default=0)\n"
 | 
				
			||||||
		"  -S    Swap channels (UmTRX only)\n",
 | 
							"  -S    Swap channels (UmTRX only)\n",
 | 
				
			||||||
@@ -284,7 +285,7 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
 | 
				
			|||||||
	config->swap_channels = false;
 | 
						config->swap_channels = false;
 | 
				
			||||||
	config->edge = false;
 | 
						config->edge = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while ((option = getopt(argc, argv, "ha:l:i:p:c:dmxgfo:s:b:r:A:R:Se")) != -1) {
 | 
						while ((option = getopt(argc, argv, "ha:l:i:p:c:dmxgfo:s:b:r:E:A:R:Se")) != -1) {
 | 
				
			||||||
		switch (option) {
 | 
							switch (option) {
 | 
				
			||||||
		case 'h':
 | 
							case 'h':
 | 
				
			||||||
			print_help();
 | 
								print_help();
 | 
				
			||||||
@@ -330,6 +331,10 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
 | 
				
			|||||||
			config->rtsc = atoi(optarg);
 | 
								config->rtsc = atoi(optarg);
 | 
				
			||||||
			config->filler = Transceiver::FILLER_NORM_RAND;
 | 
								config->filler = Transceiver::FILLER_NORM_RAND;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
							case 'E':
 | 
				
			||||||
 | 
								config->rtsc = atoi(optarg);
 | 
				
			||||||
 | 
								config->filler = Transceiver::FILLER_EDGE_RAND;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		case 'A':
 | 
							case 'A':
 | 
				
			||||||
			config->rach_delay = atoi(optarg);
 | 
								config->rach_delay = atoi(optarg);
 | 
				
			||||||
			config->filler = Transceiver::FILLER_ACCESS_RAND;
 | 
								config->filler = Transceiver::FILLER_ACCESS_RAND;
 | 
				
			||||||
@@ -360,8 +365,10 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
 | 
				
			|||||||
		goto bad_config;
 | 
							goto bad_config;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (config->edge && (config->filler == Transceiver::FILLER_NORM_RAND))
 | 
						if (!config->edge && (config->filler == Transceiver::FILLER_EDGE_RAND)) {
 | 
				
			||||||
		config->filler = Transceiver::FILLER_EDGE_RAND;
 | 
							printf("Can't enable EDGE filler when EDGE mode is disabled\n\n");
 | 
				
			||||||
 | 
							goto bad_config;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((config->tx_sps != 1) && (config->tx_sps != 4) &&
 | 
						if ((config->tx_sps != 1) && (config->tx_sps != 4) &&
 | 
				
			||||||
	    (config->rx_sps != 1) && (config->rx_sps != 4)) {
 | 
						    (config->rx_sps != 1) && (config->rx_sps != 4)) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,6 +22,7 @@
 | 
				
			|||||||
#include "radioInterface.h"
 | 
					#include "radioInterface.h"
 | 
				
			||||||
#include "Resampler.h"
 | 
					#include "Resampler.h"
 | 
				
			||||||
#include <Logger.h>
 | 
					#include <Logger.h>
 | 
				
			||||||
 | 
					#include <PRBS.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern "C" {
 | 
					extern "C" {
 | 
				
			||||||
#include "convert.h"
 | 
					#include "convert.h"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -915,7 +915,7 @@ static signalVector *shapeEdgeBurst(const signalVector &symbols)
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * Generate a random GSM normal burst.
 | 
					 * Generate a random GSM normal burst.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
signalVector *genRandNormalBurst(int tsc, int sps, int tn)
 | 
					signalVector *genRandNormalBurst(int tsc, int sps, int tn, PRBS &prbs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if ((tsc < 0) || (tsc > 7) || (tn < 0) || (tn > 7))
 | 
					  if ((tsc < 0) || (tsc > 7) || (tn < 0) || (tn > 7))
 | 
				
			||||||
    return NULL;
 | 
					    return NULL;
 | 
				
			||||||
@@ -932,7 +932,7 @@ signalVector *genRandNormalBurst(int tsc, int sps, int tn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /* Random bits */
 | 
					  /* Random bits */
 | 
				
			||||||
  for (; i < 60; i++)
 | 
					  for (; i < 60; i++)
 | 
				
			||||||
    (*bits)[i] = rand() % 2;
 | 
					    (*bits)[i] = prbs.generateBit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Stealing bit */
 | 
					  /* Stealing bit */
 | 
				
			||||||
  (*bits)[i++] = 0;
 | 
					  (*bits)[i++] = 0;
 | 
				
			||||||
@@ -946,7 +946,7 @@ signalVector *genRandNormalBurst(int tsc, int sps, int tn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /* Random bits */
 | 
					  /* Random bits */
 | 
				
			||||||
  for (; i < 145; i++)
 | 
					  for (; i < 145; i++)
 | 
				
			||||||
    (*bits)[i] = rand() % 2;
 | 
					    (*bits)[i] = prbs.generateBit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Tail bits */
 | 
					  /* Tail bits */
 | 
				
			||||||
  for (; i < 148; i++)
 | 
					  for (; i < 148; i++)
 | 
				
			||||||
@@ -1855,8 +1855,8 @@ int analyzeTrafficBurst(const signalVector &burst, unsigned tsc, float threshold
 | 
				
			|||||||
    return -SIGERR_UNSUPPORTED;
 | 
					    return -SIGERR_UNSUPPORTED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  target = 3 + 58 + 16 + 5;
 | 
					  target = 3 + 58 + 16 + 5;
 | 
				
			||||||
  head = 6;
 | 
					  head = 3;
 | 
				
			||||||
  tail = 6 + max_toa;
 | 
					  tail = 3 + max_toa;
 | 
				
			||||||
  sync = gMidambles[tsc];
 | 
					  sync = gMidambles[tsc];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  rc = detectGeneralBurst(burst, threshold, sps, amplitude, toa,
 | 
					  rc = detectGeneralBurst(burst, threshold, sps, amplitude, toa,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@
 | 
				
			|||||||
#include "Vector.h"
 | 
					#include "Vector.h"
 | 
				
			||||||
#include "Complex.h"
 | 
					#include "Complex.h"
 | 
				
			||||||
#include "BitVector.h"
 | 
					#include "BitVector.h"
 | 
				
			||||||
 | 
					#include "PRBS.h"
 | 
				
			||||||
#include "signalVector.h"
 | 
					#include "signalVector.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Burst lengths */
 | 
					/* Burst lengths */
 | 
				
			||||||
@@ -140,7 +141,7 @@ signalVector *generateEdgeBurst(int tsc);
 | 
				
			|||||||
signalVector *generateEmptyBurst(int sps, int tn);
 | 
					signalVector *generateEmptyBurst(int sps, int tn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Generate a normal GSM burst with random payload - 4 or 1 SPS */
 | 
					/** Generate a normal GSM burst with random payload - 4 or 1 SPS */
 | 
				
			||||||
signalVector *genRandNormalBurst(int tsc, int sps, int tn);
 | 
					signalVector *genRandNormalBurst(int tsc, int sps, int tn, PRBS &prbs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Generate an access GSM burst with random payload - 4 or 1 SPS */
 | 
					/** Generate an access GSM burst with random payload - 4 or 1 SPS */
 | 
				
			||||||
signalVector *genRandAccessBurst(int delay, int sps, int tn);
 | 
					signalVector *genRandAccessBurst(int delay, int sps, int tn);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user