mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-trx.git
				synced 2025-11-04 06:03:17 +00:00 
			
		
		
		
	Compare commits
	
		
			77 Commits
		
	
	
		
			fairwaves/
			...
			max/fix
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					f38a0c06dc | ||
| 
						 | 
					3b093bb13b | ||
| 
						 | 
					3f4a13f049 | ||
| 
						 | 
					0fe41a583c | ||
| 
						 | 
					a5e0f1cdba | ||
| 
						 | 
					2c650a6895 | ||
| 
						 | 
					d4555f267e | ||
| 
						 | 
					047956259b | ||
| 
						 | 
					d2b070369d | ||
| 
						 | 
					9664c3a6e7 | ||
| 
						 | 
					1ab5e7f7bc | ||
| 
						 | 
					5efe05021a | ||
| 
						 | 
					78d1fc9a13 | ||
| 
						 | 
					a8cf208616 | ||
| 
						 | 
					f84232d30a | ||
| 
						 | 
					9bd649ec73 | ||
| 
						 | 
					871b87829f | ||
| 
						 | 
					d17b189cbc | ||
| 
						 | 
					7fec3030d4 | ||
| 
						 | 
					af717b2d3c | ||
| 
						 | 
					8ee2f38a87 | ||
| 
						 | 
					4dfd64aa9e | ||
| 
						 | 
					b0aefcbf47 | ||
| 
						 | 
					d325343ecc | ||
| 
						 | 
					5cd70dc4ec | ||
| 
						 | 
					465694027b | ||
| 
						 | 
					2079a3c664 | ||
| 
						 | 
					99cf930f9a | ||
| 
						 | 
					283b22dbce | ||
| 
						 | 
					f147b17447 | ||
| 
						 | 
					d4d3daa12e | ||
| 
						 | 
					c312905f43 | ||
| 
						 | 
					c4eab8795f | ||
| 
						 | 
					cc6f79b1c0 | ||
| 
						 | 
					5a0680655f | ||
| 
						 | 
					3722920100 | ||
| 
						 | 
					f3b9af65ed | ||
| 
						 | 
					e692ce986c | ||
| 
						 | 
					81c6873205 | ||
| 
						 | 
					c052aa1d4c | ||
| 
						 | 
					130a8007fa | ||
| 
						 | 
					72e8619632 | ||
| 
						 | 
					2beb1adcea | ||
| 
						 | 
					2b542100a0 | ||
| 
						 | 
					2268c8558c | ||
| 
						 | 
					50747dc65d | ||
| 
						 | 
					1e9b4d57da | ||
| 
						 | 
					954b118bfa | ||
| 
						 | 
					dbe26abcb9 | ||
| 
						 | 
					e8905a03a5 | ||
| 
						 | 
					909ffbfd23 | ||
| 
						 | 
					351fd76706 | ||
| 
						 | 
					6a2bf0d87b | ||
| 
						 | 
					2966048b07 | ||
| 
						 | 
					f5fd578d60 | ||
| 
						 | 
					57ef87d061 | ||
| 
						 | 
					5721920a08 | ||
| 
						 | 
					194a9b1982 | ||
| 
						 | 
					1fe5282133 | ||
| 
						 | 
					4438a9fd8f | ||
| 
						 | 
					64ad712daa | ||
| 
						 | 
					5c7c178369 | ||
| 
						 | 
					90f7a01d1d | ||
| 
						 | 
					e171425b99 | ||
| 
						 | 
					4d029d8965 | ||
| 
						 | 
					6613331459 | ||
| 
						 | 
					577cd020c1 | ||
| 
						 | 
					88bbf1aafd | ||
| 
						 | 
					2cc2ddda41 | ||
| 
						 | 
					d7610cf0b8 | ||
| 
						 | 
					722d4f70a4 | ||
| 
						 | 
					93b7f37309 | ||
| 
						 | 
					4ad9ea69ab | ||
| 
						 | 
					eb54bddf47 | ||
| 
						 | 
					a4d1a41244 | ||
| 
						 | 
					b999759175 | ||
| 
						 | 
					1ae25561fa | 
							
								
								
									
										56
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
				
			|||||||
 | 
					.deps
 | 
				
			||||||
 | 
					.libs
 | 
				
			||||||
 | 
					*.o
 | 
				
			||||||
 | 
					*.lo
 | 
				
			||||||
 | 
					CommonLibs/BitVectorTest
 | 
				
			||||||
 | 
					CommonLibs/ConfigurationTest
 | 
				
			||||||
 | 
					CommonLibs/F16Test
 | 
				
			||||||
 | 
					CommonLibs/InterthreadTest
 | 
				
			||||||
 | 
					CommonLibs/LogTest
 | 
				
			||||||
 | 
					CommonLibs/Makefile
 | 
				
			||||||
 | 
					CommonLibs/Makefile.in
 | 
				
			||||||
 | 
					CommonLibs/RegexpTest
 | 
				
			||||||
 | 
					CommonLibs/SocketsTest
 | 
				
			||||||
 | 
					CommonLibs/TimevalTest
 | 
				
			||||||
 | 
					CommonLibs/URLEncodeTest
 | 
				
			||||||
 | 
					CommonLibs/VectorTest
 | 
				
			||||||
 | 
					CommonLibs/libcommon.la
 | 
				
			||||||
 | 
					GSM/Makefile
 | 
				
			||||||
 | 
					GSM/Makefile.in
 | 
				
			||||||
 | 
					GSM/libGSM.la
 | 
				
			||||||
 | 
					Makefile
 | 
				
			||||||
 | 
					Makefile.in
 | 
				
			||||||
 | 
					Transceiver52M/Makefile
 | 
				
			||||||
 | 
					Transceiver52M/Makefile.in
 | 
				
			||||||
 | 
					Transceiver52M/arm/Makefile
 | 
				
			||||||
 | 
					Transceiver52M/arm/Makefile.in
 | 
				
			||||||
 | 
					Transceiver52M/common/.dirstamp
 | 
				
			||||||
 | 
					Transceiver52M/libtransceiver.la
 | 
				
			||||||
 | 
					Transceiver52M/osmo-trx
 | 
				
			||||||
 | 
					Transceiver52M/x86/Makefile
 | 
				
			||||||
 | 
					Transceiver52M/x86/Makefile.in
 | 
				
			||||||
 | 
					Transceiver52M/x86/libarch.la
 | 
				
			||||||
 | 
					aclocal.m4
 | 
				
			||||||
 | 
					autom4te.cache/
 | 
				
			||||||
 | 
					compile
 | 
				
			||||||
 | 
					config.guess
 | 
				
			||||||
 | 
					config.h
 | 
				
			||||||
 | 
					config.h.in
 | 
				
			||||||
 | 
					config.log
 | 
				
			||||||
 | 
					config.status
 | 
				
			||||||
 | 
					config.sub
 | 
				
			||||||
 | 
					config/libtool.m4
 | 
				
			||||||
 | 
					config/ltoptions.m4
 | 
				
			||||||
 | 
					config/ltsugar.m4
 | 
				
			||||||
 | 
					config/ltversion.m4
 | 
				
			||||||
 | 
					config/lt~obsolete.m4
 | 
				
			||||||
 | 
					configure
 | 
				
			||||||
 | 
					depcomp
 | 
				
			||||||
 | 
					install-sh
 | 
				
			||||||
 | 
					libtool
 | 
				
			||||||
 | 
					ltmain.sh
 | 
				
			||||||
 | 
					missing
 | 
				
			||||||
 | 
					sqlite3/Makefile
 | 
				
			||||||
 | 
					sqlite3/Makefile.in
 | 
				
			||||||
 | 
					sqlite3/libsqlite.la
 | 
				
			||||||
 | 
					stamp-h1
 | 
				
			||||||
@@ -35,7 +35,7 @@
 | 
				
			|||||||
#ifdef DEBUG_CONFIG
 | 
					#ifdef DEBUG_CONFIG
 | 
				
			||||||
#define	debugLogEarly gLogEarly
 | 
					#define	debugLogEarly gLogEarly
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#define	debugLogEarly
 | 
					#define	debugLogEarly(x,y,z)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,6 +38,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					using namespace std;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Switches to enable/disable logging targets
 | 
				
			||||||
 | 
					// MUST BE DEFINED BEFORE gConfig FOR gLogEarly() TO WORK CORRECTLY
 | 
				
			||||||
 | 
					bool gLogToConsole = true;
 | 
				
			||||||
 | 
					bool gLogToSyslog = false;
 | 
				
			||||||
 | 
					FILE *gLogToFile = NULL;
 | 
				
			||||||
 | 
					Mutex gLogToLock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Reference to a global config table, used all over the system.
 | 
					// Reference to a global config table, used all over the system.
 | 
				
			||||||
extern ConfigurationTable gConfig;
 | 
					extern ConfigurationTable gConfig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -67,9 +75,6 @@ const char *levelNames[] = {
 | 
				
			|||||||
	"EMERG", "ALERT", "CRIT", "ERR", "WARNING", "NOTICE", "INFO", "DEBUG"
 | 
						"EMERG", "ALERT", "CRIT", "ERR", "WARNING", "NOTICE", "INFO", "DEBUG"
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
int numLevels = 8;
 | 
					int numLevels = 8;
 | 
				
			||||||
bool gLogToConsole = 0;
 | 
					 | 
				
			||||||
FILE *gLogToFile = NULL;
 | 
					 | 
				
			||||||
Mutex gLogToLock;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int levelStringToInt(const string& name)
 | 
					int levelStringToInt(const string& name)
 | 
				
			||||||
@@ -196,14 +201,16 @@ Log::~Log()
 | 
				
			|||||||
		if (sLoggerInited) addAlarm(mStream.str().c_str());
 | 
							if (sLoggerInited) addAlarm(mStream.str().c_str());
 | 
				
			||||||
		cerr << mStream.str() << endl;
 | 
							cerr << mStream.str() << endl;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// Current logging level was already checked by the macro.
 | 
						// Current logging level was already checked by the macro. So just log.
 | 
				
			||||||
	// So just log.
 | 
						// Log to syslog
 | 
				
			||||||
 | 
						if (gLogToSyslog) {
 | 
				
			||||||
		syslog(mPriority, "%s", mStream.str().c_str());
 | 
							syslog(mPriority, "%s", mStream.str().c_str());
 | 
				
			||||||
	// pat added for easy debugging.
 | 
						}
 | 
				
			||||||
 | 
						// Log to file and console
 | 
				
			||||||
	if (gLogToConsole||gLogToFile) {
 | 
						if (gLogToConsole||gLogToFile) {
 | 
				
			||||||
		int mlen = mStream.str().size();
 | 
							int mlen = mStream.str().size();
 | 
				
			||||||
		int neednl = (mlen==0 || mStream.str()[mlen-1] != '\n');
 | 
							int neednl = (mlen==0 || mStream.str()[mlen-1] != '\n');
 | 
				
			||||||
		gLogToLock.lock();
 | 
							ScopedLock lock(gLogToLock);
 | 
				
			||||||
		if (gLogToConsole) {
 | 
							if (gLogToConsole) {
 | 
				
			||||||
			// The COUT() macro prevents messages from stomping each other but adds uninteresting thread numbers,
 | 
								// The COUT() macro prevents messages from stomping each other but adds uninteresting thread numbers,
 | 
				
			||||||
			// so just use std::cout.
 | 
								// so just use std::cout.
 | 
				
			||||||
@@ -215,7 +222,6 @@ Log::~Log()
 | 
				
			|||||||
			if (neednl) {fputc('\n',gLogToFile);}
 | 
								if (neednl) {fputc('\n',gLogToFile);}
 | 
				
			||||||
			fflush(gLogToFile);
 | 
								fflush(gLogToFile);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		gLogToLock.unlock();
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -243,10 +249,9 @@ void gLogInit(const char* name, const char* level, int facility)
 | 
				
			|||||||
		gConfig.set("Log.Level",level);
 | 
							gConfig.set("Log.Level",level);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Pat added, tired of the syslog facility.
 | 
					 | 
				
			||||||
	// Both the transceiver and OpenBTS use this same facility, but only OpenBTS/OpenNodeB may use this log file:
 | 
						// Both the transceiver and OpenBTS use this same facility, but only OpenBTS/OpenNodeB may use this log file:
 | 
				
			||||||
	string str = gConfig.getStr("Log.File");
 | 
						string str = gConfig.getStr("Log.File");
 | 
				
			||||||
	if (gLogToFile==0 && str.length() && 0==strncmp(gCmdName,"Open",4)) {
 | 
						if (gLogToFile==NULL && str.length() && 0==strncmp(gCmdName,"Open",4)) {
 | 
				
			||||||
		const char *fn = str.c_str();
 | 
							const char *fn = str.c_str();
 | 
				
			||||||
		if (fn && *fn && strlen(fn)>3) {	// strlen because a garbage char is getting in sometimes.
 | 
							if (fn && *fn && strlen(fn)>3) {	// strlen because a garbage char is getting in sometimes.
 | 
				
			||||||
			gLogToFile = fopen(fn,"w"); // New log file each time we start.
 | 
								gLogToFile = fopen(fn,"w"); // New log file each time we start.
 | 
				
			||||||
@@ -270,7 +275,30 @@ void gLogEarly(int level, const char *fmt, ...)
 | 
				
			|||||||
	va_list args;
 | 
						va_list args;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	va_start(args, fmt);
 | 
						va_start(args, fmt);
 | 
				
			||||||
	vsyslog(level | LOG_USER, fmt, args);
 | 
					
 | 
				
			||||||
 | 
						if (gLogToSyslog) {
 | 
				
			||||||
 | 
							va_list args_copy;
 | 
				
			||||||
 | 
							va_copy(args_copy, args);
 | 
				
			||||||
 | 
							vsyslog(level | LOG_USER, fmt, args_copy);
 | 
				
			||||||
 | 
							va_end(args_copy);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (gLogToConsole) {
 | 
				
			||||||
 | 
							va_list args_copy;
 | 
				
			||||||
 | 
							va_copy(args_copy, args);
 | 
				
			||||||
 | 
							vprintf(fmt, args_copy);
 | 
				
			||||||
 | 
							printf("\n");
 | 
				
			||||||
 | 
							va_end(args_copy);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (gLogToFile) {
 | 
				
			||||||
 | 
							va_list args_copy;
 | 
				
			||||||
 | 
							va_copy(args_copy, args);
 | 
				
			||||||
 | 
							vfprintf(gLogToFile, fmt, args_copy);
 | 
				
			||||||
 | 
							fprintf(gLogToFile, "\n");
 | 
				
			||||||
 | 
							va_end(args_copy);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	va_end(args);
 | 
						va_end(args);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -116,7 +116,8 @@ class Log {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	std::ostringstream& get();
 | 
						std::ostringstream& get();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
extern bool gLogToConsole;	// Pat added for easy debugging.
 | 
					extern bool gLogToConsole;	// Output log messages to stdout
 | 
				
			||||||
 | 
					extern bool gLogToSyslog;	// Output log messages to syslog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -187,24 +187,20 @@ int DatagramSocket::send(const struct sockaddr* dest, const char * message)
 | 
				
			|||||||
	return send(dest,message,length);
 | 
						return send(dest,message,length);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int DatagramSocket::read(char* buffer, size_t length)
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int DatagramSocket::read(char* buffer)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	socklen_t temp_len = sizeof(mSource);
 | 
						socklen_t addr_len = sizeof(mSource);
 | 
				
			||||||
	int length = recvfrom(mSocketFD, (void*)buffer, MAX_UDP_LENGTH, 0,
 | 
						int rd_length = recvfrom(mSocketFD, (void *) buffer, length, 0,
 | 
				
			||||||
	    (struct sockaddr*)&mSource,&temp_len);
 | 
							(struct sockaddr*) &mSource, &addr_len);
 | 
				
			||||||
	if ((length==-1) && (errno!=EAGAIN)) {
 | 
					
 | 
				
			||||||
 | 
						if ((rd_length==-1) && (errno!=EAGAIN)) {
 | 
				
			||||||
		perror("DatagramSocket::read() failed");
 | 
							perror("DatagramSocket::read() failed");
 | 
				
			||||||
		throw SocketError();
 | 
							throw SocketError();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return length;
 | 
						return rd_length;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int DatagramSocket::read(char* buffer, size_t length, unsigned timeout)
 | 
				
			||||||
int DatagramSocket::read(char* buffer, unsigned timeout)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	fd_set fds;
 | 
						fd_set fds;
 | 
				
			||||||
	FD_ZERO(&fds);
 | 
						FD_ZERO(&fds);
 | 
				
			||||||
@@ -218,7 +214,7 @@ int DatagramSocket::read(char* buffer, unsigned timeout)
 | 
				
			|||||||
		throw SocketError();
 | 
							throw SocketError();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (sel==0) return -1;
 | 
						if (sel==0) return -1;
 | 
				
			||||||
	if (FD_ISSET(mSocketFD,&fds)) return read(buffer);
 | 
						if (FD_ISSET(mSocketFD,&fds)) return read(buffer, length);
 | 
				
			||||||
	return -1;
 | 
						return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -269,7 +265,7 @@ void UDPSocket::open(unsigned short localPort)
 | 
				
			|||||||
	size_t length = sizeof(address);
 | 
						size_t length = sizeof(address);
 | 
				
			||||||
	bzero(&address,length);
 | 
						bzero(&address,length);
 | 
				
			||||||
	address.sin_family = AF_INET;
 | 
						address.sin_family = AF_INET;
 | 
				
			||||||
	address.sin_addr.s_addr = INADDR_ANY;
 | 
						address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 | 
				
			||||||
	address.sin_port = htons(localPort);
 | 
						address.sin_port = htons(localPort);
 | 
				
			||||||
	if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
 | 
						if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
 | 
				
			||||||
		perror("bind() failed");
 | 
							perror("bind() failed");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -108,7 +108,7 @@ public:
 | 
				
			|||||||
		@param buffer A char[MAX_UDP_LENGTH] procured by the caller.
 | 
							@param buffer A char[MAX_UDP_LENGTH] procured by the caller.
 | 
				
			||||||
		@return The number of bytes received or -1 on non-blocking pass.
 | 
							@return The number of bytes received or -1 on non-blocking pass.
 | 
				
			||||||
	*/
 | 
						*/
 | 
				
			||||||
	int read(char* buffer);
 | 
						int read(char* buffer, size_t length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
		Receive a packet with a timeout.
 | 
							Receive a packet with a timeout.
 | 
				
			||||||
@@ -116,7 +116,7 @@ public:
 | 
				
			|||||||
		@param maximum wait time in milliseconds
 | 
							@param maximum wait time in milliseconds
 | 
				
			||||||
		@return The number of bytes received or -1 on timeout.
 | 
							@return The number of bytes received or -1 on timeout.
 | 
				
			||||||
	*/
 | 
						*/
 | 
				
			||||||
	int read(char* buffer, unsigned timeout);
 | 
						int read(char* buffer, size_t length, unsigned timeout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Send a packet to a given destination, other than the default. */
 | 
						/** Send a packet to a given destination, other than the default. */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,7 +42,7 @@ void *testReaderIP(void *)
 | 
				
			|||||||
	int rc = 0;
 | 
						int rc = 0;
 | 
				
			||||||
	while (rc<gNumToSend) {
 | 
						while (rc<gNumToSend) {
 | 
				
			||||||
		char buf[MAX_UDP_LENGTH];
 | 
							char buf[MAX_UDP_LENGTH];
 | 
				
			||||||
		int count = readSocket.read(buf);
 | 
							int count = readSocket.read(buf, MAX_UDP_LENGTH);
 | 
				
			||||||
		if (count>0) {
 | 
							if (count>0) {
 | 
				
			||||||
			COUT("read: " << buf);
 | 
								COUT("read: " << buf);
 | 
				
			||||||
			rc++;
 | 
								rc++;
 | 
				
			||||||
@@ -62,7 +62,7 @@ void *testReaderUnix(void *)
 | 
				
			|||||||
	int rc = 0;
 | 
						int rc = 0;
 | 
				
			||||||
	while (rc<gNumToSend) {
 | 
						while (rc<gNumToSend) {
 | 
				
			||||||
		char buf[MAX_UDP_LENGTH];
 | 
							char buf[MAX_UDP_LENGTH];
 | 
				
			||||||
		int count = readSocket.read(buf);
 | 
							int count = readSocket.read(buf, MAX_UDP_LENGTH);
 | 
				
			||||||
		if (count>0) {
 | 
							if (count>0) {
 | 
				
			||||||
			COUT("read: " << buf);
 | 
								COUT("read: " << buf);
 | 
				
			||||||
			rc++;
 | 
								rc++;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -172,8 +172,15 @@ class Thread {
 | 
				
			|||||||
	void start(void *(*task)(void*), void *arg);
 | 
						void start(void *(*task)(void*), void *arg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Join a thread that will stop on its own. */
 | 
						/** Join a thread that will stop on its own. */
 | 
				
			||||||
	void join() { int s = pthread_join(mThread,NULL); assert(!s); mThread = 0; }
 | 
						void join() {
 | 
				
			||||||
 | 
							if (mThread) {
 | 
				
			||||||
 | 
								int s = pthread_join(mThread, NULL);
 | 
				
			||||||
 | 
								assert(!s);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Send cancelation to thread */
 | 
				
			||||||
 | 
						void cancel() { pthread_cancel(mThread); }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,10 +41,24 @@ const BitVector GSM::gTrainingSequence[] = {
 | 
				
			|||||||
    BitVector("11101111000100101110111100"),
 | 
					    BitVector("11101111000100101110111100"),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const BitVector GSM::gEdgeTrainingSequence[] = {
 | 
				
			||||||
 | 
					    BitVector("111111001111111001111001001001111111111111001111111111001111111001111001001001"),
 | 
				
			||||||
 | 
					    BitVector("111111001111001001111001001001111001001001001111111111001111001001111001001001"),
 | 
				
			||||||
 | 
					    BitVector("111001111111111111001001001111001001001111001111111001111111111111001001001111"),
 | 
				
			||||||
 | 
					    BitVector("111001111111111001001001001111001001111001111111111001111111111001001001001111"),
 | 
				
			||||||
 | 
					    BitVector("111111111001001111001111001001001111111001111111111111111001001111001111001001"),
 | 
				
			||||||
 | 
					    BitVector("111001111111001001001111001111001001111111111111111001111111001001001111001111"),
 | 
				
			||||||
 | 
					    BitVector("001111001111111001001001001001111001001111111111001111001111111001001001001001"),
 | 
				
			||||||
 | 
					    BitVector("001001001111001001001001111111111001111111001111001001001111001001001001111111"),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const BitVector GSM::gDummyBurst("0001111101101110110000010100100111000001001000100000001111100011100010111000101110001010111010010100011001100111001111010011111000100101111101010000");
 | 
					const BitVector GSM::gDummyBurst("0001111101101110110000010100100111000001001000100000001111100011100010111000101110001010111010010100011001100111001111010011111000100101111101010000");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const BitVector GSM::gRACHSynchSequence("01001011011111111001100110101010001111000");
 | 
					const BitVector GSM::gRACHSynchSequence("01001011011111111001100110101010001111000");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//                               |-head-||---------midamble----------------------||--------------data----------------||t|
 | 
				
			||||||
 | 
					const BitVector GSM::gRACHBurst("0011101001001011011111111001100110101010001111000110111101111110000111001001010110011000");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int32_t GSM::FNDelta(int32_t v1, int32_t v2)
 | 
					int32_t GSM::FNDelta(int32_t v1, int32_t v2)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,12 +46,15 @@ namespace GSM {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/** GSM Training sequences from GSM 05.02 5.2.3. */
 | 
					/** GSM Training sequences from GSM 05.02 5.2.3. */
 | 
				
			||||||
extern const BitVector gTrainingSequence[];
 | 
					extern const BitVector gTrainingSequence[];
 | 
				
			||||||
 | 
					extern const BitVector gEdgeTrainingSequence[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** C0T0 filler burst, GSM 05.02, 5.2.6 */
 | 
					/** C0T0 filler burst, GSM 05.02, 5.2.6 */
 | 
				
			||||||
extern const BitVector gDummyBurst;
 | 
					extern const BitVector gDummyBurst;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Random access burst synch. sequence */
 | 
					/** Random access burst synch. sequence */
 | 
				
			||||||
extern const BitVector gRACHSynchSequence;
 | 
					extern const BitVector gRACHSynchSequence;
 | 
				
			||||||
 | 
					/** Random access burst synch. sequence, GSM 05.02 5.2.7 */
 | 
				
			||||||
 | 
					extern const BitVector gRACHBurst;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**@name Modulus operations for frame numbers. */
 | 
					/**@name Modulus operations for frame numbers. */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										260
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										260
									
								
								README
									
									
									
									
									
								
							@@ -1,168 +1,116 @@
 | 
				
			|||||||
Welcome to the OpenBTS source code.
 | 
					This is the interface to the transcevier.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Each TRX Manager UDP socket interface represents a single ARFCN.
 | 
				
			||||||
For free support, please subscribe to openbts-discuss@lists.sourceforge.net.
 | 
					Each of these per-ARFCN interfaces is a pair of UDP sockets, one for control and one for data.
 | 
				
			||||||
See http://sourceforge.net/mailarchive/forum.php?forum_name=openbts-discuss
 | 
					Give a base port B (5700), the master clock interface is at port P=B.
 | 
				
			||||||
and https://lists.sourceforge.net/lists/listinfo/openbts-discuss for details.
 | 
					The TRX-side control interface for C(N) is on  port P=B+2N+1 and the data interface is on an odd numbered port P=B+2N+2.
 | 
				
			||||||
 | 
					The corresponding core-side interface for every socket is at P+100.
 | 
				
			||||||
For additional information, refer to http://openbts.org.
 | 
					For any given build, the number of ARFCN interfaces can be fixed.
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
These are the directories:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
AsteriskConfig	Asterisk configuration files for use with OpenBTS.
 | 
					 | 
				
			||||||
CommonLib	Common-use libraries, mostly C++ wrappers for basic facilities.
 | 
					 | 
				
			||||||
Control		Control-layer functions for the protocols of GSM 04.08 and SIP.
 | 
					 | 
				
			||||||
GSM		The GSM stack.
 | 
					 | 
				
			||||||
SIP		Components of the SIP state machines ued by the control layer.
 | 
					 | 
				
			||||||
SMS		The SMS stack.
 | 
					 | 
				
			||||||
SR		The subscriber registry.
 | 
					 | 
				
			||||||
TRXManager	The interface between the GSM stack and the radio.
 | 
					 | 
				
			||||||
Transceiver	The software transceiver and specific installation tests.
 | 
					 | 
				
			||||||
apps		OpenBTS application binaries.
 | 
					 | 
				
			||||||
doc		Project documentation.
 | 
					 | 
				
			||||||
tests		Test fixtures for subsets of OpenBTS components.
 | 
					 | 
				
			||||||
smqueue		RFC-3428 store-and-forward server for SMS
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
By default, OpenBTS assumes the following UDP port assignments:
 | 
					Indications on the Master Clock Interface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
5060 -- Asterisk SIP interface
 | 
					The master clock interface is output only (from the radio).
 | 
				
			||||||
5061 -- local SIP softphone
 | 
					Messages are "indications".
 | 
				
			||||||
5062 -- OpenBTS SIP interface
 | 
					 | 
				
			||||||
5063 -- smqueue SIP interface
 | 
					 | 
				
			||||||
5064 -- subscriber registry SIP interface
 | 
					 | 
				
			||||||
5700-range -- OpenBTS-transceiver interface
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
These can be controlled in the CONFIG table in /etc/OpenBTS.db.
 | 
					CLOCK gives the current value of the transceiver clock to be used by the core.
 | 
				
			||||||
 | 
					This message is sent whenever a trasmission packet arrives that is too late or too early.  The clock value is NOT the current transceiver time.  It is a time setting the the core should use to give better packet arrival times.
 | 
				
			||||||
 | 
					IND CLOCK <totalFrames>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Standrd paths:
 | 
					 | 
				
			||||||
/OpenBTS -- Binary installation.
 | 
					 | 
				
			||||||
/etc/OpenBTS -- Configuration databases.
 | 
					 | 
				
			||||||
/var/run/OpenBTS -- Real-time reporting databases.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
The script apps/setUpFiles.sh will create these directories and install the
 | 
					
 | 
				
			||||||
correct files in them.
 | 
					Commands on the Per-ARFCN Control Interface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The per-ARFCN control interface uses a command-reponse protocol.
 | 
				
			||||||
 | 
					Commands are NULL-terminated ASCII strings, one per UDP socket.
 | 
				
			||||||
 | 
					Each command has a corresponding response.
 | 
				
			||||||
 | 
					Every command is of the form:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CMD <cmdtype> [params]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The <cmdtype> is the actual command.
 | 
				
			||||||
 | 
					Parameters are optional depending on the commands type.
 | 
				
			||||||
 | 
					Every response is of the form:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RSP <cmdtype> <status> [result]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The <status> is 0 for success and a non-zero error code for failure.
 | 
				
			||||||
 | 
					Successful responses may include results, depending on the command type.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Power Control
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					POWEROFF shuts off transmitter power and stops the demodulator.
 | 
				
			||||||
 | 
					CMD POWEROFF
 | 
				
			||||||
 | 
					RSP POWEROFF <status>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					POWERON starts the transmitter and starts the demodulator.  Initial power level is very low.
 | 
				
			||||||
 | 
					This command fails if the transmitter and receiver are not yet tuned.
 | 
				
			||||||
 | 
					This command fails if the transmit or receive frequency creates a conflict with another ARFCN that is already runnng.
 | 
				
			||||||
 | 
					If the transceiver is already on, it response with success to this command.
 | 
				
			||||||
 | 
					CMD POWERON
 | 
				
			||||||
 | 
					RSP POWERON <status>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SETPOWER sets output power in dB wrt full scale.
 | 
				
			||||||
 | 
					This command fails if the transmitter and receiver are not running.
 | 
				
			||||||
 | 
					CMD SETPOWER <dB>
 | 
				
			||||||
 | 
					RSP SETPOWER <status> <dB>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ADJPOWER adjusts power by the given dB step.  Response returns resulting power level wrt full scale.
 | 
				
			||||||
 | 
					This command fails if the transmitter and receiver are not running.
 | 
				
			||||||
 | 
					CMD ADJPOWER <dBStep>
 | 
				
			||||||
 | 
					RSP ADJPOWER <status> <dBLevel>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Tuning Control
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RXTUNE tunes the receiver to a given frequency in kHz.
 | 
				
			||||||
 | 
					This command fails if the receiver is already running.
 | 
				
			||||||
 | 
					(To re-tune you stop the radio, re-tune, and restart.)
 | 
				
			||||||
 | 
					This command fails if the transmit or receive frequency creates a conflict with another ARFCN that is already runnng.
 | 
				
			||||||
 | 
					CMD RXTUNE <kHz>
 | 
				
			||||||
 | 
					RSP RXTUNE <status> <kHz>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TXTUNE tunes the transmitter to a given frequency in kHz.
 | 
				
			||||||
 | 
					This command fails if the transmitter is already running.
 | 
				
			||||||
 | 
					(To re-tune you stop the radio, re-tune, and restart.)
 | 
				
			||||||
 | 
					This command fails if the transmit or receive frequency creates a conflict with another ARFCN that is already runnng.
 | 
				
			||||||
 | 
					CMD TXTUNE <kHz>
 | 
				
			||||||
 | 
					RSP TXTUNE <status> <kHz>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Timeslot Control
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SETSLOT sets the format of the uplink timeslots in the ARFCN.
 | 
				
			||||||
 | 
					The <timeslot> indicates the timeslot of interest.
 | 
				
			||||||
 | 
					The <chantype> indicates the type of channel that occupies the timeslot.
 | 
				
			||||||
 | 
					A chantype of zero indicates the timeslot is off.
 | 
				
			||||||
 | 
					CMD SETSLOT <timeslot> <chantype>
 | 
				
			||||||
 | 
					RSP SETSLOT <status> <timeslot> <chantype>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Messages on the per-ARFCN Data Interface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Messages on the data interface carry one radio burst per UDP message.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Received Data Burst
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1 byte timeslot index
 | 
				
			||||||
 | 
					4 bytes GSM frame number, big endian
 | 
				
			||||||
 | 
					1 byte RSSI in -dBm
 | 
				
			||||||
 | 
					2 bytes correlator timing offset in 1/256 symbol steps, 2's-comp, big endian
 | 
				
			||||||
 | 
					148 bytes soft symbol estimates, 0 -> definite "0", 255 -> definite "1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Transmit Data Burst
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1 byte timeslot index
 | 
				
			||||||
 | 
					4 bytes GSM frame number, big endian
 | 
				
			||||||
 | 
					1 byte transmit level wrt ARFCN max, -dB (attenuation)
 | 
				
			||||||
 | 
					148 bytes output symbol values, 0 & 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Release history:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Release	Name		SVN Reposiory	SVN Rev	Comments
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
1.0	(none)		SF.net		??		completed L1, L2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
1.1	Arnaudville	GNU Radio	r10019 (trunk)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
1.2	Breaux Bridge	GNU Radio	r10088 (trunk)	GNU Build, very early assignment
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
1.3	Carencro	KSP		r1 (trunk)	first post-injunction release
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
1.4	Donaldsonville	KSP		r23 (trunk)	fixed Ubuntu build error
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
1.5	Eunice		KSP		r39 (trunk)	fixed L2 bugs related to segmentation
 | 
					 | 
				
			||||||
							removed incomplete SMS directory
 | 
					 | 
				
			||||||
							moved "abort" calls into L3 subclasses
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
1.6	New Iberia	KSP		r130 (trunk)	import of all 2.2 improvements to non-SMS release
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
2.0	St. Francisville KSP		r54 (smswork)	SMS support
 | 
					 | 
				
			||||||
							file-based configuration
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
2.1	Grand Coteau	KSP		r70 (smswork)	DTMF support
 | 
					 | 
				
			||||||
							fixed more Linux-related build errors
 | 
					 | 
				
			||||||
								-lpthread
 | 
					 | 
				
			||||||
								TLMessage constructor
 | 
					 | 
				
			||||||
							expanded stack to prevent overflows in Linux
 | 
					 | 
				
			||||||
							moved gSIPInterface to main app
 | 
					 | 
				
			||||||
							fixed iterator bug in Pager
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
2.2	Houma		KSP		r122 (smswork)	added LEGAL notice
 | 
					 | 
				
			||||||
							removed Assert classes
 | 
					 | 
				
			||||||
							stop paging on page response
 | 
					 | 
				
			||||||
							fixed Pager-spin bug
 | 
					 | 
				
			||||||
							fixed Transceiver spin bugs
 | 
					 | 
				
			||||||
							fixed 2^32 microsecond rollover bug
 | 
					 | 
				
			||||||
							reduced stack footprints in Transceiver
 | 
					 | 
				
			||||||
							fixed SMS timestamps
 | 
					 | 
				
			||||||
							check LAI before using TMSI in LUR
 | 
					 | 
				
			||||||
							reduced memory requirement by 75%
 | 
					 | 
				
			||||||
							removed PagerTest
 | 
					 | 
				
			||||||
							fixed stale-transaction bug in paging handler
 | 
					 | 
				
			||||||
							fixed USRP clock rollover bug
 | 
					 | 
				
			||||||
							faster call connection
 | 
					 | 
				
			||||||
							new USRPDevice design
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
2.3	Jean Lafitte	KSP		r190? (trunk)	check for out-of-date RACH bursts
 | 
					 | 
				
			||||||
							better TRX-GSM clock sync
 | 
					 | 
				
			||||||
							formal logging system
 | 
					 | 
				
			||||||
							command line interface
 | 
					 | 
				
			||||||
							emergency call setup
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
2.4	Kinder		KSP		r208? (trunk)	fixed BCCH neighbor list bug
 | 
					 | 
				
			||||||
							support for neighbor lists
 | 
					 | 
				
			||||||
							fixed support for non-local Asterisk servers
 | 
					 | 
				
			||||||
							cleaner configuration management
 | 
					 | 
				
			||||||
							more realtime control of BCCH parameters
 | 
					 | 
				
			||||||
							proper rejection of Hold messages
 | 
					 | 
				
			||||||
							fixed L3 hanging bug in MTDCheckBYE
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
2.4.1	Kinder		KSP		r462		fixed lots of valgrind errors
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
2.4.2	Kinder		KSP		r482		zero-length calling party number bug
 | 
					 | 
				
			||||||
							g++ 4.4 #includes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
2.5	Lacassine	KSP		r551		imported Joshua Lackey patches
 | 
					 | 
				
			||||||
							SIP fixes from Anne Kwong
 | 
					 | 
				
			||||||
							SIP fixes from testing with SMS server
 | 
					 | 
				
			||||||
							L3 TI handling fixes
 | 
					 | 
				
			||||||
							SMS server support
 | 
					 | 
				
			||||||
							GNU Radio 3.2 compatibility
 | 
					 | 
				
			||||||
							configurable max range and LU-reject cause
 | 
					 | 
				
			||||||
							"page" & "testcall" CLI features
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
2.5.1	Lacassine	KSP		r595		fixed some build bugs for some Linux distros
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
2.5.2	Lacassine	KSP		r630		fixed channel assignment bug for Nokia DCT4+ handsets
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
2.5.3	Lacassine	KSP		r756		merged fix for transceiver startup crash
 | 
					 | 
				
			||||||
								due to use of uninitialized variables (r646)
 | 
					 | 
				
			||||||
							merged fix for fusb bug from trunk (r582)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
2.5.4	Lacassine	KSP		r812		merged fixes to build under latest Fedora and
 | 
					 | 
				
			||||||
								to build with git GnuRadio (r814)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
2.6	Mamou		KSP		r886		fixed infamous fusb bug (r582)
 | 
					 | 
				
			||||||
							fixed idle-filling table size bug
 | 
					 | 
				
			||||||
							smoother uplink power control
 | 
					 | 
				
			||||||
							load-limiting downlink power control
 | 
					 | 
				
			||||||
							new "config" features (optional, static)
 | 
					 | 
				
			||||||
							IMEI interrogation
 | 
					 | 
				
			||||||
							fixed MOD "missing FIFO" bug
 | 
					 | 
				
			||||||
							configurable short code features
 | 
					 | 
				
			||||||
							fixed transceiver startup crash (r646)
 | 
					 | 
				
			||||||
							readline support is back
 | 
					 | 
				
			||||||
							fixed timing advance bug (r844)
 | 
					 | 
				
			||||||
							added CLI "chans" command
 | 
					 | 
				
			||||||
							track time-of-use in TMSI table (r844)
 | 
					 | 
				
			||||||
							added CLI "noise" command (r844)
 | 
					 | 
				
			||||||
							added CLI "rxpower" command (r844)
 | 
					 | 
				
			||||||
							added CLI "unconfig" command
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
2.7	Natchitoches	Range	rxxx			(never released publicly)
 | 
					 | 
				
			||||||
							converted TMSITable to sqlite3 (r902)
 | 
					 | 
				
			||||||
							sqlite3-based configuration (r???)
 | 
					 | 
				
			||||||
							converted Logger to syslogd (r903)
 | 
					 | 
				
			||||||
							added support for rest octets (r1022)
 | 
					 | 
				
			||||||
							external database for transaction reporting (r1184)
 | 
					 | 
				
			||||||
							external database for channel status reporting (r1203)
 | 
					 | 
				
			||||||
							in-call delivery and submission of text messages (r1231)
 | 
					 | 
				
			||||||
							RFC-2833 DMTF (r1249)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
2.8	Opelousas	Range	rxxx			move databases to /etc and /var
 | 
					 | 
				
			||||||
							RRLP aiding support
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -175,8 +175,13 @@ int Resampler::rotate(float *in, size_t in_len, float *out, size_t out_len)
 | 
				
			|||||||
	if (!check_vec_len(in_len, out_len, p, q))
 | 
						if (!check_vec_len(in_len, out_len, p, q))
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Insert history */
 | 
						if (history_on) {
 | 
				
			||||||
	memcpy(&in[-2 * hist_len], history, hist_len * 2 * sizeof(float));
 | 
							memcpy(&in[-2 * hist_len],
 | 
				
			||||||
 | 
							       history, hist_len * 2 * sizeof(float));
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							memset(&in[-2 * hist_len], 0,
 | 
				
			||||||
 | 
							       hist_len * 2 * sizeof(float));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Generate output from precomputed input/output paths */
 | 
						/* Generate output from precomputed input/output paths */
 | 
				
			||||||
	for (size_t i = 0; i < out_len; i++) {
 | 
						for (size_t i = 0; i < out_len; i++) {
 | 
				
			||||||
@@ -190,8 +195,10 @@ int Resampler::rotate(float *in, size_t in_len, float *out, size_t out_len)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Save history */
 | 
						/* Save history */
 | 
				
			||||||
 | 
						if (history_on) {
 | 
				
			||||||
		memcpy(history, &in[2 * (in_len - hist_len)],
 | 
							memcpy(history, &in[2 * (in_len - hist_len)],
 | 
				
			||||||
		       hist_len * 2 * sizeof(float));
 | 
							       hist_len * 2 * sizeof(float));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return out_len;
 | 
						return out_len;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -221,8 +228,14 @@ size_t Resampler::len()
 | 
				
			|||||||
	return filt_len;
 | 
						return filt_len;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Resampler::enableHistory(bool on)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						history_on = on;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Resampler::Resampler(size_t p, size_t q, size_t filt_len)
 | 
					Resampler::Resampler(size_t p, size_t q, size_t filt_len)
 | 
				
			||||||
	: in_index(NULL), out_path(NULL), partitions(NULL), history(NULL)
 | 
						: in_index(NULL), out_path(NULL), partitions(NULL),
 | 
				
			||||||
 | 
						  history(NULL), history_on(true)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	this->p = p;
 | 
						this->p = p;
 | 
				
			||||||
	this->q = q;
 | 
						this->q = q;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,6 +59,11 @@ public:
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	size_t len();
 | 
						size_t len();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Enable/disable history 
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void enableHistory(bool on);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	size_t p;
 | 
						size_t p;
 | 
				
			||||||
	size_t q;
 | 
						size_t q;
 | 
				
			||||||
@@ -68,6 +73,7 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	float **partitions;
 | 
						float **partitions;
 | 
				
			||||||
	float *history;
 | 
						float *history;
 | 
				
			||||||
 | 
						bool history_on;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool initFilters(float bw);
 | 
						bool initFilters(float bw);
 | 
				
			||||||
	void releaseFilters();
 | 
						void releaseFilters();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,6 +22,8 @@
 | 
				
			|||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <iomanip>      // std::setprecision
 | 
				
			||||||
 | 
					#include <fstream>
 | 
				
			||||||
#include "Transceiver.h"
 | 
					#include "Transceiver.h"
 | 
				
			||||||
#include <Logger.h>
 | 
					#include <Logger.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -43,7 +45,7 @@ using namespace GSM;
 | 
				
			|||||||
#define NOISE_CNT			20
 | 
					#define NOISE_CNT			20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TransceiverState::TransceiverState()
 | 
					TransceiverState::TransceiverState()
 | 
				
			||||||
  : mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT)
 | 
					  : mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT), mPower(0.0)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  for (int i = 0; i < 8; i++) {
 | 
					  for (int i = 0; i < 8; i++) {
 | 
				
			||||||
    chanType[i] = Transceiver::NONE;
 | 
					    chanType[i] = Transceiver::NONE;
 | 
				
			||||||
@@ -69,41 +71,60 @@ TransceiverState::~TransceiverState()
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TransceiverState::init(size_t slot, signalVector *burst, bool fill)
 | 
					bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  signalVector *filler;
 | 
					  signalVector *burst;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (int i = 0; i < 102; i++) {
 | 
					  if ((sps != 1) && (sps != 4))
 | 
				
			||||||
    if (fill)
 | 
					    return false;
 | 
				
			||||||
      filler = new signalVector(*burst);
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      filler = new signalVector(burst->size());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fillerTable[i][slot] = filler;
 | 
					  for (size_t n = 0; n < 8; n++) {
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < 102; i++) {
 | 
				
			||||||
 | 
					      switch (filler) {
 | 
				
			||||||
 | 
					      case Transceiver::FILLER_DUMMY:
 | 
				
			||||||
 | 
					        burst = generateDummyBurst(sps, n);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case Transceiver::FILLER_NORM_RAND:
 | 
				
			||||||
 | 
					        burst = genRandNormalBurst(rtsc, sps, n);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case Transceiver::FILLER_EDGE_RAND:
 | 
				
			||||||
 | 
					        burst = generateEdgeBurst(rtsc);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case Transceiver::FILLER_ACCESS_RAND:
 | 
				
			||||||
 | 
					        burst = genRandAccessBurst(sps, n);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case Transceiver::FILLER_ZERO:
 | 
				
			||||||
 | 
					      default:
 | 
				
			||||||
 | 
					        burst = generateEmptyBurst(sps, n);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      scaleVector(*burst, scale);
 | 
				
			||||||
 | 
					      fillerTable[i][n] = burst;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((filler == Transceiver::FILLER_NORM_RAND) ||
 | 
				
			||||||
 | 
					        (filler == Transceiver::FILLER_EDGE_RAND)) {
 | 
				
			||||||
 | 
					        chanType[n] = Transceiver::TSC;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Transceiver::Transceiver(int wBasePort,
 | 
					Transceiver::Transceiver(int wBasePort,
 | 
				
			||||||
			 const char *TRXAddress,
 | 
					                         const char *wTRXAddress,
 | 
				
			||||||
			 size_t wSPS, size_t wChans,
 | 
					                         size_t tx_sps, size_t rx_sps, size_t chans,
 | 
				
			||||||
                         GSM::Time wTransmitLatency,
 | 
					                         GSM::Time wTransmitLatency,
 | 
				
			||||||
			 RadioInterface *wRadioInterface)
 | 
					                         RadioInterface *wRadioInterface,
 | 
				
			||||||
  : mBasePort(wBasePort), mAddr(TRXAddress),
 | 
					                         double wRssiOffset)
 | 
				
			||||||
    mTransmitLatency(wTransmitLatency), mClockSocket(NULL),
 | 
					  : mBasePort(wBasePort), mAddr(wTRXAddress),
 | 
				
			||||||
    mRadioInterface(wRadioInterface), mSPSTx(wSPS), mSPSRx(1), mChans(wChans),
 | 
					    mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
 | 
				
			||||||
    mOn(false), mTxFreq(0.0), mRxFreq(0.0), mPower(-10), mMaxExpectedDelay(0),
 | 
					    mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
 | 
				
			||||||
    mTSC(0)
 | 
					    rssiOffset(wRssiOffset),
 | 
				
			||||||
 | 
					    mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mOn(false),
 | 
				
			||||||
 | 
					    mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelayAB(0), mMaxExpectedDelayNB(0),
 | 
				
			||||||
 | 
					    mWriteBurstToDiskMask(0)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  GSM::Time startTime(random() % gHyperframe,0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  mRxLowerLoopThread = new Thread(32768);
 | 
					 | 
				
			||||||
  mTxLowerLoopThread = new Thread(32768);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  mTransmitDeadlineClock = startTime;
 | 
					 | 
				
			||||||
  mLastClockUpdateTime = startTime;
 | 
					 | 
				
			||||||
  mLatencyUpdateTime = startTime;
 | 
					 | 
				
			||||||
  mRadioInterface->getClock()->set(startTime);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  txFullScale = mRadioInterface->fullScaleInputValue();
 | 
					  txFullScale = mRadioInterface->fullScaleInputValue();
 | 
				
			||||||
  rxFullScale = mRadioInterface->fullScaleOutputValue();
 | 
					  rxFullScale = mRadioInterface->fullScaleOutputValue();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -111,40 +132,50 @@ Transceiver::Transceiver(int wBasePort,
 | 
				
			|||||||
    for (int j = 0; j < 8; j++)
 | 
					    for (int j = 0; j < 8; j++)
 | 
				
			||||||
      mHandover[i][j] = false;
 | 
					      mHandover[i][j] = false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Transceiver::~Transceiver()
 | 
					Transceiver::~Transceiver()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					  stop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  sigProcLibDestroy();
 | 
					  sigProcLibDestroy();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  delete mClockSocket;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (size_t i = 0; i < mChans; i++) {
 | 
					  for (size_t i = 0; i < mChans; i++) {
 | 
				
			||||||
 | 
					    mControlServiceLoopThreads[i]->cancel();
 | 
				
			||||||
 | 
					    mControlServiceLoopThreads[i]->join();
 | 
				
			||||||
 | 
					    delete mControlServiceLoopThreads[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mTxPriorityQueues[i].clear();
 | 
					    mTxPriorityQueues[i].clear();
 | 
				
			||||||
    delete mCtrlSockets[i];
 | 
					    delete mCtrlSockets[i];
 | 
				
			||||||
    delete mDataSockets[i];
 | 
					    delete mDataSockets[i];
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Transceiver::init(bool filler)
 | 
					/*
 | 
				
			||||||
 | 
					 * Initialize transceiver
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Start or restart the control loop. Any further control is handled through the
 | 
				
			||||||
 | 
					 * socket API. Randomize the central radio clock set the downlink burst
 | 
				
			||||||
 | 
					 * counters. Note that the clock will not update until the radio starts, but we
 | 
				
			||||||
 | 
					 * are still expected to report clock indications through control channel
 | 
				
			||||||
 | 
					 * activity.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool Transceiver::init(int filler, size_t rtsc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  int d_srcport, d_dstport, c_srcport, c_dstport;
 | 
					  int d_srcport, d_dstport, c_srcport, c_dstport;
 | 
				
			||||||
  signalVector *burst;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!mChans) {
 | 
					  if (!mChans) {
 | 
				
			||||||
    LOG(ALERT) << "No channels assigned";
 | 
					    LOG(ALERT) << "No channels assigned";
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!sigProcLibSetup(mSPSTx)) {
 | 
					  if (!sigProcLibSetup()) {
 | 
				
			||||||
    LOG(ALERT) << "Failed to initialize signal processing library";
 | 
					    LOG(ALERT) << "Failed to initialize signal processing library";
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  mDataSockets.resize(mChans);
 | 
					  mDataSockets.resize(mChans);
 | 
				
			||||||
  mCtrlSockets.resize(mChans);
 | 
					  mCtrlSockets.resize(mChans);
 | 
				
			||||||
 | 
					 | 
				
			||||||
  mControlServiceLoopThreads.resize(mChans);
 | 
					  mControlServiceLoopThreads.resize(mChans);
 | 
				
			||||||
  mTxPriorityQueueServiceLoopThreads.resize(mChans);
 | 
					  mTxPriorityQueueServiceLoopThreads.resize(mChans);
 | 
				
			||||||
  mRxServiceLoopThreads.resize(mChans);
 | 
					  mRxServiceLoopThreads.resize(mChans);
 | 
				
			||||||
@@ -154,11 +185,10 @@ bool Transceiver::init(bool filler)
 | 
				
			|||||||
  mStates.resize(mChans);
 | 
					  mStates.resize(mChans);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Filler table retransmissions - support only on channel 0 */
 | 
					  /* Filler table retransmissions - support only on channel 0 */
 | 
				
			||||||
  if (filler)
 | 
					  if (filler == FILLER_DUMMY)
 | 
				
			||||||
    mStates[0].mRetrans = true;
 | 
					    mStates[0].mRetrans = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  mClockSocket = new UDPSocket(mBasePort, mAddr.c_str(), mBasePort + 100);
 | 
					  /* Setup sockets */
 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (size_t i = 0; i < mChans; i++) {
 | 
					  for (size_t i = 0; i < mChans; i++) {
 | 
				
			||||||
    c_srcport = mBasePort + 2 * i + 1;
 | 
					    c_srcport = mBasePort + 2 * i + 1;
 | 
				
			||||||
    c_dstport = mBasePort + 2 * i + 101;
 | 
					    c_dstport = mBasePort + 2 * i + 101;
 | 
				
			||||||
@@ -169,22 +199,129 @@ bool Transceiver::init(bool filler)
 | 
				
			|||||||
    mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
 | 
					    mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (size_t i = 0; i < mChans; i++) {
 | 
					  /* Randomize the central clock */
 | 
				
			||||||
    mControlServiceLoopThreads[i] = new Thread(32768);
 | 
					  GSM::Time startTime(random() % gHyperframe, 0);
 | 
				
			||||||
    mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
 | 
					  mRadioInterface->getClock()->set(startTime);
 | 
				
			||||||
    mRxServiceLoopThreads[i] = new Thread(32768);
 | 
					  mTransmitDeadlineClock = startTime;
 | 
				
			||||||
 | 
					  mLastClockUpdateTime = startTime;
 | 
				
			||||||
 | 
					  mLatencyUpdateTime = startTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (size_t n = 0; n < 8; n++) {
 | 
					  /* Start control threads */
 | 
				
			||||||
      burst = modulateBurst(gDummyBurst, 8 + (n % 4 == 0), mSPSTx);
 | 
					  for (size_t i = 0; i < mChans; i++) {
 | 
				
			||||||
      scaleVector(*burst, txFullScale);
 | 
					    TransceiverChannel *chan = new TransceiverChannel(this, i);
 | 
				
			||||||
      mStates[i].init(n, burst, filler && !i);
 | 
					    mControlServiceLoopThreads[i] = new Thread(32768);
 | 
				
			||||||
      delete burst;
 | 
					    mControlServiceLoopThreads[i]->start((void * (*)(void*))
 | 
				
			||||||
    }
 | 
					                                 ControlServiceLoopAdapter, (void*) chan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (i && filler == FILLER_DUMMY)
 | 
				
			||||||
 | 
					      filler = FILLER_ZERO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mStates[i].init(filler, mSPSTx, txFullScale, rtsc);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Start the transceiver
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Submit command(s) to the radio device to commence streaming samples and
 | 
				
			||||||
 | 
					 * launch threads to handle sample I/O. Re-synchronize the transmit burst
 | 
				
			||||||
 | 
					 * counters to the central radio clock here as well.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool Transceiver::start()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  ScopedLock lock(mLock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (mOn) {
 | 
				
			||||||
 | 
					    LOG(ERR) << "Transceiver already running";
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  LOG(NOTICE) << "Starting the transceiver";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  GSM::Time time = mRadioInterface->getClock()->get();
 | 
				
			||||||
 | 
					  mTransmitDeadlineClock = time;
 | 
				
			||||||
 | 
					  mLastClockUpdateTime = time;
 | 
				
			||||||
 | 
					  mLatencyUpdateTime = time;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!mRadioInterface->start()) {
 | 
				
			||||||
 | 
					    LOG(ALERT) << "Device failed to start";
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Device is running - launch I/O threads */
 | 
				
			||||||
 | 
					  mRxLowerLoopThread = new Thread(32768);
 | 
				
			||||||
 | 
					  mTxLowerLoopThread = new Thread(32768);
 | 
				
			||||||
 | 
					  mTxLowerLoopThread->start((void * (*)(void*))
 | 
				
			||||||
 | 
					                            TxLowerLoopAdapter,(void*) this);
 | 
				
			||||||
 | 
					  mRxLowerLoopThread->start((void * (*)(void*))
 | 
				
			||||||
 | 
					                            RxLowerLoopAdapter,(void*) this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Launch uplink and downlink burst processing threads */
 | 
				
			||||||
 | 
					  for (size_t i = 0; i < mChans; i++) {
 | 
				
			||||||
 | 
					    TransceiverChannel *chan = new TransceiverChannel(this, i);
 | 
				
			||||||
 | 
					    mRxServiceLoopThreads[i] = new Thread(32768);
 | 
				
			||||||
 | 
					    mRxServiceLoopThreads[i]->start((void * (*)(void*))
 | 
				
			||||||
 | 
					                            RxUpperLoopAdapter, (void*) chan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    chan = new TransceiverChannel(this, i);
 | 
				
			||||||
 | 
					    mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
 | 
				
			||||||
 | 
					    mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
 | 
				
			||||||
 | 
					                            TxUpperLoopAdapter, (void*) chan);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  writeClockInterface();
 | 
				
			||||||
 | 
					  mOn = true;
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Stop the transceiver
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Perform stopping by disabling receive streaming and issuing cancellation
 | 
				
			||||||
 | 
					 * requests to running threads. Most threads will timeout and terminate once
 | 
				
			||||||
 | 
					 * device is disabled, but the transmit loop may block waiting on the central
 | 
				
			||||||
 | 
					 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
 | 
				
			||||||
 | 
					 * makes it to the thread cancellation point.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void Transceiver::stop()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  ScopedLock lock(mLock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!mOn)
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  LOG(NOTICE) << "Stopping the transceiver";
 | 
				
			||||||
 | 
					  mTxLowerLoopThread->cancel();
 | 
				
			||||||
 | 
					  mRxLowerLoopThread->cancel();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (size_t i = 0; i < mChans; i++) {
 | 
				
			||||||
 | 
					    mRxServiceLoopThreads[i]->cancel();
 | 
				
			||||||
 | 
					    mTxPriorityQueueServiceLoopThreads[i]->cancel();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  LOG(INFO) << "Stopping the device";
 | 
				
			||||||
 | 
					  mRadioInterface->stop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (size_t i = 0; i < mChans; i++) {
 | 
				
			||||||
 | 
					    mRxServiceLoopThreads[i]->join();
 | 
				
			||||||
 | 
					    mTxPriorityQueueServiceLoopThreads[i]->join();
 | 
				
			||||||
 | 
					    delete mRxServiceLoopThreads[i];
 | 
				
			||||||
 | 
					    delete mTxPriorityQueueServiceLoopThreads[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mTxPriorityQueues[i].clear();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mTxLowerLoopThread->join();
 | 
				
			||||||
 | 
					  mRxLowerLoopThread->join();
 | 
				
			||||||
 | 
					  delete mTxLowerLoopThread;
 | 
				
			||||||
 | 
					  delete mRxLowerLoopThread;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mOn = false;
 | 
				
			||||||
 | 
					  LOG(NOTICE) << "Transceiver stopped";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Transceiver::addRadioVector(size_t chan, BitVector &bits,
 | 
					void Transceiver::addRadioVector(size_t chan, BitVector &bits,
 | 
				
			||||||
                                 int RSSI, GSM::Time &wTime)
 | 
					                                 int RSSI, GSM::Time &wTime)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -201,7 +338,12 @@ void Transceiver::addRadioVector(size_t chan, BitVector &bits,
 | 
				
			|||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Use the number of bits as the EDGE burst indicator */
 | 
				
			||||||
 | 
					  if (bits.size() == EDGE_BURST_NBITS)
 | 
				
			||||||
 | 
					    burst = modulateEdgeBurst(bits, mSPSTx);
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
    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));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  radio_burst = new radioVector(wTime, burst);
 | 
					  radio_burst = new radioVector(wTime, burst);
 | 
				
			||||||
@@ -302,15 +444,15 @@ void Transceiver::setModulus(size_t timeslot, size_t chan)
 | 
				
			|||||||
Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
 | 
					Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
 | 
				
			||||||
                                                    size_t chan)
 | 
					                                                    size_t 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 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,
 | 
					  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 };
 | 
					                                     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,
 | 
					  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 };
 | 
					                                     1,1,1,1,2,2,2,2,3,3,3,3,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,4,4,4,4 };
 | 
				
			||||||
 
 | 
					  TransceiverState *state = &mStates[chan];
 | 
				
			||||||
  unsigned burstTN = currTime.TN();
 | 
					  unsigned burstTN = currTime.TN();
 | 
				
			||||||
  unsigned burstFN = currTime.FN();
 | 
					  unsigned burstFN = currTime.FN();
 | 
				
			||||||
 | 
					  int subch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  switch (state->chanType[burstTN]) {
 | 
					  switch (state->chanType[burstTN]) {
 | 
				
			||||||
  case NONE:
 | 
					  case NONE:
 | 
				
			||||||
@@ -320,19 +462,24 @@ Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
 | 
				
			|||||||
    return IDLE;
 | 
					    return IDLE;
 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
  case I:
 | 
					  case I:
 | 
				
			||||||
 | 
					    // TODO: Are we expecting RACH on an IDLE frame?
 | 
				
			||||||
 | 
					/*    if (burstFN % 26 == 25)
 | 
				
			||||||
 | 
					      return IDLE;*/
 | 
				
			||||||
    if (mHandover[burstTN][0])
 | 
					    if (mHandover[burstTN][0])
 | 
				
			||||||
      return RACH;
 | 
					      return RACH;
 | 
				
			||||||
    return TSC;
 | 
					    return TSC;
 | 
				
			||||||
    /*if (burstFN % 26 == 25) 
 | 
					 | 
				
			||||||
      return IDLE;
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      return TSC;*/
 | 
					 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
  case II:
 | 
					  case II:
 | 
				
			||||||
 | 
					    subch = tchh_subslot[burstFN % 26];
 | 
				
			||||||
 | 
					    if (subch == 1)
 | 
				
			||||||
 | 
					      return IDLE;
 | 
				
			||||||
 | 
					    if (mHandover[burstTN][0])
 | 
				
			||||||
 | 
					      return RACH;
 | 
				
			||||||
    return TSC;
 | 
					    return TSC;
 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
  case III:
 | 
					  case III:
 | 
				
			||||||
    if (mHandover[burstTN][tchh_subslot[burstFN % 26]])
 | 
					    subch = tchh_subslot[burstFN % 26];
 | 
				
			||||||
 | 
					    if (mHandover[burstTN][subch])
 | 
				
			||||||
      return RACH;
 | 
					      return RACH;
 | 
				
			||||||
    return TSC;
 | 
					    return TSC;
 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
@@ -384,104 +531,77 @@ Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 
 | 
					int Transceiver::detectBurst(signalVector &burst,
 | 
				
			||||||
 * Detect RACH synchronization sequence within a burst. No equalization
 | 
					                             complex &, float &toa, CorrType type)
 | 
				
			||||||
 * is used or available on the RACH channel.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
bool Transceiver::detectRACH(TransceiverState *state,
 | 
					 | 
				
			||||||
                             signalVector &burst,
 | 
					 | 
				
			||||||
                             complex &, float &toa)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  float threshold = 6.0;
 | 
					  float threshold = 5.0, rc = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return detectRACHBurst(burst, threshold, mSPSRx, &, &toa);
 | 
					  switch (type) {
 | 
				
			||||||
 | 
					  case EDGE:
 | 
				
			||||||
 | 
					    rc = detectEdgeBurst(burst, mTSC, threshold, mSPSRx,
 | 
				
			||||||
 | 
					                         amp, toa, mMaxExpectedDelayNB);
 | 
				
			||||||
 | 
					    if (rc > 0)
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      type = TSC;
 | 
				
			||||||
 | 
					  case TSC:
 | 
				
			||||||
 | 
					    rc = analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx,
 | 
				
			||||||
 | 
					                             amp, toa, mMaxExpectedDelayNB);
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  case RACH:
 | 
				
			||||||
 | 
					    threshold = 6.0;
 | 
				
			||||||
 | 
					    rc = detectRACHBurst(burst, threshold, mSPSRx, amp, toa,
 | 
				
			||||||
 | 
					                         mMaxExpectedDelayAB);
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  default:
 | 
				
			||||||
 | 
					    LOG(ERR) << "Invalid correlation type";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (rc > 0)
 | 
				
			||||||
 | 
					    return type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Detect normal burst training sequence midamble. Update equalization
 | 
					 * Demodulate GMSK by direct rotation and soft slicing.
 | 
				
			||||||
 * state information and channel estimate if necessary. Equalization
 | 
					 | 
				
			||||||
 * is currently disabled.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
 | 
					SoftVector *Transceiver::demodulate(signalVector &burst, complex amp,
 | 
				
			||||||
                            complex &, float &toa, GSM::Time &time)
 | 
					                                    float toa, CorrType type)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  int tn = time.TN();
 | 
					  if (type == EDGE)
 | 
				
			||||||
  float chanOffset, threshold = 5.0;
 | 
						  return demodEdgeBurst(burst, mSPSRx, amp, toa);
 | 
				
			||||||
  bool noise, needDFE = false, estimateChan = false;
 | 
					 | 
				
			||||||
  double elapsed = time - state->chanEstimateTime[tn];
 | 
					 | 
				
			||||||
  signalVector *chanResp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* Check equalization update state */
 | 
					 | 
				
			||||||
  if (needDFE && ((elapsed > 50) || (!state->chanResponse[tn]))) {
 | 
					 | 
				
			||||||
    delete state->DFEForward[tn];
 | 
					 | 
				
			||||||
    delete state->DFEFeedback[tn];
 | 
					 | 
				
			||||||
    state->DFEForward[tn] = NULL;
 | 
					 | 
				
			||||||
    state->DFEFeedback[tn] = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    estimateChan = true;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* Detect normal burst midambles */
 | 
					 | 
				
			||||||
  if (!analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, &,
 | 
					 | 
				
			||||||
                           &toa, mMaxExpectedDelay, estimateChan,
 | 
					 | 
				
			||||||
                           &chanResp, &chanOffset)) {
 | 
					 | 
				
			||||||
    return false;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  noise = state->mNoiseLev;
 | 
					 | 
				
			||||||
  state->SNRestimate[tn] = amp.norm2() / (noise * noise + 1.0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* Set equalizer if unabled */
 | 
					 | 
				
			||||||
  if (needDFE && estimateChan) {
 | 
					 | 
				
			||||||
     state->chanResponse[tn] = chanResp;
 | 
					 | 
				
			||||||
     state->chanRespOffset[tn] = chanOffset;
 | 
					 | 
				
			||||||
     state->chanRespAmplitude[tn] = amp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     scaleVector(*chanResp, complex(1.0, 0.0) / amp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     designDFE(*chanResp, state->SNRestimate[tn],
 | 
					 | 
				
			||||||
               7, &state->DFEForward[tn], &state->DFEFeedback[tn]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     state->chanEstimateTime[tn] = time;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return true;;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Demodulate GMSK burst using equalization if requested. Otherwise
 | 
					 | 
				
			||||||
 * demodulate by direct rotation and soft slicing.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
SoftVector *Transceiver::demodulate(TransceiverState *state,
 | 
					 | 
				
			||||||
                                    signalVector &burst, complex amp,
 | 
					 | 
				
			||||||
                                    float toa, size_t tn, bool equalize)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  if (equalize) {
 | 
					 | 
				
			||||||
    scaleVector(burst, complex(1.0, 0.0) / amp);
 | 
					 | 
				
			||||||
    return equalizeBurst(burst,
 | 
					 | 
				
			||||||
                         toa - state->chanRespOffset[tn],
 | 
					 | 
				
			||||||
                         mSPSRx,
 | 
					 | 
				
			||||||
                         *state->DFEForward[tn],
 | 
					 | 
				
			||||||
                         *state->DFEFeedback[tn]);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return demodulateBurst(burst, mSPSRx, amp, toa);
 | 
					  return demodulateBurst(burst, mSPSRx, amp, toa);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void writeToFile(radioVector *radio_burst, size_t chan)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  GSM::Time time = radio_burst->getTime();
 | 
				
			||||||
 | 
					  std::ostringstream fname;
 | 
				
			||||||
 | 
					  fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
 | 
				
			||||||
 | 
					  std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
 | 
				
			||||||
 | 
					  outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
 | 
				
			||||||
 | 
					  outfile.close();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Pull bursts from the FIFO and handle according to the slot
 | 
					 * Pull bursts from the FIFO and handle according to the slot
 | 
				
			||||||
 * and burst correlation type. Equalzation is currently disabled. 
 | 
					 * and burst correlation type. Equalzation is currently disabled. 
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
 | 
					SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
 | 
				
			||||||
                                         int &timingOffset, size_t chan)
 | 
					                                         double &timingOffset, double &noise,
 | 
				
			||||||
 | 
					                                         size_t chan)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  bool success, equalize = false;
 | 
					  int rc;
 | 
				
			||||||
  complex amp;
 | 
					  complex amp;
 | 
				
			||||||
  float toa, pow, max = -1.0, avg = 0.0;
 | 
					  float toa, pow, max = -1.0, avg = 0.0;
 | 
				
			||||||
  int max_i = -1;
 | 
					  int max_i = -1;
 | 
				
			||||||
  signalVector *burst;
 | 
					  signalVector *burst;
 | 
				
			||||||
  SoftVector *bits = NULL;
 | 
					  SoftVector *bits = NULL;
 | 
				
			||||||
  TransceiverState *state = &mStates[chan];
 | 
					  TransceiverState *state = &mStates[chan];
 | 
				
			||||||
 | 
					  isRssiValid = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Blocking FIFO read */
 | 
					  /* Blocking FIFO read */
 | 
				
			||||||
  radioVector *radio_burst = mReceiveFIFO[chan]->read();
 | 
					  radioVector *radio_burst = mReceiveFIFO[chan]->read();
 | 
				
			||||||
@@ -492,7 +612,15 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
 | 
				
			|||||||
  GSM::Time time = radio_burst->getTime();
 | 
					  GSM::Time time = radio_burst->getTime();
 | 
				
			||||||
  CorrType type = expectedCorrType(time, chan);
 | 
					  CorrType type = expectedCorrType(time, chan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if ((type == OFF) || (type == IDLE)) {
 | 
					  /* Debug: dump bursts to disk */
 | 
				
			||||||
 | 
					  /* bits 0-7  - chan 0 timeslots
 | 
				
			||||||
 | 
					   * bits 8-15 - chan 1 timeslots */
 | 
				
			||||||
 | 
					  if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
 | 
				
			||||||
 | 
					    writeToFile(radio_burst, chan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* No processing if the timeslot is off.
 | 
				
			||||||
 | 
					   * Not even power level or noise calculation. */
 | 
				
			||||||
 | 
					  if (type == OFF) {
 | 
				
			||||||
    delete radio_burst;
 | 
					    delete radio_burst;
 | 
				
			||||||
    return NULL;
 | 
					    return NULL;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -516,55 +644,50 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
 | 
				
			|||||||
  /* Average noise on diversity paths and update global levels */
 | 
					  /* Average noise on diversity paths and update global levels */
 | 
				
			||||||
  burst = radio_burst->getVector(max_i);
 | 
					  burst = radio_burst->getVector(max_i);
 | 
				
			||||||
  avg = sqrt(avg / radio_burst->chans());
 | 
					  avg = sqrt(avg / radio_burst->chans());
 | 
				
			||||||
  state->mNoiseLev = state->mNoises.avg();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* Detect normal or RACH bursts */
 | 
					 | 
				
			||||||
  if (type == TSC)
 | 
					 | 
				
			||||||
    success = detectTSC(state, *burst, amp, toa, time);
 | 
					 | 
				
			||||||
  else
 | 
					 | 
				
			||||||
    success = detectRACH(state, *burst, amp, toa);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (success == 0) {
 | 
					 | 
				
			||||||
    state->mNoises.insert(avg);
 | 
					 | 
				
			||||||
    delete radio_burst;
 | 
					 | 
				
			||||||
    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 */
 | 
					 | 
				
			||||||
  if (equalize && (type != TSC))
 | 
					 | 
				
			||||||
    equalize = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (avg - state->mNoiseLev > 0.0)
 | 
					 | 
				
			||||||
    bits = demodulate(state, *burst, amp, toa, time.TN(), equalize);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  wTime = time;
 | 
					  wTime = time;
 | 
				
			||||||
  RSSI = (int) floor(20.0 * log10(rxFullScale / avg));
 | 
					  RSSI = 20.0 * log10(rxFullScale / avg);
 | 
				
			||||||
  timingOffset = (int) round(toa * 256.0 / mSPSRx);
 | 
					
 | 
				
			||||||
 | 
					  /* RSSI estimation are valid */
 | 
				
			||||||
 | 
					  isRssiValid = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (type == IDLE) {
 | 
				
			||||||
 | 
					    /* Update noise levels */
 | 
				
			||||||
 | 
					    state->mNoises.insert(avg);
 | 
				
			||||||
 | 
					    state->mNoiseLev = state->mNoises.avg();
 | 
				
			||||||
 | 
					    noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    delete radio_burst;
 | 
					    delete radio_burst;
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    /* Do not update noise levels */
 | 
				
			||||||
 | 
					    noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Detect normal or RACH bursts */
 | 
				
			||||||
 | 
					  rc = detectBurst(*burst, amp, toa, type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (rc > 0) {
 | 
				
			||||||
 | 
					    type = (CorrType) rc;
 | 
				
			||||||
 | 
					  } else if (rc <= 0) {
 | 
				
			||||||
 | 
					    if (rc == -SIGERR_CLIP) {
 | 
				
			||||||
 | 
					      LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
 | 
				
			||||||
 | 
					    } else if (rc != SIGERR_NONE) {
 | 
				
			||||||
 | 
					      LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    delete radio_burst;
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  timingOffset = toa / mSPSRx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bits = demodulate(*burst, amp, toa, type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  delete radio_burst;
 | 
				
			||||||
  return bits;
 | 
					  return bits;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Transceiver::start()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  TransceiverChannel *chan;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (size_t i = 0; i < mControlServiceLoopThreads.size(); i++) {
 | 
					 | 
				
			||||||
    chan = new TransceiverChannel(this, i);
 | 
					 | 
				
			||||||
    mControlServiceLoopThreads[i]->start((void * (*)(void*))
 | 
					 | 
				
			||||||
                                 ControlServiceLoopAdapter, (void*) chan);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Transceiver::reset()
 | 
					void Transceiver::reset()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
 | 
					  for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
 | 
				
			||||||
@@ -581,7 +704,7 @@ void Transceiver::driveControl(size_t chan)
 | 
				
			|||||||
  int msgLen = -1;
 | 
					  int msgLen = -1;
 | 
				
			||||||
  buffer[0] = '\0';
 | 
					  buffer[0] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  msgLen = mCtrlSockets[chan]->read(buffer);
 | 
					  msgLen = mCtrlSockets[chan]->read(buffer, sizeof(buffer));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (msgLen < 1) {
 | 
					  if (msgLen < 1) {
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
@@ -603,44 +726,18 @@ void Transceiver::driveControl(size_t chan)
 | 
				
			|||||||
  LOG(INFO) << "command is " << buffer;
 | 
					  LOG(INFO) << "command is " << buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (strcmp(command,"POWEROFF")==0) {
 | 
					  if (strcmp(command,"POWEROFF")==0) {
 | 
				
			||||||
    // turn off transmitter/demod
 | 
					    stop();
 | 
				
			||||||
    sprintf(response,"RSP POWEROFF 0");
 | 
					    sprintf(response,"RSP POWEROFF 0");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  else if (strcmp(command,"POWERON")==0) {
 | 
					  else if (strcmp(command,"POWERON")==0) {
 | 
				
			||||||
    // turn on transmitter/demod
 | 
					    if (!start())
 | 
				
			||||||
    if (!mTxFreq || !mRxFreq) 
 | 
					 | 
				
			||||||
      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 i = 0; i < 8; i++) {
 | 
				
			||||||
        for (int j = 0; j < 8; j++)
 | 
					        for (int j = 0; j < 8; j++)
 | 
				
			||||||
          mHandover[i][j] = false;
 | 
					          mHandover[i][j] = false;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (!chan && !mOn) {
 | 
					 | 
				
			||||||
        // Prepare for thread start
 | 
					 | 
				
			||||||
        mPower = -20;
 | 
					 | 
				
			||||||
        mRadioInterface->start();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Start radio interface threads.
 | 
					 | 
				
			||||||
        mTxLowerLoopThread->start((void * (*)(void*))
 | 
					 | 
				
			||||||
                                  TxLowerLoopAdapter,(void*) this);
 | 
					 | 
				
			||||||
        mRxLowerLoopThread->start((void * (*)(void*))
 | 
					 | 
				
			||||||
                                  RxLowerLoopAdapter,(void*) this);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for (size_t i = 0; i < mChans; i++) {
 | 
					 | 
				
			||||||
          TransceiverChannel *chan = new TransceiverChannel(this, i);
 | 
					 | 
				
			||||||
          mRxServiceLoopThreads[i]->start((void * (*)(void*))
 | 
					 | 
				
			||||||
                                  RxUpperLoopAdapter, (void*) chan);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          chan = new TransceiverChannel(this, i);
 | 
					 | 
				
			||||||
          mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
 | 
					 | 
				
			||||||
                                  TxUpperLoopAdapter, (void*) chan);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        writeClockInterface();
 | 
					 | 
				
			||||||
        mOn = true;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  else if (strcmp(command,"HANDOVER")==0){
 | 
					  else if (strcmp(command,"HANDOVER")==0){
 | 
				
			||||||
    int ts=0,ss=0;
 | 
					    int ts=0,ss=0;
 | 
				
			||||||
@@ -660,9 +757,16 @@ void Transceiver::driveControl(size_t chan)
 | 
				
			|||||||
    //set expected maximum time-of-arrival
 | 
					    //set expected maximum time-of-arrival
 | 
				
			||||||
    int maxDelay;
 | 
					    int maxDelay;
 | 
				
			||||||
    sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
 | 
					    sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
 | 
				
			||||||
    mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
 | 
					    mMaxExpectedDelayAB = maxDelay; // 1 GSM symbol is approx. 1 km
 | 
				
			||||||
    sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
 | 
					    sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  else if (strcmp(command,"SETMAXDLYNB")==0) {
 | 
				
			||||||
 | 
					    //set expected maximum time-of-arrival
 | 
				
			||||||
 | 
					    int maxDelay;
 | 
				
			||||||
 | 
					    sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
 | 
				
			||||||
 | 
					    mMaxExpectedDelayNB = maxDelay; // 1 GSM symbol is approx. 1 km
 | 
				
			||||||
 | 
					    sprintf(response,"RSP SETMAXDLYNB 0 %d",maxDelay);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  else if (strcmp(command,"SETRXGAIN")==0) {
 | 
					  else if (strcmp(command,"SETRXGAIN")==0) {
 | 
				
			||||||
    //set expected maximum time-of-arrival
 | 
					    //set expected maximum time-of-arrival
 | 
				
			||||||
    int newGain;
 | 
					    int newGain;
 | 
				
			||||||
@@ -681,28 +785,19 @@ void Transceiver::driveControl(size_t chan)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  else if (!strcmp(command, "SETPOWER")) {
 | 
					  else if (!strcmp(command, "SETPOWER")) {
 | 
				
			||||||
    // set output power in dB
 | 
					    int power;
 | 
				
			||||||
    int dbPwr;
 | 
					    sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
 | 
				
			||||||
    sscanf(buffer, "%3s %s %d", cmdcheck, command, &dbPwr);
 | 
					    power = mRadioInterface->setPowerAttenuation(power, chan);
 | 
				
			||||||
    if (!mOn)
 | 
					    mStates[chan].mPower = power;
 | 
				
			||||||
      sprintf(response, "RSP SETPOWER 1 %d", dbPwr);
 | 
					    sprintf(response, "RSP SETPOWER 0 %d", power);
 | 
				
			||||||
    else {
 | 
					 | 
				
			||||||
      mPower = dbPwr;
 | 
					 | 
				
			||||||
      mRadioInterface->setPowerAttenuation(mPower, chan);
 | 
					 | 
				
			||||||
      sprintf(response, "RSP SETPOWER 0 %d", dbPwr);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  else if (!strcmp(command,"ADJPOWER")) {
 | 
					  else if (!strcmp(command,"ADJPOWER")) {
 | 
				
			||||||
    // adjust power in dB steps
 | 
					    int power, step;
 | 
				
			||||||
    int dbStep;
 | 
					    sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
 | 
				
			||||||
    sscanf(buffer, "%3s %s %d", cmdcheck, command, &dbStep);
 | 
					    power = mStates[chan].mPower + step;
 | 
				
			||||||
    if (!mOn)
 | 
					    power = mRadioInterface->setPowerAttenuation(power, chan);
 | 
				
			||||||
      sprintf(response, "RSP ADJPOWER 1 %d", mPower);
 | 
					    mStates[chan].mPower = power;
 | 
				
			||||||
    else {
 | 
					    sprintf(response, "RSP ADJPOWER 0 %d", power);
 | 
				
			||||||
      mPower += dbStep;
 | 
					 | 
				
			||||||
      mRadioInterface->setPowerAttenuation(mPower, chan);
 | 
					 | 
				
			||||||
      sprintf(response, "RSP ADJPOWER 0 %d", mPower);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  else if (strcmp(command,"RXTUNE")==0) {
 | 
					  else if (strcmp(command,"RXTUNE")==0) {
 | 
				
			||||||
    // tune receiver
 | 
					    // tune receiver
 | 
				
			||||||
@@ -738,7 +833,6 @@ void Transceiver::driveControl(size_t chan)
 | 
				
			|||||||
      sprintf(response, "RSP SETTSC 1 %d", TSC);
 | 
					      sprintf(response, "RSP SETTSC 1 %d", TSC);
 | 
				
			||||||
    else {
 | 
					    else {
 | 
				
			||||||
      mTSC = TSC;
 | 
					      mTSC = TSC;
 | 
				
			||||||
      generateMidamble(mSPSRx, TSC);
 | 
					 | 
				
			||||||
      sprintf(response,"RSP SETTSC 0 %d", TSC);
 | 
					      sprintf(response,"RSP SETTSC 0 %d", TSC);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -757,6 +851,14 @@ void Transceiver::driveControl(size_t chan)
 | 
				
			|||||||
    sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
 | 
					    sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  else if (strcmp(command,"_SETBURSTTODISKMASK")==0) {
 | 
				
			||||||
 | 
					    // debug command! may change or disapear without notice
 | 
				
			||||||
 | 
					    // set a mask which bursts to dump to disk
 | 
				
			||||||
 | 
					    int mask;
 | 
				
			||||||
 | 
					    sscanf(buffer,"%3s %s %d",cmdcheck,command,&mask);
 | 
				
			||||||
 | 
					    mWriteBurstToDiskMask = mask;
 | 
				
			||||||
 | 
					    sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  else {
 | 
					  else {
 | 
				
			||||||
    LOG(WARNING) << "bogus command " << command << " on control interface.";
 | 
					    LOG(WARNING) << "bogus command " << command << " on control interface.";
 | 
				
			||||||
    sprintf(response,"RSP ERR 1");
 | 
					    sprintf(response,"RSP ERR 1");
 | 
				
			||||||
@@ -770,7 +872,7 @@ bool Transceiver::driveTxPriorityQueue(size_t chan)
 | 
				
			|||||||
  char buffer[gSlotLen+50];
 | 
					  char buffer[gSlotLen+50];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // check data socket
 | 
					  // check data socket
 | 
				
			||||||
  size_t msgLen = mDataSockets[chan]->read(buffer);
 | 
					  size_t msgLen = mDataSockets[chan]->read(buffer, sizeof(buffer));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (msgLen!=gSlotLen+1+4+1) {
 | 
					  if (msgLen!=gSlotLen+1+4+1) {
 | 
				
			||||||
    LOG(ERR) << "badly formatted packet on GSM->TRX interface";
 | 
					    LOG(ERR) << "badly formatted packet on GSM->TRX interface";
 | 
				
			||||||
@@ -782,15 +884,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];
 | 
				
			||||||
@@ -811,44 +904,70 @@ bool Transceiver::driveTxPriorityQueue(size_t chan)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void Transceiver::driveReceiveRadio()
 | 
					void Transceiver::driveReceiveRadio()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if (!mRadioInterface->driveReceiveRadio())
 | 
					  if (!mRadioInterface->driveReceiveRadio()) {
 | 
				
			||||||
    usleep(100000);
 | 
					    usleep(100000);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
 | 
				
			||||||
 | 
					      writeClockInterface();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Transceiver::logRxBurst(SoftVector *burst, GSM::Time time, double dbm,
 | 
				
			||||||
 | 
					                             double rssi, double noise, double toa)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  LOG(DEBUG) << std::fixed << std::right
 | 
				
			||||||
 | 
					    << " time: "   << time
 | 
				
			||||||
 | 
					    << " RSSI: "   << std::setw(5) << std::setprecision(1) << rssi
 | 
				
			||||||
 | 
					                   << "dBFS/" << std::setw(6) << -dbm << "dBm"
 | 
				
			||||||
 | 
					    << " noise: "  << std::setw(5) << std::setprecision(1) << noise
 | 
				
			||||||
 | 
					                   << "dBFS/" << std::setw(6) << -(noise + rssiOffset) << "dBm"
 | 
				
			||||||
 | 
					    << " TOA: "    << std::setw(5) << std::setprecision(2) << toa
 | 
				
			||||||
 | 
					    << " bits: "   << *burst;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Transceiver::driveReceiveFIFO(size_t chan)
 | 
					void Transceiver::driveReceiveFIFO(size_t chan)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  SoftVector *rxBurst = NULL;
 | 
					  SoftVector *rxBurst = NULL;
 | 
				
			||||||
  int RSSI;
 | 
					  double RSSI; // in dBFS
 | 
				
			||||||
  int TOA;  // in 1/256 of a symbol
 | 
					  double dBm;  // in dBm
 | 
				
			||||||
 | 
					  double TOA;  // in symbols
 | 
				
			||||||
 | 
					  int TOAint;  // in 1/256 symbols
 | 
				
			||||||
 | 
					  double noise; // noise level in dBFS
 | 
				
			||||||
  GSM::Time burstTime;
 | 
					  GSM::Time burstTime;
 | 
				
			||||||
 | 
					  bool isRssiValid; // are RSSI, noise and burstTime valid
 | 
				
			||||||
 | 
					  unsigned nbits = gSlotLen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  rxBurst = pullRadioVector(burstTime, RSSI, TOA, chan);
 | 
					  rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
 | 
				
			||||||
 | 
					  if (!rxBurst)
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (rxBurst) { 
 | 
					  /*
 | 
				
			||||||
 | 
					   * EDGE demodulator returns 444 (148 * 3) bits
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  if (rxBurst->size() == gSlotLen * 3)
 | 
				
			||||||
 | 
					    nbits = gSlotLen * 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    LOG(DEBUG) << "burst parameters: "
 | 
					  dBm = RSSI + rssiOffset;
 | 
				
			||||||
	  << " time: " << burstTime
 | 
					  logRxBurst(rxBurst, burstTime, dBm, RSSI, noise, TOA);
 | 
				
			||||||
	  << " RSSI: " << RSSI
 | 
					 | 
				
			||||||
	  << " TOA: "  << TOA
 | 
					 | 
				
			||||||
	  << " bits: " << *rxBurst;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char burstString[gSlotLen+10];
 | 
					  TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  char burstString[nbits + 10];
 | 
				
			||||||
  burstString[0] = burstTime.TN();
 | 
					  burstString[0] = burstTime.TN();
 | 
				
			||||||
  for (int i = 0; i < 4; i++)
 | 
					  for (int i = 0; i < 4; i++)
 | 
				
			||||||
    burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
 | 
					    burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
 | 
				
			||||||
    burstString[5] = RSSI;
 | 
					  burstString[5] = (int)dBm;
 | 
				
			||||||
    burstString[6] = (TOA >> 8) & 0x0ff;
 | 
					  burstString[6] = (TOAint >> 8) & 0x0ff;
 | 
				
			||||||
    burstString[7] = TOA & 0x0ff;
 | 
					  burstString[7] = TOAint & 0x0ff;
 | 
				
			||||||
  SoftVector::iterator burstItr = rxBurst->begin();
 | 
					  SoftVector::iterator burstItr = rxBurst->begin();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (unsigned int i = 0; i < gSlotLen; i++) {
 | 
					  for (unsigned i = 0; i < nbits; i++)
 | 
				
			||||||
    burstString[8 + i] = (char) round((*burstItr++) * 255.0);
 | 
					    burstString[8 + i] = (char) round((*burstItr++) * 255.0);
 | 
				
			||||||
    }
 | 
					
 | 
				
			||||||
    burstString[gSlotLen+9] = '\0';
 | 
					  burstString[nbits + 9] = '\0';
 | 
				
			||||||
  delete rxBurst;
 | 
					  delete rxBurst;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mDataSockets[chan]->write(burstString,gSlotLen+10);
 | 
					  mDataSockets[chan]->write(burstString, nbits + 10);
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Transceiver::driveTxFIFO()
 | 
					void Transceiver::driveTxFIFO()
 | 
				
			||||||
@@ -913,7 +1032,7 @@ void Transceiver::writeClockInterface()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  LOG(INFO) << "ClockInterface: sending " << command;
 | 
					  LOG(INFO) << "ClockInterface: sending " << command;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  mClockSocket->write(command, strlen(command) + 1);
 | 
					  mClockSocket.write(command, strlen(command) + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  mLastClockUpdateTime = mTransmitDeadlineClock;
 | 
					  mLastClockUpdateTime = mTransmitDeadlineClock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -981,15 +1100,7 @@ void *TxUpperLoopAdapter(TransceiverChannel *chan)
 | 
				
			|||||||
  trx->setPriority(0.40);
 | 
					  trx->setPriority(0.40);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  while (1) {
 | 
					  while (1) {
 | 
				
			||||||
    bool stale = false;
 | 
					    trx->driveTxPriorityQueue(num);
 | 
				
			||||||
    // Flush the UDP packets until a successful transfer.
 | 
					 | 
				
			||||||
    while (!trx->driveTxPriorityQueue(num)) {
 | 
					 | 
				
			||||||
      stale = true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (!num && stale) {
 | 
					 | 
				
			||||||
      // If a packet was stale, remind the GSM stack of the clock.
 | 
					 | 
				
			||||||
      trx->writeClockInterface();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pthread_testcancel();
 | 
					    pthread_testcancel();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return NULL;
 | 
					  return NULL;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,7 +54,7 @@ struct TransceiverState {
 | 
				
			|||||||
  ~TransceiverState();
 | 
					  ~TransceiverState();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Initialize a multiframe slot in the filler table */
 | 
					  /* Initialize a multiframe slot in the filler table */
 | 
				
			||||||
  void init(size_t slot, signalVector *burst, bool fill);
 | 
					  bool init(int filler, size_t sps, float scale, size_t rtsc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int chanType[8];
 | 
					  int chanType[8];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -81,99 +81,14 @@ struct TransceiverState {
 | 
				
			|||||||
  /* Received noise energy levels */
 | 
					  /* Received noise energy levels */
 | 
				
			||||||
  float mNoiseLev;
 | 
					  float mNoiseLev;
 | 
				
			||||||
  noiseVector mNoises;
 | 
					  noiseVector mNoises;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Shadowed downlink attenuation */
 | 
				
			||||||
 | 
					  int mPower;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** The Transceiver class, responsible for physical layer of basestation */
 | 
					/** The Transceiver class, responsible for physical layer of basestation */
 | 
				
			||||||
class Transceiver {
 | 
					class Transceiver {
 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
  int mBasePort;
 | 
					 | 
				
			||||||
  std::string mAddr;
 | 
					 | 
				
			||||||
  GSM::Time mTransmitLatency;     ///< latency between basestation clock and transmit deadline clock
 | 
					 | 
				
			||||||
  GSM::Time mLatencyUpdateTime;   ///< last time latency was updated
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  std::vector<UDPSocket *> mDataSockets;  ///< socket for writing to/reading from GSM core
 | 
					 | 
				
			||||||
  std::vector<UDPSocket *> mCtrlSockets;  ///< socket for writing/reading control commands from GSM core
 | 
					 | 
				
			||||||
  UDPSocket *mClockSocket;                ///< socket for writing clock updates to GSM core
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  std::vector<VectorQueue> mTxPriorityQueues;   ///< priority queue of transmit bursts received from GSM core
 | 
					 | 
				
			||||||
  std::vector<VectorFIFO *>  mReceiveFIFO;      ///< radioInterface FIFO of receive bursts
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  std::vector<Thread *> mRxServiceLoopThreads;  ///< thread to pull bursts into receive FIFO
 | 
					 | 
				
			||||||
  Thread *mRxLowerLoopThread;                   ///< 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 *> mTxPriorityQueueServiceLoopThreads; ///< thread to process transmit bursts from GSM core
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GSM::Time mTransmitDeadlineClock;       ///< deadline for pushing bursts into transmit FIFO 
 | 
					 | 
				
			||||||
  GSM::Time mLastClockUpdateTime;         ///< last time clock update was sent up to core
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  RadioInterface *mRadioInterface;	  ///< associated radioInterface object
 | 
					 | 
				
			||||||
  double txFullScale;                     ///< full scale input to radio
 | 
					 | 
				
			||||||
  double rxFullScale;                     ///< full scale output to radio
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /** Codes for burst types of received bursts*/
 | 
					 | 
				
			||||||
  typedef enum {
 | 
					 | 
				
			||||||
    OFF,               ///< timeslot is off
 | 
					 | 
				
			||||||
    TSC,	       ///< timeslot should contain a normal burst
 | 
					 | 
				
			||||||
    RACH,	       ///< timeslot should contain an access burst
 | 
					 | 
				
			||||||
    IDLE	       ///< timeslot is an idle (or dummy) burst
 | 
					 | 
				
			||||||
  } CorrType;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /** modulate and add a burst to the transmit queue */
 | 
					 | 
				
			||||||
  void addRadioVector(size_t chan, BitVector &bits,
 | 
					 | 
				
			||||||
                      int RSSI, GSM::Time &wTime);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /** Update filler table */
 | 
					 | 
				
			||||||
  void updateFillerTable(size_t chan, radioVector *burst);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /** Push modulated burst into transmit FIFO corresponding to a particular timestamp */
 | 
					 | 
				
			||||||
  void pushRadioVector(GSM::Time &nowTime);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /** Pull and demodulate a burst from the receive FIFO */
 | 
					 | 
				
			||||||
  SoftVector *pullRadioVector(GSM::Time &wTime, int &RSSI,
 | 
					 | 
				
			||||||
                              int &timingOffset, size_t chan = 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /** Set modulus for specific timeslot */
 | 
					 | 
				
			||||||
  void setModulus(size_t timeslot, size_t chan);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /** return the expected burst type for the specified timestamp */
 | 
					 | 
				
			||||||
  CorrType expectedCorrType(GSM::Time currTime, size_t chan);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /** send messages over the clock socket */
 | 
					 | 
				
			||||||
  void writeClockInterface(void);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /** Detect RACH bursts */
 | 
					 | 
				
			||||||
  bool detectRACH(TransceiverState *state,
 | 
					 | 
				
			||||||
                  signalVector &burst,
 | 
					 | 
				
			||||||
                  complex &, float &toa);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /** Detect normal bursts */
 | 
					 | 
				
			||||||
  bool detectTSC(TransceiverState *state,
 | 
					 | 
				
			||||||
                 signalVector &burst,
 | 
					 | 
				
			||||||
                 complex &, float &toa, GSM::Time &time);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /** Demodulat burst and output soft bits */
 | 
					 | 
				
			||||||
  SoftVector *demodulate(TransceiverState *state,
 | 
					 | 
				
			||||||
                         signalVector &burst, complex amp,
 | 
					 | 
				
			||||||
                         float toa, size_t tn, bool equalize);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int mSPSTx;                          ///< number of samples per Tx symbol
 | 
					 | 
				
			||||||
  int mSPSRx;                          ///< number of samples per Rx symbol
 | 
					 | 
				
			||||||
  size_t mChans;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  bool mOn;			       ///< flag to indicate that transceiver is powered on
 | 
					 | 
				
			||||||
  bool mHandover[8][8];                ///< expect handover to the timeslot/subslot
 | 
					 | 
				
			||||||
  double mTxFreq;                      ///< the transmit frequency
 | 
					 | 
				
			||||||
  double mRxFreq;                      ///< the receive frequency
 | 
					 | 
				
			||||||
  int mPower;                          ///< the transmit power in dB
 | 
					 | 
				
			||||||
  unsigned mTSC;                       ///< the midamble sequence code
 | 
					 | 
				
			||||||
  unsigned mMaxExpectedDelay;            ///< maximum expected time-of-arrival offset in GSM symbols
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  std::vector<TransceiverState> mStates;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
					 | 
				
			||||||
  /** Transceiver constructor 
 | 
					  /** Transceiver constructor 
 | 
				
			||||||
      @param wBasePort base port number of UDP sockets
 | 
					      @param wBasePort base port number of UDP sockets
 | 
				
			||||||
      @param TRXAddress IP address of the TRX manager, as a string
 | 
					      @param TRXAddress IP address of the TRX manager, as a string
 | 
				
			||||||
@@ -183,16 +98,16 @@ public:
 | 
				
			|||||||
  */
 | 
					  */
 | 
				
			||||||
  Transceiver(int wBasePort,
 | 
					  Transceiver(int wBasePort,
 | 
				
			||||||
              const char *TRXAddress,
 | 
					              const char *TRXAddress,
 | 
				
			||||||
	      size_t wSPS, size_t chans,
 | 
					              size_t tx_sps, size_t rx_sps, size_t chans,
 | 
				
			||||||
              GSM::Time wTransmitLatency,
 | 
					              GSM::Time wTransmitLatency,
 | 
				
			||||||
	      RadioInterface *wRadioInterface);
 | 
					              RadioInterface *wRadioInterface,
 | 
				
			||||||
 | 
					              double wRssiOffset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Destructor */
 | 
					  /** Destructor */
 | 
				
			||||||
  ~Transceiver();
 | 
					  ~Transceiver();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** start the Transceiver */
 | 
					  /** Start the control loop */
 | 
				
			||||||
  void start();
 | 
					  bool init(int filler, size_t rtsc);
 | 
				
			||||||
  bool init(bool filler);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** attach the radioInterface receive FIFO */
 | 
					  /** attach the radioInterface receive FIFO */
 | 
				
			||||||
  bool receiveFIFO(VectorFIFO *wFIFO, size_t chan)
 | 
					  bool receiveFIFO(VectorFIFO *wFIFO, size_t chan)
 | 
				
			||||||
@@ -227,6 +142,105 @@ public:
 | 
				
			|||||||
    LOOPBACK            ///< similar go VII, used in loopback testing
 | 
					    LOOPBACK            ///< similar go VII, used in loopback testing
 | 
				
			||||||
  } ChannelCombination;
 | 
					  } ChannelCombination;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Codes for burst types of received bursts*/
 | 
				
			||||||
 | 
					  typedef enum {
 | 
				
			||||||
 | 
					    OFF,               ///< timeslot is off
 | 
				
			||||||
 | 
					    TSC,	       ///< timeslot should contain a normal burst
 | 
				
			||||||
 | 
					    RACH,	       ///< timeslot should contain an access burst
 | 
				
			||||||
 | 
					    EDGE,	       ///< timeslot should contain an EDGE burst
 | 
				
			||||||
 | 
					    IDLE	       ///< timeslot is an idle (or dummy) burst
 | 
				
			||||||
 | 
					  } CorrType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  enum FillerType {
 | 
				
			||||||
 | 
					    FILLER_DUMMY,
 | 
				
			||||||
 | 
					    FILLER_ZERO,
 | 
				
			||||||
 | 
					    FILLER_NORM_RAND,
 | 
				
			||||||
 | 
					    FILLER_EDGE_RAND,
 | 
				
			||||||
 | 
					    FILLER_ACCESS_RAND,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					  int mBasePort;
 | 
				
			||||||
 | 
					  std::string mAddr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::vector<UDPSocket *> mDataSockets;  ///< socket for writing to/reading from GSM core
 | 
				
			||||||
 | 
					  std::vector<UDPSocket *> mCtrlSockets;  ///< socket for writing/reading control commands from GSM core
 | 
				
			||||||
 | 
					  UDPSocket mClockSocket;                 ///< socket for writing clock updates to GSM core
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::vector<VectorQueue> mTxPriorityQueues;   ///< priority queue of transmit bursts received from GSM core
 | 
				
			||||||
 | 
					  std::vector<VectorFIFO *>  mReceiveFIFO;      ///< radioInterface FIFO of receive bursts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::vector<Thread *> mRxServiceLoopThreads;  ///< thread to pull bursts into receive FIFO
 | 
				
			||||||
 | 
					  Thread *mRxLowerLoopThread;                   ///< 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 *> mTxPriorityQueueServiceLoopThreads; ///< thread to process transmit bursts from GSM core
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  GSM::Time mTransmitLatency;             ///< latency between basestation clock and transmit deadline clock
 | 
				
			||||||
 | 
					  GSM::Time mLatencyUpdateTime;           ///< last time latency was updated
 | 
				
			||||||
 | 
					  GSM::Time mTransmitDeadlineClock;       ///< deadline for pushing bursts into transmit FIFO 
 | 
				
			||||||
 | 
					  GSM::Time mLastClockUpdateTime;         ///< last time clock update was sent up to core
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  RadioInterface *mRadioInterface;	  ///< associated radioInterface object
 | 
				
			||||||
 | 
					  double txFullScale;                     ///< full scale input to radio
 | 
				
			||||||
 | 
					  double rxFullScale;                     ///< full scale output to radio
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  double rssiOffset;                      ///< RSSI to dBm conversion offset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** modulate and add a burst to the transmit queue */
 | 
				
			||||||
 | 
					  void addRadioVector(size_t chan, BitVector &bits,
 | 
				
			||||||
 | 
					                      int RSSI, GSM::Time &wTime);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Update filler table */
 | 
				
			||||||
 | 
					  void updateFillerTable(size_t chan, radioVector *burst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Push modulated burst into transmit FIFO corresponding to a particular timestamp */
 | 
				
			||||||
 | 
					  void pushRadioVector(GSM::Time &nowTime);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Pull and demodulate a burst from the receive FIFO */
 | 
				
			||||||
 | 
					  SoftVector *pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
 | 
				
			||||||
 | 
					                              double &timingOffset, double &noise,
 | 
				
			||||||
 | 
					                              size_t chan = 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Set modulus for specific timeslot */
 | 
				
			||||||
 | 
					  void setModulus(size_t timeslot, size_t chan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** return the expected burst type for the specified timestamp */
 | 
				
			||||||
 | 
					  CorrType expectedCorrType(GSM::Time currTime, size_t chan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** send messages over the clock socket */
 | 
				
			||||||
 | 
					  void writeClockInterface(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Detectbursts */
 | 
				
			||||||
 | 
					  int detectBurst(signalVector &burst,
 | 
				
			||||||
 | 
					                  complex &, float &toa, CorrType type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Demodulate burst and output soft bits */
 | 
				
			||||||
 | 
					  SoftVector *demodulate(signalVector &burst,
 | 
				
			||||||
 | 
					                         complex amp, float toa, CorrType type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int mSPSTx;                          ///< number of samples per Tx symbol
 | 
				
			||||||
 | 
					  int mSPSRx;                          ///< number of samples per Rx symbol
 | 
				
			||||||
 | 
					  size_t mChans;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool mOn;	                           ///< flag to indicate that transceiver is powered on
 | 
				
			||||||
 | 
					  bool mHandover[8][8];                ///< expect handover to the timeslot/subslot
 | 
				
			||||||
 | 
					  double mTxFreq;                      ///< the transmit frequency
 | 
				
			||||||
 | 
					  double mRxFreq;                      ///< the receive frequency
 | 
				
			||||||
 | 
					  unsigned mTSC;                       ///< the midamble sequence code
 | 
				
			||||||
 | 
					  unsigned mMaxExpectedDelayAB;        ///< maximum expected time-of-arrival offset in GSM symbols for Access Bursts (RACH)
 | 
				
			||||||
 | 
					  unsigned mMaxExpectedDelayNB;        ///< maximum expected time-of-arrival offset in GSM symbols for Normal Bursts
 | 
				
			||||||
 | 
					  unsigned mWriteBurstToDiskMask;      ///< debug: bitmask to indicate which timeslots to dump to disk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::vector<TransceiverState> mStates;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Start and stop I/O threads through the control socket API */
 | 
				
			||||||
 | 
					  bool start();
 | 
				
			||||||
 | 
					  void stop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Protect destructor accessable stop call */
 | 
				
			||||||
 | 
					  Mutex mLock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
  /** drive lower receive I/O and burst generation */
 | 
					  /** drive lower receive I/O and burst generation */
 | 
				
			||||||
  void driveReceiveRadio();
 | 
					  void driveReceiveRadio();
 | 
				
			||||||
@@ -262,6 +276,8 @@ protected:
 | 
				
			|||||||
  /** set priority on current thread */
 | 
					  /** set priority on current thread */
 | 
				
			||||||
  void setPriority(float prio = 0.5) { mRadioInterface->setPriority(prio); }
 | 
					  void setPriority(float prio = 0.5) { mRadioInterface->setPriority(prio); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void logRxBurst(SoftVector *burst, GSM::Time time, double dbm,
 | 
				
			||||||
 | 
					                  double rssi, double noise, double toa);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void *RxUpperLoopAdapter(TransceiverChannel *);
 | 
					void *RxUpperLoopAdapter(TransceiverChannel *);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,13 +34,23 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define B2XX_CLK_RT      26e6
 | 
					#define B2XX_CLK_RT      26e6
 | 
				
			||||||
#define E1XX_CLK_RT      52e6
 | 
					#define E1XX_CLK_RT      52e6
 | 
				
			||||||
#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 USRP_TX_AMPL     0.3
 | 
				
			||||||
#define UMTRX_TX_AMPL    0.7
 | 
					#define UMTRX_TX_AMPL    0.7
 | 
				
			||||||
#define SAMPLE_BUF_SZ    (1 << 20)
 | 
					#define SAMPLE_BUF_SZ    (1 << 20)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * UHD timeout value on streaming (re)start
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Allow some time for streaming to commence after the start command is issued,
 | 
				
			||||||
 | 
					 * but consider a wait beyond one second to be a definite error condition.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define UHD_RESTART_TIMEOUT     1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * UmTRX specific settings
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
#define UMTRX_VGA1_DEF   -18
 | 
					#define UMTRX_VGA1_DEF   -18
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum uhd_dev_type {
 | 
					enum uhd_dev_type {
 | 
				
			||||||
@@ -50,17 +60,33 @@ enum uhd_dev_type {
 | 
				
			|||||||
	B200,
 | 
						B200,
 | 
				
			||||||
	B210,
 | 
						B210,
 | 
				
			||||||
	E1XX,
 | 
						E1XX,
 | 
				
			||||||
 | 
						E3XX,
 | 
				
			||||||
 | 
						X3XX,
 | 
				
			||||||
	UMTRX,
 | 
						UMTRX,
 | 
				
			||||||
	NUM_USRP_TYPES,
 | 
						NUM_USRP_TYPES,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct uhd_dev_offset {
 | 
					struct uhd_dev_offset {
 | 
				
			||||||
	enum uhd_dev_type type;
 | 
						enum uhd_dev_type type;
 | 
				
			||||||
	int sps;
 | 
						size_t tx_sps;
 | 
				
			||||||
 | 
						size_t rx_sps;
 | 
				
			||||||
	double offset;
 | 
						double offset;
 | 
				
			||||||
	const std::string desc;
 | 
						const std::string desc;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * USRP version dependent device timings
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifdef USE_UHD_3_9
 | 
				
			||||||
 | 
					#define B2XX_TIMING_1SPS	1.7153e-4
 | 
				
			||||||
 | 
					#define B2XX_TIMING_4SPS	1.1696e-4
 | 
				
			||||||
 | 
					#define B2XX_TIMING_4_4SPS	6.18462e-5
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define B2XX_TIMING_1SPS	9.9692e-5
 | 
				
			||||||
 | 
					#define B2XX_TIMING_4SPS	6.9248e-5
 | 
				
			||||||
 | 
					#define B2XX_TIMING_4_4SPS	4.52308e-5
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * 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
 | 
				
			||||||
@@ -71,74 +97,40 @@ struct uhd_dev_offset {
 | 
				
			|||||||
 * Notes:
 | 
					 * Notes:
 | 
				
			||||||
 *   USRP1 with timestamps is not supported by UHD.
 | 
					 *   USRP1 with timestamps is not supported by UHD.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static struct uhd_dev_offset uhd_offsets[NUM_USRP_TYPES * 2] = {
 | 
					static struct uhd_dev_offset uhd_offsets[] = {
 | 
				
			||||||
	{ USRP1, 1,       0.0, "USRP1 not supported" },
 | 
						{ USRP1, 1, 1,       0.0, "USRP1 not supported" },
 | 
				
			||||||
	{ USRP1, 4,       0.0, "USRP1 not supported"},
 | 
						{ USRP1, 4, 1,       0.0, "USRP1 not supported"},
 | 
				
			||||||
	{ USRP2, 1, 1.2184e-4, "N2XX 1 SPS" },
 | 
						{ USRP2, 1, 1, 1.2184e-4, "N2XX 1 SPS" },
 | 
				
			||||||
	{ USRP2, 4, 8.0230e-5, "N2XX 4 SPS" },
 | 
						{ USRP2, 4, 1, 8.0230e-5, "N2XX 4 SPS" },
 | 
				
			||||||
	{ B100,  1, 1.2104e-4, "B100 1 SPS" },
 | 
						{ B100,  1, 1, 1.2104e-4, "B100 1 SPS" },
 | 
				
			||||||
	{ B100,  4, 7.9307e-5, "B100 4 SPS" },
 | 
						{ B100,  4, 1, 7.9307e-5, "B100 4 SPS" },
 | 
				
			||||||
	{ B200,  1, 9.9692e-5, "B200 1 SPS" },
 | 
						{ B200,  1, 1, B2XX_TIMING_1SPS, "B200 1 SPS" },
 | 
				
			||||||
	{ B200,  4, 6.9248e-5, "B200 4 SPS" },
 | 
						{ B200,  4, 1, B2XX_TIMING_4SPS, "B200 4 SPS" },
 | 
				
			||||||
	{ B210,  1, 9.9692e-5, "B210 1 SPS" },
 | 
						{ B210,  1, 1, B2XX_TIMING_1SPS, "B210 1 SPS" },
 | 
				
			||||||
	{ B210,  4, 6.9248e-5, "B210 4 SPS" },
 | 
						{ B210,  4, 1, B2XX_TIMING_4SPS, "B210 4 SPS" },
 | 
				
			||||||
	{ E1XX,  1, 9.5192e-5, "E1XX 1 SPS" },
 | 
						{ E1XX,  1, 1, 9.5192e-5, "E1XX 1 SPS" },
 | 
				
			||||||
	{ E1XX,  4, 6.5571e-5, "E1XX 4 SPS" },
 | 
						{ E1XX,  4, 1, 6.5571e-5, "E1XX 4 SPS" },
 | 
				
			||||||
	{ UMTRX, 1, 9.9692e-5, "UmTRX 1 SPS" },
 | 
						{ E3XX,  1, 1, 1.84616e-4, "E3XX 1 SPS" },
 | 
				
			||||||
	{ UMTRX, 4, 7.3846e-5, "UmTRX 4 SPS" },
 | 
						{ E3XX,  4, 1, 1.29231e-4, "E3XX 4 SPS" },
 | 
				
			||||||
 | 
						{ X3XX,  1, 1, 1.5360e-4, "X3XX 1 SPS"},
 | 
				
			||||||
 | 
						{ X3XX,  4, 1, 1.1264e-4, "X3XX 4 SPS"},
 | 
				
			||||||
 | 
						{ UMTRX, 1, 1, 9.9692e-5, "UmTRX 1 SPS" },
 | 
				
			||||||
 | 
						{ UMTRX, 4, 1, 7.3846e-5, "UmTRX 4 SPS" },
 | 
				
			||||||
 | 
						{ B200,  4, 4, B2XX_TIMING_4_4SPS, "B200/B210 EDGE mode (4 SPS TX/RX)" },
 | 
				
			||||||
 | 
						{ B210,  4, 4, B2XX_TIMING_4_4SPS, "B200/B210 EDGE mode (4 SPS TX/RX)" },
 | 
				
			||||||
 | 
						{ UMTRX, 4, 4, 5.1503e-5, "UmTRX EDGE mode (4 SPS TX/RX)" },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					#define NUM_UHD_OFFSETS (sizeof(uhd_offsets)/sizeof(uhd_offsets[0]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Offset handling for special cases. Currently used for UmTRX dual channel
 | 
					 * Offset handling for special cases. Currently used for UmTRX dual channel
 | 
				
			||||||
 * diversity receiver only.
 | 
					 * diversity receiver only.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static struct uhd_dev_offset special_offsets[] = {
 | 
					static struct uhd_dev_offset special_offsets[] = {
 | 
				
			||||||
	{ UMTRX, 1, 8.0875e-5, "UmTRX diversity, 1 SPS" },
 | 
						{ UMTRX, 1, 1, 8.0875e-5, "UmTRX diversity, 1 SPS" },
 | 
				
			||||||
	{ UMTRX, 4, 5.2103e-5, "UmTRX diversity, 4 SPS" },
 | 
						{ UMTRX, 4, 1, 5.2103e-5, "UmTRX diversity, 4 SPS" },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static double get_dev_offset(enum uhd_dev_type type,
 | 
					 | 
				
			||||||
			     int sps, bool diversity = false)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct uhd_dev_offset *offset;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Reject USRP1 */
 | 
					 | 
				
			||||||
	if (type == USRP1) {
 | 
					 | 
				
			||||||
		LOG(ERR) << "Invalid device type";
 | 
					 | 
				
			||||||
		return 0.0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Special cases (e.g. diversity receiver) */
 | 
					 | 
				
			||||||
	if (diversity) {
 | 
					 | 
				
			||||||
		if (type != UMTRX) {
 | 
					 | 
				
			||||||
			LOG(ALERT) << "Diversity on UmTRX only";
 | 
					 | 
				
			||||||
			return 0.0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		switch (sps) {
 | 
					 | 
				
			||||||
		case 1:
 | 
					 | 
				
			||||||
			offset = &special_offsets[0];
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case 4:
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			offset = &special_offsets[1];
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		/* Normal operation */
 | 
					 | 
				
			||||||
		switch (sps) {
 | 
					 | 
				
			||||||
		case 1:
 | 
					 | 
				
			||||||
			offset = &uhd_offsets[2 * type + 0];
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case 4:
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			offset = &uhd_offsets[2 * type + 1];
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::cout << "-- Setting " << offset->desc << std::endl;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return offset->offset;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Select sample rate based on device type and requested samples-per-symbol.
 | 
					 * Select sample rate based on device type and requested samples-per-symbol.
 | 
				
			||||||
@@ -159,12 +151,14 @@ static double select_rate(uhd_dev_type type, int sps, bool diversity = false)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	switch (type) {
 | 
						switch (type) {
 | 
				
			||||||
	case USRP2:
 | 
						case USRP2:
 | 
				
			||||||
 | 
						case X3XX:
 | 
				
			||||||
		return USRP2_BASE_RT * sps;
 | 
							return USRP2_BASE_RT * sps;
 | 
				
			||||||
	case B100:
 | 
						case B100:
 | 
				
			||||||
		return B100_BASE_RT * sps;
 | 
							return B100_BASE_RT * sps;
 | 
				
			||||||
	case B200:
 | 
						case B200:
 | 
				
			||||||
	case B210:
 | 
						case B210:
 | 
				
			||||||
	case E1XX:
 | 
						case E1XX:
 | 
				
			||||||
 | 
						case E3XX:
 | 
				
			||||||
	case UMTRX:
 | 
						case UMTRX:
 | 
				
			||||||
		return GSMRATE * sps;
 | 
							return GSMRATE * sps;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
@@ -175,23 +169,6 @@ static double select_rate(uhd_dev_type type, int sps, bool diversity = false)
 | 
				
			|||||||
	return -9999.99;
 | 
						return -9999.99;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Timestamp conversion
 | 
					 | 
				
			||||||
    @param timestamp a UHD or OpenBTS timestamp
 | 
					 | 
				
			||||||
    @param rate sample rate
 | 
					 | 
				
			||||||
    @return the converted timestamp
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
uhd::time_spec_t convert_time(TIMESTAMP ticks, double rate)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	double secs = (double) ticks / rate;
 | 
					 | 
				
			||||||
	return uhd::time_spec_t(secs);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TIMESTAMP convert_time(uhd::time_spec_t ts, double rate)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	TIMESTAMP ticks = ts.get_full_secs() * rate;
 | 
					 | 
				
			||||||
	return ts.get_tick_count(rate) + ticks;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
    Sample Buffer - Allows reading and writing of timed samples using OpenBTS
 | 
					    Sample Buffer - Allows reading and writing of timed samples using OpenBTS
 | 
				
			||||||
                    or UHD style timestamps. Time conversions are handled
 | 
					                    or UHD style timestamps. Time conversions are handled
 | 
				
			||||||
@@ -228,7 +205,7 @@ public:
 | 
				
			|||||||
	/** Buffer status string
 | 
						/** Buffer status string
 | 
				
			||||||
	    @return a formatted string describing internal buffer state
 | 
						    @return a formatted string describing internal buffer state
 | 
				
			||||||
	*/
 | 
						*/
 | 
				
			||||||
	std::string str_status() const;
 | 
						std::string str_status(size_t ts) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Formatted error string 
 | 
						/** Formatted error string 
 | 
				
			||||||
	    @param code an error code
 | 
						    @param code an error code
 | 
				
			||||||
@@ -265,13 +242,14 @@ private:
 | 
				
			|||||||
*/
 | 
					*/
 | 
				
			||||||
class uhd_device : public RadioDevice {
 | 
					class uhd_device : public RadioDevice {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	uhd_device(size_t sps, size_t chans, bool diversity, double offset);
 | 
						uhd_device(size_t tx_sps, size_t rx_sps,
 | 
				
			||||||
 | 
							   size_t chans, bool diversity, double offset);
 | 
				
			||||||
	~uhd_device();
 | 
						~uhd_device();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int open(const std::string &args, bool extref);
 | 
						int open(const std::string &args, bool extref, bool swap_channels);
 | 
				
			||||||
	bool start();
 | 
						bool start();
 | 
				
			||||||
	bool stop();
 | 
						bool stop();
 | 
				
			||||||
	void restart();
 | 
						bool restart();
 | 
				
			||||||
	void setPriority(float prio);
 | 
						void setPriority(float prio);
 | 
				
			||||||
	enum TxWindowType getWindowType() { return tx_window; }
 | 
						enum TxWindowType getWindowType() { return tx_window; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -286,11 +264,11 @@ 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inline TIMESTAMP initialWriteTimestamp() { return ts_initial * sps; }
 | 
						inline TIMESTAMP initialWriteTimestamp();
 | 
				
			||||||
	inline TIMESTAMP initialReadTimestamp() { return ts_initial; }
 | 
						inline TIMESTAMP initialReadTimestamp();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inline double fullScaleInputValue() { return (dev_type==UMTRX) ? (32000 * UMTRX_TX_AMPL) : (32000 * USRP_TX_AMPL); }
 | 
						double fullScaleInputValue();
 | 
				
			||||||
	inline double fullScaleOutputValue() { return 32000; }
 | 
						double fullScaleOutputValue();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	double setRxGain(double db, size_t chan);
 | 
						double setRxGain(double db, size_t chan);
 | 
				
			||||||
	double getRxGain(size_t chan);
 | 
						double getRxGain(size_t chan);
 | 
				
			||||||
@@ -316,8 +294,9 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	enum err_code {
 | 
						enum err_code {
 | 
				
			||||||
		ERROR_TIMING = -1,
 | 
							ERROR_TIMING = -1,
 | 
				
			||||||
		ERROR_UNRECOVERABLE = -2,
 | 
							ERROR_TIMEOUT = -2,
 | 
				
			||||||
		ERROR_UNHANDLED = -3,
 | 
							ERROR_UNRECOVERABLE = -3,
 | 
				
			||||||
 | 
							ERROR_UNHANDLED = -4,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
@@ -327,7 +306,7 @@ private:
 | 
				
			|||||||
	enum TxWindowType tx_window;
 | 
						enum TxWindowType tx_window;
 | 
				
			||||||
	enum uhd_dev_type dev_type;
 | 
						enum uhd_dev_type dev_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	size_t sps, chans;
 | 
						size_t tx_sps, rx_sps, chans;
 | 
				
			||||||
	double tx_rate, rx_rate;
 | 
						double tx_rate, rx_rate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	double tx_gain_min, tx_gain_max;
 | 
						double tx_gain_min, tx_gain_max;
 | 
				
			||||||
@@ -349,6 +328,7 @@ private:
 | 
				
			|||||||
	std::vector<smpl_buf *> rx_buffers;
 | 
						std::vector<smpl_buf *> rx_buffers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void init_gains();
 | 
						void init_gains();
 | 
				
			||||||
 | 
						double get_dev_offset(bool edge, bool diversity);
 | 
				
			||||||
	int set_master_clk(double rate);
 | 
						int set_master_clk(double rate);
 | 
				
			||||||
	int set_rates(double tx_rate, double rx_rate);
 | 
						int set_rates(double tx_rate, double rx_rate);
 | 
				
			||||||
	bool parse_dev_type();
 | 
						bool parse_dev_type();
 | 
				
			||||||
@@ -361,8 +341,9 @@ private:
 | 
				
			|||||||
	uhd::tune_request_t select_freq(double wFreq, size_t chan, bool tx);
 | 
						uhd::tune_request_t select_freq(double wFreq, size_t chan, bool tx);
 | 
				
			||||||
	bool set_freq(double freq, size_t chan, bool tx);
 | 
						bool set_freq(double freq, size_t chan, bool tx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Thread async_event_thrd;
 | 
						Thread *async_event_thrd;
 | 
				
			||||||
	bool diversity;
 | 
						bool diversity;
 | 
				
			||||||
 | 
						Mutex tune_lock;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void *async_event_loop(uhd_device *dev)
 | 
					void *async_event_loop(uhd_device *dev)
 | 
				
			||||||
@@ -399,14 +380,22 @@ void uhd_msg_handler(uhd::msg::type_t type, const std::string &msg)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uhd_device::uhd_device(size_t sps, size_t chans, bool diversity, double offset)
 | 
					static void thread_enable_cancel(bool cancel)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						cancel ? pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) :
 | 
				
			||||||
 | 
							 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uhd_device::uhd_device(size_t tx_sps, size_t rx_sps,
 | 
				
			||||||
 | 
							       size_t chans, bool diversity, double offset)
 | 
				
			||||||
	: tx_gain_min(0.0), tx_gain_max(0.0),
 | 
						: tx_gain_min(0.0), tx_gain_max(0.0),
 | 
				
			||||||
	  rx_gain_min(0.0), rx_gain_max(0.0),
 | 
						  rx_gain_min(0.0), rx_gain_max(0.0),
 | 
				
			||||||
	  tx_spp(0), rx_spp(0),
 | 
						  tx_spp(0), rx_spp(0),
 | 
				
			||||||
	  started(false), aligned(false), rx_pkt_cnt(0), drop_cnt(0),
 | 
						  started(false), aligned(false), rx_pkt_cnt(0), drop_cnt(0),
 | 
				
			||||||
	  prev_ts(0,0), ts_initial(0), ts_offset(0)
 | 
						  prev_ts(0,0), ts_initial(0), ts_offset(0)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	this->sps = sps;
 | 
						this->tx_sps = tx_sps;
 | 
				
			||||||
 | 
						this->rx_sps = rx_sps;
 | 
				
			||||||
	this->chans = chans;
 | 
						this->chans = chans;
 | 
				
			||||||
	this->offset = offset;
 | 
						this->offset = offset;
 | 
				
			||||||
	this->diversity = diversity;
 | 
						this->diversity = diversity;
 | 
				
			||||||
@@ -468,6 +457,64 @@ void uhd_device::init_gains()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					double uhd_device::get_dev_offset(bool edge, bool diversity)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct uhd_dev_offset *offset = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Reject USRP1 */
 | 
				
			||||||
 | 
						if (dev_type == USRP1) {
 | 
				
			||||||
 | 
							LOG(ERR) << "Invalid device type";
 | 
				
			||||||
 | 
							return 0.0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (edge && diversity) {
 | 
				
			||||||
 | 
							LOG(ERR) << "Unsupported configuration";
 | 
				
			||||||
 | 
							return 0.0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (edge && (dev_type != B200) &&
 | 
				
			||||||
 | 
						    (dev_type != B210) && (dev_type != UMTRX)) {
 | 
				
			||||||
 | 
							LOG(ALERT) << "EDGE is supported on B200/B210 and UmTRX only";
 | 
				
			||||||
 | 
							return 0.0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Special cases (e.g. diversity receiver) */
 | 
				
			||||||
 | 
						if (diversity) {
 | 
				
			||||||
 | 
							if (dev_type != UMTRX) {
 | 
				
			||||||
 | 
								LOG(ALERT) << "Diversity on UmTRX only";
 | 
				
			||||||
 | 
								return 0.0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch (tx_sps) {
 | 
				
			||||||
 | 
							case 1:
 | 
				
			||||||
 | 
								offset = &special_offsets[0];
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 4:
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								offset = &special_offsets[1];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							/* Search for matching offset value */
 | 
				
			||||||
 | 
							for (size_t i = 0; i < NUM_UHD_OFFSETS; i++) {
 | 
				
			||||||
 | 
								if ((dev_type == uhd_offsets[i].type) &&
 | 
				
			||||||
 | 
									(tx_sps == uhd_offsets[i].tx_sps) &&
 | 
				
			||||||
 | 
									(rx_sps == uhd_offsets[i].rx_sps)) {
 | 
				
			||||||
 | 
									offset = &uhd_offsets[i];
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!offset) {
 | 
				
			||||||
 | 
							LOG(ERR) << "Invalid device configuration";
 | 
				
			||||||
 | 
							return 0.0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::cout << "-- Setting " << offset->desc << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return offset->offset;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int uhd_device::set_master_clk(double clk_rate)
 | 
					int uhd_device::set_master_clk(double clk_rate)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	double actual, offset, limit = 1.0;
 | 
						double actual, offset, limit = 1.0;
 | 
				
			||||||
@@ -499,7 +546,7 @@ int uhd_device::set_rates(double tx_rate, double rx_rate)
 | 
				
			|||||||
	double tx_offset, rx_offset;
 | 
						double tx_offset, rx_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* B2XX and E1xx are the only device where we set FPGA clocking */
 | 
						/* B2XX and E1xx are the only device where we set FPGA clocking */
 | 
				
			||||||
	if ((dev_type == B200) || (dev_type == B210)) {
 | 
						if ((dev_type == B200) || (dev_type == B210) || (dev_type == E3XX)) {
 | 
				
			||||||
		if (set_master_clk(B2XX_CLK_RT) < 0)
 | 
							if (set_master_clk(B2XX_CLK_RT) < 0)
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -543,7 +590,6 @@ double uhd_device::setTxGain(double db, size_t chan)
 | 
				
			|||||||
		std::vector<std::string> gain_stages = usrp_dev->get_tx_gain_names(0);
 | 
							std::vector<std::string> gain_stages = usrp_dev->get_tx_gain_names(0);
 | 
				
			||||||
		if (gain_stages[0] == "VGA" || gain_stages[0] == "PA") {
 | 
							if (gain_stages[0] == "VGA" || gain_stages[0] == "PA") {
 | 
				
			||||||
			usrp_dev->set_tx_gain(db, chan);
 | 
								usrp_dev->set_tx_gain(db, chan);
 | 
				
			||||||
			tx_gains[chan] = usrp_dev->get_tx_gain(chan);
 | 
					 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			// New UHD versions support split configuration of
 | 
								// New UHD versions support split configuration of
 | 
				
			||||||
			// Tx gain stages. We utilize this to set the gain
 | 
								// Tx gain stages. We utilize this to set the gain
 | 
				
			||||||
@@ -552,13 +598,13 @@ double uhd_device::setTxGain(double db, size_t chan)
 | 
				
			|||||||
			// one and VGA2 is the best when 23dB or lower.
 | 
								// 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(UMTRX_VGA1_DEF, "VGA1", chan);
 | 
				
			||||||
			usrp_dev->set_tx_gain(db-UMTRX_VGA1_DEF, "VGA2", chan);
 | 
								usrp_dev->set_tx_gain(db-UMTRX_VGA1_DEF, "VGA2", chan);
 | 
				
			||||||
			tx_gains[chan] = usrp_dev->get_tx_gain(chan);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		usrp_dev->set_tx_gain(db, chan);
 | 
							usrp_dev->set_tx_gain(db, chan);
 | 
				
			||||||
		tx_gains[chan] = usrp_dev->get_tx_gain(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 (asked for " << db << "dB)";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return tx_gains[chan];
 | 
						return tx_gains[chan];
 | 
				
			||||||
@@ -599,8 +645,8 @@ bool uhd_device::parse_dev_type()
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	std::string mboard_str, dev_str;
 | 
						std::string mboard_str, dev_str;
 | 
				
			||||||
	uhd::property_tree::sptr prop_tree;
 | 
						uhd::property_tree::sptr prop_tree;
 | 
				
			||||||
	size_t usrp1_str, usrp2_str, e100_str, e110_str,
 | 
						size_t usrp1_str, usrp2_str, e100_str, e110_str, e310_str, e3xx_str,
 | 
				
			||||||
	       b100_str, b200_str, b210_str, umtrx_str;
 | 
						       b100_str, b200_str, b210_str, x300_str, x310_str, umtrx_str;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	prop_tree = usrp_dev->get_device()->get_tree();
 | 
						prop_tree = usrp_dev->get_device()->get_tree();
 | 
				
			||||||
	dev_str = prop_tree->access<std::string>("/name").get();
 | 
						dev_str = prop_tree->access<std::string>("/name").get();
 | 
				
			||||||
@@ -613,6 +659,10 @@ bool uhd_device::parse_dev_type()
 | 
				
			|||||||
	b210_str = mboard_str.find("B210");
 | 
						b210_str = mboard_str.find("B210");
 | 
				
			||||||
	e100_str = mboard_str.find("E100");
 | 
						e100_str = mboard_str.find("E100");
 | 
				
			||||||
	e110_str = mboard_str.find("E110");
 | 
						e110_str = mboard_str.find("E110");
 | 
				
			||||||
 | 
						e310_str = mboard_str.find("E310");
 | 
				
			||||||
 | 
						e3xx_str = mboard_str.find("E3XX");
 | 
				
			||||||
 | 
						x300_str = mboard_str.find("X300");
 | 
				
			||||||
 | 
						x310_str = mboard_str.find("X310");
 | 
				
			||||||
	umtrx_str = dev_str.find("UmTRX");
 | 
						umtrx_str = dev_str.find("UmTRX");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (usrp1_str != std::string::npos) {
 | 
						if (usrp1_str != std::string::npos) {
 | 
				
			||||||
@@ -640,11 +690,22 @@ bool uhd_device::parse_dev_type()
 | 
				
			|||||||
	} else if (usrp2_str != std::string::npos) {
 | 
						} else if (usrp2_str != std::string::npos) {
 | 
				
			||||||
		tx_window = TX_WINDOW_FIXED;
 | 
							tx_window = TX_WINDOW_FIXED;
 | 
				
			||||||
		dev_type = USRP2;
 | 
							dev_type = USRP2;
 | 
				
			||||||
 | 
						} else if ((e310_str != std::string::npos) ||
 | 
				
			||||||
 | 
							   (e3xx_str != std::string::npos)) {
 | 
				
			||||||
 | 
							tx_window = TX_WINDOW_FIXED;
 | 
				
			||||||
 | 
							dev_type = E3XX;
 | 
				
			||||||
 | 
						} else if (x300_str != std::string::npos) {
 | 
				
			||||||
 | 
							tx_window = TX_WINDOW_FIXED;
 | 
				
			||||||
 | 
							dev_type = X3XX;
 | 
				
			||||||
 | 
						} else if (x310_str != std::string::npos) {
 | 
				
			||||||
 | 
							tx_window = TX_WINDOW_FIXED;
 | 
				
			||||||
 | 
							dev_type = X3XX;
 | 
				
			||||||
	} else if (umtrx_str != std::string::npos) {
 | 
						} else if (umtrx_str != std::string::npos) {
 | 
				
			||||||
		tx_window = TX_WINDOW_FIXED;
 | 
							tx_window = TX_WINDOW_FIXED;
 | 
				
			||||||
		dev_type = UMTRX;
 | 
							dev_type = UMTRX;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		LOG(ALERT) << "Unknown UHD device type " << dev_str;
 | 
							LOG(ALERT) << "Unknown UHD device type "
 | 
				
			||||||
 | 
								   << dev_str << " " << mboard_str;
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -659,7 +720,27 @@ bool uhd_device::parse_dev_type()
 | 
				
			|||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int uhd_device::open(const std::string &args, bool extref)
 | 
					/*
 | 
				
			||||||
 | 
					 * Check for UHD version > 3.9.0 for E3XX support
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static bool uhd_e3xx_version_chk()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						std::string ver = uhd::get_version_string();
 | 
				
			||||||
 | 
						std::string major_str(ver.begin(), ver.begin() + 3);
 | 
				
			||||||
 | 
						std::string minor_str(ver.begin() + 4, ver.begin() + 7);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int major_val = atoi(major_str.c_str());
 | 
				
			||||||
 | 
						int minor_val = atoi(minor_str.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (major_val < 3)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						if (minor_val < 9)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int uhd_device::open(const std::string &args, bool extref, bool swap_channels)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	// Find UHD devices
 | 
						// Find UHD devices
 | 
				
			||||||
	uhd::device_addr_t addr(args);
 | 
						uhd::device_addr_t addr(args);
 | 
				
			||||||
@@ -674,7 +755,7 @@ int uhd_device::open(const std::string &args, bool extref)
 | 
				
			|||||||
	try {
 | 
						try {
 | 
				
			||||||
		usrp_dev = uhd::usrp::multi_usrp::make(addr);
 | 
							usrp_dev = uhd::usrp::multi_usrp::make(addr);
 | 
				
			||||||
	} catch(...) {
 | 
						} catch(...) {
 | 
				
			||||||
		LOG(ALERT) << "UHD make failed, device " << dev_addrs[0].to_string();
 | 
							LOG(ALERT) << "UHD make failed, device " << args;
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -682,10 +763,15 @@ int uhd_device::open(const std::string &args, bool extref)
 | 
				
			|||||||
	if (!parse_dev_type())
 | 
						if (!parse_dev_type())
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((dev_type == E3XX) && !uhd_e3xx_version_chk()) {
 | 
				
			||||||
 | 
							LOG(ALERT) << "E3XX requires UHD 003.009.000 or greater";
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Verify and set channels
 | 
						// Verify and set channels
 | 
				
			||||||
	if ((dev_type == B210) && (chans == 2)) {
 | 
						if ((dev_type == B210) && (chans == 2)) {
 | 
				
			||||||
	} else if ((dev_type == UMTRX) && (chans == 2)) {
 | 
						} else if ((dev_type == UMTRX) && (chans == 2)) {
 | 
				
			||||||
		uhd::usrp::subdev_spec_t subdev_spec("A:0 B:0");
 | 
							uhd::usrp::subdev_spec_t subdev_spec(swap_channels?"B:0 A:0":"A:0 B:0");
 | 
				
			||||||
		usrp_dev->set_tx_subdev_spec(subdev_spec);
 | 
							usrp_dev->set_tx_subdev_spec(subdev_spec);
 | 
				
			||||||
		usrp_dev->set_rx_subdev_spec(subdev_spec);
 | 
							usrp_dev->set_rx_subdev_spec(subdev_spec);
 | 
				
			||||||
	} else if (chans != 1) {
 | 
						} else if (chans != 1) {
 | 
				
			||||||
@@ -703,12 +789,8 @@ int uhd_device::open(const std::string &args, bool extref)
 | 
				
			|||||||
		usrp_dev->set_clock_source("external");
 | 
							usrp_dev->set_clock_source("external");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Set rates
 | 
						// Set rates
 | 
				
			||||||
	double _rx_rate;
 | 
						double _tx_rate = select_rate(dev_type, tx_sps);
 | 
				
			||||||
	double _tx_rate = select_rate(dev_type, sps);
 | 
						double _rx_rate = select_rate(dev_type, rx_sps, diversity);
 | 
				
			||||||
	if (diversity)
 | 
					 | 
				
			||||||
		_rx_rate = select_rate(dev_type, 1, true);
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		_rx_rate = _tx_rate / sps;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((_tx_rate < 0.0) || (_rx_rate < 0.0))
 | 
						if ((_tx_rate < 0.0) || (_rx_rate < 0.0))
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
@@ -742,8 +824,14 @@ int uhd_device::open(const std::string &args, bool extref)
 | 
				
			|||||||
	for (size_t i = 0; i < rx_buffers.size(); i++)
 | 
						for (size_t i = 0; i < rx_buffers.size(); i++)
 | 
				
			||||||
		rx_buffers[i] = new smpl_buf(buf_len, rx_rate);
 | 
							rx_buffers[i] = new smpl_buf(buf_len, rx_rate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Set receive chain sample offset 
 | 
						// Set receive chain sample offset. Trigger the EDGE offset
 | 
				
			||||||
	double offset = get_dev_offset(dev_type, sps, diversity);
 | 
						// table by checking for 4 SPS on the receive path. No other
 | 
				
			||||||
 | 
						// configuration supports using 4 SPS.
 | 
				
			||||||
 | 
						bool edge = false;
 | 
				
			||||||
 | 
						if (rx_sps == 4)
 | 
				
			||||||
 | 
							edge = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						double offset = get_dev_offset(edge, diversity);
 | 
				
			||||||
	if (offset == 0.0) {
 | 
						if (offset == 0.0) {
 | 
				
			||||||
		LOG(ERR) << "Unsupported configuration, no correction applied";
 | 
							LOG(ERR) << "Unsupported configuration, no correction applied";
 | 
				
			||||||
		ts_offset = 0;
 | 
							ts_offset = 0;
 | 
				
			||||||
@@ -764,10 +852,12 @@ int uhd_device::open(const std::string &args, bool extref)
 | 
				
			|||||||
	case B100:
 | 
						case B100:
 | 
				
			||||||
		return RESAMP_64M;
 | 
							return RESAMP_64M;
 | 
				
			||||||
	case USRP2:
 | 
						case USRP2:
 | 
				
			||||||
 | 
						case X3XX:
 | 
				
			||||||
		return RESAMP_100M;
 | 
							return RESAMP_100M;
 | 
				
			||||||
	case B200:
 | 
						case B200:
 | 
				
			||||||
	case B210:
 | 
						case B210:
 | 
				
			||||||
	case E1XX:
 | 
						case E1XX:
 | 
				
			||||||
 | 
						case E3XX:
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -779,7 +869,7 @@ bool uhd_device::flush_recv(size_t num_pkts)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	uhd::rx_metadata_t md;
 | 
						uhd::rx_metadata_t md;
 | 
				
			||||||
	size_t num_smpls;
 | 
						size_t num_smpls;
 | 
				
			||||||
	float timeout = 0.1f;
 | 
						float timeout = UHD_RESTART_TIMEOUT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::vector<std::vector<short> >
 | 
						std::vector<std::vector<short> >
 | 
				
			||||||
		pkt_bufs(chans, std::vector<short>(2 * rx_spp));
 | 
							pkt_bufs(chans, std::vector<short>(2 * rx_spp));
 | 
				
			||||||
@@ -795,12 +885,14 @@ bool uhd_device::flush_recv(size_t num_pkts)
 | 
				
			|||||||
		if (!num_smpls) {
 | 
							if (!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) << "Device timed out";
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ts_initial = convert_time(md.time_spec, rx_rate);
 | 
							ts_initial = md.time_spec.to_ticks(rx_rate);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOG(INFO) << "Initial timestamp " << ts_initial << std::endl;
 | 
						LOG(INFO) << "Initial timestamp " << ts_initial << std::endl;
 | 
				
			||||||
@@ -808,7 +900,7 @@ bool uhd_device::flush_recv(size_t num_pkts)
 | 
				
			|||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void uhd_device::restart()
 | 
					bool uhd_device::restart()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* Allow 100 ms delay to align multi-channel streams */
 | 
						/* Allow 100 ms delay to align multi-channel streams */
 | 
				
			||||||
	double delay = 0.1;
 | 
						double delay = 0.1;
 | 
				
			||||||
@@ -823,7 +915,7 @@ void uhd_device::restart()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	usrp_dev->issue_stream_cmd(cmd);
 | 
						usrp_dev->issue_stream_cmd(cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	flush_recv(1);
 | 
						return flush_recv(10);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool uhd_device::start()
 | 
					bool uhd_device::start()
 | 
				
			||||||
@@ -839,10 +931,12 @@ bool uhd_device::start()
 | 
				
			|||||||
	uhd::msg::register_handler(&uhd_msg_handler);
 | 
						uhd::msg::register_handler(&uhd_msg_handler);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Start asynchronous event (underrun check) loop
 | 
						// Start asynchronous event (underrun check) loop
 | 
				
			||||||
	async_event_thrd.start((void * (*)(void*))async_event_loop, (void*)this);
 | 
						async_event_thrd = new Thread();
 | 
				
			||||||
 | 
						async_event_thrd->start((void * (*)(void*))async_event_loop, (void*)this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Start streaming
 | 
						// Start streaming
 | 
				
			||||||
	restart();
 | 
						if (!restart())
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Display usrp time
 | 
						// Display usrp time
 | 
				
			||||||
	double time_now = usrp_dev->get_time_now().get_real_secs();
 | 
						double time_now = usrp_dev->get_time_now().get_real_secs();
 | 
				
			||||||
@@ -862,6 +956,10 @@ bool uhd_device::stop()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	usrp_dev->issue_stream_cmd(stream_cmd);
 | 
						usrp_dev->issue_stream_cmd(stream_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						async_event_thrd->cancel();
 | 
				
			||||||
 | 
						async_event_thrd->join();
 | 
				
			||||||
 | 
						delete async_event_thrd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	started = false;
 | 
						started = false;
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -875,7 +973,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 +980,7 @@ 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) {
 | 
								return ERROR_TIMEOUT;
 | 
				
			||||||
				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:
 | 
				
			||||||
@@ -936,14 +1029,14 @@ int uhd_device::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
 | 
				
			|||||||
	// Shift read time with respect to transmit clock
 | 
						// Shift read time with respect to transmit clock
 | 
				
			||||||
	timestamp += ts_offset;
 | 
						timestamp += ts_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ts = convert_time(timestamp, rx_rate);
 | 
						ts = uhd::time_spec_t::from_ticks(timestamp, rx_rate);
 | 
				
			||||||
	LOG(DEBUG) << "Requested timestamp = " << ts.get_real_secs();
 | 
						LOG(DEBUG) << "Requested timestamp = " << ts.get_real_secs();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Check that timestamp is valid
 | 
						// Check that timestamp is valid
 | 
				
			||||||
	rc = rx_buffers[0]->avail_smpls(timestamp);
 | 
						rc = rx_buffers[0]->avail_smpls(timestamp);
 | 
				
			||||||
	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(timestamp);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -957,8 +1050,11 @@ int uhd_device::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Receive samples from the usrp until we have enough
 | 
						// Receive samples from the usrp until we have enough
 | 
				
			||||||
	while (rx_buffers[0]->avail_smpls(timestamp) < len) {
 | 
						while (rx_buffers[0]->avail_smpls(timestamp) < len) {
 | 
				
			||||||
 | 
							thread_enable_cancel(false);
 | 
				
			||||||
		size_t num_smpls = rx_stream->recv(pkt_ptrs, rx_spp,
 | 
							size_t num_smpls = rx_stream->recv(pkt_ptrs, rx_spp,
 | 
				
			||||||
						   metadata, 0.1, true);
 | 
											   metadata, 0.1, true);
 | 
				
			||||||
 | 
							thread_enable_cancel(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rx_pkt_cnt++;
 | 
							rx_pkt_cnt++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Check for errors 
 | 
							// Check for errors 
 | 
				
			||||||
@@ -968,6 +1064,9 @@ int uhd_device::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
 | 
				
			|||||||
			LOG(ALERT) << "UHD: Version " << uhd::get_version_string();
 | 
								LOG(ALERT) << "UHD: Version " << uhd::get_version_string();
 | 
				
			||||||
			LOG(ALERT) << "UHD: Unrecoverable error, exiting...";
 | 
								LOG(ALERT) << "UHD: Unrecoverable error, exiting...";
 | 
				
			||||||
			exit(-1);
 | 
								exit(-1);
 | 
				
			||||||
 | 
							case ERROR_TIMEOUT:
 | 
				
			||||||
 | 
								// Assume stopping condition
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
		case ERROR_TIMING:
 | 
							case ERROR_TIMING:
 | 
				
			||||||
			restart();
 | 
								restart();
 | 
				
			||||||
		case ERROR_UNHANDLED:
 | 
							case ERROR_UNHANDLED:
 | 
				
			||||||
@@ -985,7 +1084,7 @@ int uhd_device::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
 | 
				
			|||||||
			// Continue on local overrun, exit on other errors
 | 
								// Continue on local overrun, exit on other errors
 | 
				
			||||||
			if ((rc < 0)) {
 | 
								if ((rc < 0)) {
 | 
				
			||||||
				LOG(ERR) << rx_buffers[i]->str_code(rc);
 | 
									LOG(ERR) << rx_buffers[i]->str_code(rc);
 | 
				
			||||||
				LOG(ERR) << rx_buffers[i]->str_status();
 | 
									LOG(ERR) << rx_buffers[i]->str_status(timestamp);
 | 
				
			||||||
				if (rc != smpl_buf::ERROR_OVERFLOW)
 | 
									if (rc != smpl_buf::ERROR_OVERFLOW)
 | 
				
			||||||
					return 0;
 | 
										return 0;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -997,7 +1096,7 @@ int uhd_device::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
 | 
				
			|||||||
		rc = rx_buffers[i]->read(bufs[i], len, timestamp);
 | 
							rc = rx_buffers[i]->read(bufs[i], len, timestamp);
 | 
				
			||||||
		if ((rc < 0) || (rc != len)) {
 | 
							if ((rc < 0) || (rc != len)) {
 | 
				
			||||||
			LOG(ERR) << rx_buffers[i]->str_code(rc);
 | 
								LOG(ERR) << rx_buffers[i]->str_code(rc);
 | 
				
			||||||
			LOG(ERR) << rx_buffers[i]->str_status();
 | 
								LOG(ERR) << rx_buffers[i]->str_status(timestamp);
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1012,7 +1111,7 @@ int uhd_device::writeSamples(std::vector<short *> &bufs, int len, bool *underrun
 | 
				
			|||||||
	metadata.has_time_spec = true;
 | 
						metadata.has_time_spec = true;
 | 
				
			||||||
	metadata.start_of_burst = false;
 | 
						metadata.start_of_burst = false;
 | 
				
			||||||
	metadata.end_of_burst = false;
 | 
						metadata.end_of_burst = false;
 | 
				
			||||||
	metadata.time_spec = convert_time(timestamp, tx_rate);
 | 
						metadata.time_spec = uhd::time_spec_t::from_ticks(timestamp, tx_rate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*underrun = false;
 | 
						*underrun = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1046,7 +1145,10 @@ int uhd_device::writeSamples(std::vector<short *> &bufs, int len, bool *underrun
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						thread_enable_cancel(false);
 | 
				
			||||||
	size_t num_smpls = tx_stream->send(bufs, len, metadata);
 | 
						size_t num_smpls = tx_stream->send(bufs, len, metadata);
 | 
				
			||||||
 | 
						thread_enable_cancel(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (num_smpls != (unsigned) len) {
 | 
						if (num_smpls != (unsigned) len) {
 | 
				
			||||||
		LOG(ALERT) << "UHD: Device send timed out";
 | 
							LOG(ALERT) << "UHD: Device send timed out";
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1066,7 +1168,7 @@ uhd::tune_request_t uhd_device::select_freq(double freq, size_t chan, bool tx)
 | 
				
			|||||||
	uhd::tune_request_t treq(freq);
 | 
						uhd::tune_request_t treq(freq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dev_type == UMTRX) {
 | 
						if (dev_type == UMTRX) {
 | 
				
			||||||
		if (offset > 0.0)
 | 
							if (offset != 0.0)
 | 
				
			||||||
			return uhd::tune_request_t(freq, offset);
 | 
								return uhd::tune_request_t(freq, offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Don't use DSP tuning, because LMS6002D PLL steps are small enough.
 | 
							// Don't use DSP tuning, because LMS6002D PLL steps are small enough.
 | 
				
			||||||
@@ -1077,6 +1179,7 @@ uhd::tune_request_t uhd_device::select_freq(double freq, size_t chan, bool tx)
 | 
				
			|||||||
		treq.rf_freq = freq;
 | 
							treq.rf_freq = freq;
 | 
				
			||||||
		treq.dsp_freq_policy = uhd::tune_request_t::POLICY_MANUAL;
 | 
							treq.dsp_freq_policy = uhd::tune_request_t::POLICY_MANUAL;
 | 
				
			||||||
		treq.dsp_freq = 0.0;
 | 
							treq.dsp_freq = 0.0;
 | 
				
			||||||
 | 
							return treq;
 | 
				
			||||||
	} else if (chans == 1) {
 | 
						} else if (chans == 1) {
 | 
				
			||||||
		if (offset == 0.0)
 | 
							if (offset == 0.0)
 | 
				
			||||||
			return treq;
 | 
								return treq;
 | 
				
			||||||
@@ -1157,6 +1260,7 @@ bool uhd_device::setTxFreq(double wFreq, size_t chan)
 | 
				
			|||||||
		LOG(ALERT) << "Requested non-existent channel " << chan;
 | 
							LOG(ALERT) << "Requested non-existent channel " << chan;
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						ScopedLock lock(tune_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return set_freq(wFreq, chan, true);
 | 
						return set_freq(wFreq, chan, true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1167,6 +1271,7 @@ bool uhd_device::setRxFreq(double wFreq, size_t chan)
 | 
				
			|||||||
		LOG(ALERT) << "Requested non-existent channel " << chan;
 | 
							LOG(ALERT) << "Requested non-existent channel " << chan;
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						ScopedLock lock(tune_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return set_freq(wFreq, chan, false);
 | 
						return set_freq(wFreq, chan, false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1191,10 +1296,45 @@ double uhd_device::getRxFreq(size_t chan)
 | 
				
			|||||||
	return rx_freqs[chan];
 | 
						return rx_freqs[chan];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Only allow sampling the Rx path lower than Tx and not vice-versa.
 | 
				
			||||||
 | 
					 * Using Tx with 4 SPS and Rx at 1 SPS is the only allowed mixed
 | 
				
			||||||
 | 
					 * combination.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					TIMESTAMP uhd_device::initialWriteTimestamp()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (rx_sps == tx_sps)
 | 
				
			||||||
 | 
							return ts_initial;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return ts_initial * tx_sps;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TIMESTAMP uhd_device::initialReadTimestamp()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return ts_initial;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					double uhd_device::fullScaleInputValue()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (dev_type == UMTRX)
 | 
				
			||||||
 | 
							return (double) SHRT_MAX * UMTRX_TX_AMPL;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return (double) SHRT_MAX * USRP_TX_AMPL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					double uhd_device::fullScaleOutputValue()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return (double) SHRT_MAX;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool uhd_device::recv_async_msg()
 | 
					bool uhd_device::recv_async_msg()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uhd::async_metadata_t md;
 | 
						uhd::async_metadata_t md;
 | 
				
			||||||
	if (!usrp_dev->get_device()->recv_async_msg(md))
 | 
					
 | 
				
			||||||
 | 
						thread_enable_cancel(false);
 | 
				
			||||||
 | 
						bool rc = usrp_dev->get_device()->recv_async_msg(md);
 | 
				
			||||||
 | 
						thread_enable_cancel(true);
 | 
				
			||||||
 | 
						if (!rc)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Assume that any error requires resynchronization
 | 
						// Assume that any error requires resynchronization
 | 
				
			||||||
@@ -1303,7 +1443,7 @@ ssize_t smpl_buf::avail_smpls(TIMESTAMP timestamp) const
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
ssize_t smpl_buf::avail_smpls(uhd::time_spec_t timespec) const
 | 
					ssize_t smpl_buf::avail_smpls(uhd::time_spec_t timespec) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return avail_smpls(convert_time(timespec, clk_rt));
 | 
						return avail_smpls(timespec.to_ticks(clk_rt));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ssize_t smpl_buf::read(void *buf, size_t len, TIMESTAMP timestamp)
 | 
					ssize_t smpl_buf::read(void *buf, size_t len, TIMESTAMP timestamp)
 | 
				
			||||||
@@ -1349,7 +1489,7 @@ ssize_t smpl_buf::read(void *buf, size_t len, TIMESTAMP timestamp)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
ssize_t smpl_buf::read(void *buf, size_t len, uhd::time_spec_t ts)
 | 
					ssize_t smpl_buf::read(void *buf, size_t len, uhd::time_spec_t ts)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return read(buf, len, convert_time(ts, clk_rt));
 | 
						return read(buf, len, ts.to_ticks(clk_rt));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ssize_t smpl_buf::write(void *buf, size_t len, TIMESTAMP timestamp)
 | 
					ssize_t smpl_buf::write(void *buf, size_t len, TIMESTAMP timestamp)
 | 
				
			||||||
@@ -1362,6 +1502,19 @@ ssize_t smpl_buf::write(void *buf, size_t len, TIMESTAMP timestamp)
 | 
				
			|||||||
	if ((timestamp + len) <= time_end)
 | 
						if ((timestamp + len) <= time_end)
 | 
				
			||||||
		return ERROR_TIMESTAMP;
 | 
							return ERROR_TIMESTAMP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (timestamp < time_end) {
 | 
				
			||||||
 | 
							LOG(ERR) << "Overwriting old buffer data: timestamp="<<timestamp<<" time_end="<<time_end;
 | 
				
			||||||
 | 
							uhd::time_spec_t ts = uhd::time_spec_t::from_ticks(timestamp, clk_rt);
 | 
				
			||||||
 | 
							LOG(DEBUG) << "Requested timestamp = " << timestamp << " (real_sec=" << std::fixed << ts.get_real_secs() << " = " << ts.to_ticks(clk_rt) << ") rate=" << clk_rt;
 | 
				
			||||||
 | 
							// Do not return error here, because it's a rounding error and is not fatal
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (timestamp > time_end && time_end != 0) {
 | 
				
			||||||
 | 
							LOG(ERR) << "Skipping buffer data: timestamp="<<timestamp<<" time_end="<<time_end;
 | 
				
			||||||
 | 
							uhd::time_spec_t ts = uhd::time_spec_t::from_ticks(timestamp, clk_rt);
 | 
				
			||||||
 | 
							LOG(DEBUG) << "Requested timestamp = " << timestamp << " (real_sec=" << std::fixed << ts.get_real_secs() << " = " << ts.to_ticks(clk_rt) << ") rate=" << clk_rt;
 | 
				
			||||||
 | 
							// Do not return error here, because it's a rounding error and is not fatal
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Starting index
 | 
						// Starting index
 | 
				
			||||||
	size_t write_start = (data_start + (timestamp - time_start)) % buf_len;
 | 
						size_t write_start = (data_start + (timestamp - time_start)) % buf_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1393,14 +1546,15 @@ ssize_t smpl_buf::write(void *buf, size_t len, TIMESTAMP timestamp)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
ssize_t smpl_buf::write(void *buf, size_t len, uhd::time_spec_t ts)
 | 
					ssize_t smpl_buf::write(void *buf, size_t len, uhd::time_spec_t ts)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return write(buf, len, convert_time(ts, clk_rt));
 | 
						return write(buf, len, ts.to_ticks(clk_rt));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string smpl_buf::str_status() const
 | 
					std::string smpl_buf::str_status(size_t ts) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	std::ostringstream ost("Sample buffer: ");
 | 
						std::ostringstream ost("Sample buffer: ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ost << "length = " << buf_len;
 | 
						ost << "timestamp = " << ts;
 | 
				
			||||||
 | 
						ost << ", length = " << buf_len;
 | 
				
			||||||
	ost << ", time_start = " << time_start;
 | 
						ost << ", time_start = " << time_start;
 | 
				
			||||||
	ost << ", time_end = " << time_end;
 | 
						ost << ", time_end = " << time_end;
 | 
				
			||||||
	ost << ", data_start = " << data_start;
 | 
						ost << ", data_start = " << data_start;
 | 
				
			||||||
@@ -1425,8 +1579,8 @@ std::string smpl_buf::str_code(ssize_t code)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RadioDevice *RadioDevice::make(size_t sps, size_t chans,
 | 
					RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps,
 | 
				
			||||||
			       bool diversity, double offset)
 | 
								       size_t chans, bool diversity, double offset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return new uhd_device(sps, chans, diversity, offset);
 | 
						return new uhd_device(tx_sps, rx_sps, chans, diversity, offset);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,7 +59,7 @@ const dboardConfigType dboardConfig = TXA_RXB;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const double USRPDevice::masterClockRate = 52.0e6;
 | 
					const double USRPDevice::masterClockRate = 52.0e6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
USRPDevice::USRPDevice(size_t sps, size_t, bool)
 | 
					USRPDevice::USRPDevice(size_t sps)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  LOG(INFO) << "creating USRP device...";
 | 
					  LOG(INFO) << "creating USRP device...";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -89,7 +89,7 @@ USRPDevice::USRPDevice(size_t sps, size_t, bool)
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int USRPDevice::open(const std::string &, bool)
 | 
					int USRPDevice::open(const std::string &, bool, bool)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  writeLock.unlock();
 | 
					  writeLock.unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -600,7 +600,8 @@ bool USRPDevice::setTxFreq(double wFreq) { return true;};
 | 
				
			|||||||
bool USRPDevice::setRxFreq(double wFreq) { return true;};
 | 
					bool USRPDevice::setRxFreq(double wFreq) { return true;};
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RadioDevice *RadioDevice::make(size_t sps, size_t chans, bool diversity)
 | 
					RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps,
 | 
				
			||||||
 | 
								       size_t chans, bool diversity, double)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return new USRPDevice(sps, chans, diversity);
 | 
						return new USRPDevice(tx_sps);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -96,10 +96,10 @@ private:
 | 
				
			|||||||
 public:
 | 
					 public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Object constructor */
 | 
					  /** Object constructor */
 | 
				
			||||||
  USRPDevice(size_t sps, size_t chans = 1, bool diversity = false);
 | 
					  USRPDevice(size_t sps);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Instantiate the USRP */
 | 
					  /** Instantiate the USRP */
 | 
				
			||||||
  int open(const std::string &, bool);
 | 
					  int open(const std::string &, bool, bool);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Start the USRP */
 | 
					  /** Start the USRP */
 | 
				
			||||||
  bool start();
 | 
					  bool start();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,25 +25,25 @@
 | 
				
			|||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void neon_convert_ps_si16_4n(short *, float *, float *, int);
 | 
					void neon_convert_ps_si16_4n(short *, const float *, const float *, int);
 | 
				
			||||||
void neon_convert_si16_ps_4n(float *, short *, int);
 | 
					void neon_convert_si16_ps_4n(float *, const short *, int);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef HAVE_NEON
 | 
					#ifndef HAVE_NEON
 | 
				
			||||||
static void convert_si16_ps(float *out, short *in, int len)
 | 
					static void convert_si16_ps(float *out, const short *in, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	for (int i = 0; i < len; i++)
 | 
						for (int i = 0; i < len; i++)
 | 
				
			||||||
		out[i] = in[i];
 | 
							out[i] = in[i];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void convert_ps_si16(short *out, float *in, float scale, int len)
 | 
					static void convert_ps_si16(short *out, const float *in, float scale, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	for (int i = 0; i < len; i++)
 | 
						for (int i = 0; i < len; i++)
 | 
				
			||||||
		out[i] = in[i] * scale;
 | 
							out[i] = in[i] * scale;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
/* 4*N 16-bit signed integer conversion with remainder */
 | 
					/* 4*N 16-bit signed integer conversion with remainder */
 | 
				
			||||||
static void neon_convert_si16_ps(float *restrict out,
 | 
					static void neon_convert_si16_ps(float *out,
 | 
				
			||||||
				 short *restrict in,
 | 
									 const short *in,
 | 
				
			||||||
				 int len)
 | 
									 int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int start = len / 4 * 4;
 | 
						int start = len / 4 * 4;
 | 
				
			||||||
@@ -55,9 +55,9 @@ static void neon_convert_si16_ps(float *restrict out,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 4*N 16-bit signed integer conversion with remainder */
 | 
					/* 4*N 16-bit signed integer conversion with remainder */
 | 
				
			||||||
static void neon_convert_ps_si16(short *restrict out,
 | 
					static void neon_convert_ps_si16(short *out,
 | 
				
			||||||
				 float *restrict in,
 | 
									 const float *in,
 | 
				
			||||||
				 float *restrict scale,
 | 
									 const float *scale,
 | 
				
			||||||
				 int len)
 | 
									 int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int start = len / 4 * 4;
 | 
						int start = len / 4 * 4;
 | 
				
			||||||
@@ -69,7 +69,7 @@ static void neon_convert_ps_si16(short *restrict out,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void convert_float_short(short *out, float *in, float scale, int len)
 | 
					void convert_float_short(short *out, const float *in, float scale, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef HAVE_NEON
 | 
					#ifdef HAVE_NEON
 | 
				
			||||||
        float q[4] = { scale, scale, scale, scale };
 | 
					        float q[4] = { scale, scale, scale, scale };
 | 
				
			||||||
@@ -83,7 +83,7 @@ void convert_float_short(short *out, float *in, float scale, int len)
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void convert_short_float(float *out, short *in, int len)
 | 
					void convert_short_float(float *out, const short *in, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef HAVE_NEON
 | 
					#ifdef HAVE_NEON
 | 
				
			||||||
	if (len % 4)
 | 
						if (len % 4)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
#ifndef _CONVERT_H_
 | 
					#ifndef _CONVERT_H_
 | 
				
			||||||
#define _CONVERT_H_
 | 
					#define _CONVERT_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void convert_float_short(short *out, float *in, float scale, int len);
 | 
					void convert_float_short(short *out, const float *in, float scale, int len);
 | 
				
			||||||
void convert_short_float(float *out, short *in, int len);
 | 
					void convert_short_float(float *out, const short *in, int len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _CONVERT_H_ */
 | 
					#endif /* _CONVERT_H_ */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,26 +3,26 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void *convolve_h_alloc(int num);
 | 
					void *convolve_h_alloc(int num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int convolve_real(float *x, int x_len,
 | 
					int convolve_real(const float *x, int x_len,
 | 
				
			||||||
		  float *h, int h_len,
 | 
							  const float *h, int h_len,
 | 
				
			||||||
		  float *y, int y_len,
 | 
							  float *y, int y_len,
 | 
				
			||||||
		  int start, int len,
 | 
							  int start, int len,
 | 
				
			||||||
		  int step, int offset);
 | 
							  int step, int offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int convolve_complex(float *x, int x_len,
 | 
					int convolve_complex(const float *x, int x_len,
 | 
				
			||||||
		     float *h, int h_len,
 | 
							     const float *h, int h_len,
 | 
				
			||||||
		     float *y, int y_len,
 | 
							     float *y, int y_len,
 | 
				
			||||||
		     int start, int len,
 | 
							     int start, int len,
 | 
				
			||||||
		     int step, int offset);
 | 
							     int step, int offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int base_convolve_real(float *x, int x_len,
 | 
					int base_convolve_real(const float *x, int x_len,
 | 
				
			||||||
		       float *h, int h_len,
 | 
							       const float *h, int h_len,
 | 
				
			||||||
		       float *y, int y_len,
 | 
							       float *y, int y_len,
 | 
				
			||||||
		       int start, int len,
 | 
							       int start, int len,
 | 
				
			||||||
		       int step, int offset);
 | 
							       int step, int offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int base_convolve_complex(float *x, int x_len,
 | 
					int base_convolve_complex(const float *x, int x_len,
 | 
				
			||||||
			  float *h, int h_len,
 | 
								  const float *h, int h_len,
 | 
				
			||||||
			  float *y, int y_len,
 | 
								  float *y, int y_len,
 | 
				
			||||||
			  int start, int len,
 | 
								  int start, int len,
 | 
				
			||||||
			  int step, int offset);
 | 
								  int step, int offset);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,21 +26,21 @@
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Base multiply and accumulate complex-real */
 | 
					/* Base multiply and accumulate complex-real */
 | 
				
			||||||
static void mac_real(float *x, float *h, float *y)
 | 
					static void mac_real(const float *x, const float *h, float *y)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	y[0] += x[0] * h[0];
 | 
						y[0] += x[0] * h[0];
 | 
				
			||||||
	y[1] += x[1] * h[0];
 | 
						y[1] += x[1] * h[0];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Base multiply and accumulate complex-complex */
 | 
					/* Base multiply and accumulate complex-complex */
 | 
				
			||||||
static void mac_cmplx(float *x, float *h, float *y)
 | 
					static void mac_cmplx(const float *x, const float *h, float *y)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	y[0] += x[0] * h[0] - x[1] * h[1];
 | 
						y[0] += x[0] * h[0] - x[1] * h[1];
 | 
				
			||||||
	y[1] += x[0] * h[1] + x[1] * h[0];
 | 
						y[1] += x[0] * h[1] + x[1] * h[0];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Base vector complex-complex multiply and accumulate */
 | 
					/* Base vector complex-complex multiply and accumulate */
 | 
				
			||||||
static void mac_real_vec_n(float *x, float *h, float *y,
 | 
					static void mac_real_vec_n(const float *x, const float *h, float *y,
 | 
				
			||||||
			   int len, int step, int offset)
 | 
								   int len, int step, int offset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	for (int i = offset; i < len; i += step)
 | 
						for (int i = offset; i < len; i += step)
 | 
				
			||||||
@@ -48,7 +48,7 @@ static void mac_real_vec_n(float *x, float *h, float *y,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Base vector complex-complex multiply and accumulate */
 | 
					/* Base vector complex-complex multiply and accumulate */
 | 
				
			||||||
static void mac_cmplx_vec_n(float *x, float *h, float *y,
 | 
					static void mac_cmplx_vec_n(const float *x, const float *h, float *y,
 | 
				
			||||||
			    int len, int step, int offset)
 | 
								    int len, int step, int offset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	for (int i = offset; i < len; i += step)
 | 
						for (int i = offset; i < len; i += step)
 | 
				
			||||||
@@ -56,8 +56,8 @@ static void mac_cmplx_vec_n(float *x, float *h, float *y,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Base complex-real convolution */
 | 
					/* Base complex-real convolution */
 | 
				
			||||||
int _base_convolve_real(float *x, int x_len,
 | 
					int _base_convolve_real(const float *x, int x_len,
 | 
				
			||||||
			float *h, int h_len,
 | 
								const float *h, int h_len,
 | 
				
			||||||
			float *y, int y_len,
 | 
								float *y, int y_len,
 | 
				
			||||||
			int start, int len,
 | 
								int start, int len,
 | 
				
			||||||
			int step, int offset)
 | 
								int step, int offset)
 | 
				
			||||||
@@ -73,8 +73,8 @@ int _base_convolve_real(float *x, int x_len,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Base complex-complex convolution */
 | 
					/* Base complex-complex convolution */
 | 
				
			||||||
int _base_convolve_complex(float *x, int x_len,
 | 
					int _base_convolve_complex(const float *x, int x_len,
 | 
				
			||||||
			   float *h, int h_len,
 | 
								   const float *h, int h_len,
 | 
				
			||||||
			   float *y, int y_len,
 | 
								   float *y, int y_len,
 | 
				
			||||||
			   int start, int len,
 | 
								   int start, int len,
 | 
				
			||||||
			   int step, int offset)
 | 
								   int step, int offset)
 | 
				
			||||||
@@ -110,8 +110,8 @@ int bounds_check(int x_len, int h_len, int y_len,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* API: Non-aligned (no SSE) complex-real */
 | 
					/* API: Non-aligned (no SSE) complex-real */
 | 
				
			||||||
int base_convolve_real(float *x, int x_len,
 | 
					int base_convolve_real(const float *x, int x_len,
 | 
				
			||||||
		       float *h, int h_len,
 | 
							       const float *h, int h_len,
 | 
				
			||||||
		       float *y, int y_len,
 | 
							       float *y, int y_len,
 | 
				
			||||||
		       int start, int len,
 | 
							       int start, int len,
 | 
				
			||||||
		       int step, int offset)
 | 
							       int step, int offset)
 | 
				
			||||||
@@ -128,8 +128,8 @@ int base_convolve_real(float *x, int x_len,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* API: Non-aligned (no SSE) complex-complex */
 | 
					/* API: Non-aligned (no SSE) complex-complex */
 | 
				
			||||||
int base_convolve_complex(float *x, int x_len,
 | 
					int base_convolve_complex(const float *x, int x_len,
 | 
				
			||||||
			  float *h, int h_len,
 | 
								  const float *h, int h_len,
 | 
				
			||||||
			  float *y, int y_len,
 | 
								  float *y, int y_len,
 | 
				
			||||||
			  int start, int len,
 | 
								  int start, int len,
 | 
				
			||||||
			  int step, int offset)
 | 
								  int step, int offset)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,14 +37,17 @@
 | 
				
			|||||||
 *     1 - Uses minimized modulator (less computation, more distortion)
 | 
					 *     1 - Uses minimized modulator (less computation, more distortion)
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *     Other values are invalid. Receive path (uplink) is always
 | 
					 *     Other values are invalid. Receive path (uplink) is always
 | 
				
			||||||
 *     downsampled to 1 sps. Default to 4 sps for all cases except for
 | 
					 *     downsampled to 1 sps. Default to 4 sps for all cases.
 | 
				
			||||||
 *     ARM and non-SIMD enabled architectures.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#if defined(HAVE_NEON) || !defined(HAVE_SSE3)
 | 
					#define DEFAULT_TX_SPS		4
 | 
				
			||||||
#define DEFAULT_SPS		1
 | 
					
 | 
				
			||||||
#else
 | 
					/*
 | 
				
			||||||
#define DEFAULT_SPS		4
 | 
					 * Samples-per-symbol for uplink (receiver) path
 | 
				
			||||||
#endif
 | 
					 *     Do not modify this value. EDGE configures 4 sps automatically on
 | 
				
			||||||
 | 
					 *     B200/B210 devices only. Use of 4 sps on the receive path for other
 | 
				
			||||||
 | 
					 *     configurations is not supported.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define DEFAULT_RX_SPS		1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Default configuration parameters
 | 
					/* Default configuration parameters
 | 
				
			||||||
 *     Note that these values are only used if the particular key does not
 | 
					 *     Note that these values are only used if the particular key does not
 | 
				
			||||||
@@ -63,12 +66,17 @@ struct trx_config {
 | 
				
			|||||||
	std::string addr;
 | 
						std::string addr;
 | 
				
			||||||
	std::string dev_args;
 | 
						std::string dev_args;
 | 
				
			||||||
	unsigned port;
 | 
						unsigned port;
 | 
				
			||||||
	unsigned sps;
 | 
						unsigned tx_sps;
 | 
				
			||||||
 | 
						unsigned rx_sps;
 | 
				
			||||||
	unsigned chans;
 | 
						unsigned chans;
 | 
				
			||||||
 | 
						unsigned rtsc;
 | 
				
			||||||
	bool extref;
 | 
						bool extref;
 | 
				
			||||||
	bool filler;
 | 
						Transceiver::FillerType filler;
 | 
				
			||||||
	bool diversity;
 | 
						bool diversity;
 | 
				
			||||||
	double offset;
 | 
						double offset;
 | 
				
			||||||
 | 
						double rssi_offset;
 | 
				
			||||||
 | 
						bool swap_channels;
 | 
				
			||||||
 | 
						bool edge;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ConfigurationTable gConfig;
 | 
					ConfigurationTable gConfig;
 | 
				
			||||||
@@ -118,7 +126,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, edgestr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!testConfig())
 | 
						if (!testConfig())
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
@@ -154,19 +162,30 @@ bool trx_setup_config(struct trx_config *config)
 | 
				
			|||||||
			config->diversity = DEFAULT_DIVERSITY;
 | 
								config->diversity = DEFAULT_DIVERSITY;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!config->sps)
 | 
					 | 
				
			||||||
		config->sps = DEFAULT_SPS;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!config->chans)
 | 
					 | 
				
			||||||
		config->chans = DEFAULT_CHANS;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Diversity only supported on 2 channels */
 | 
						/* Diversity only supported on 2 channels */
 | 
				
			||||||
	if (config->diversity)
 | 
						if (config->diversity)
 | 
				
			||||||
		config->chans = 2;
 | 
							config->chans = 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						edgestr = config->edge ? "Enabled" : "Disabled";
 | 
				
			||||||
	refstr = config->extref ? "Enabled" : "Disabled";
 | 
						refstr = config->extref ? "Enabled" : "Disabled";
 | 
				
			||||||
	fillstr = config->filler ? "Enabled" : "Disabled";
 | 
					 | 
				
			||||||
	divstr = config->diversity ? "Enabled" : "Disabled";
 | 
						divstr = config->diversity ? "Enabled" : "Disabled";
 | 
				
			||||||
 | 
						switch (config->filler) {
 | 
				
			||||||
 | 
						case Transceiver::FILLER_DUMMY:
 | 
				
			||||||
 | 
							fillstr = "Dummy bursts";
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case Transceiver::FILLER_ZERO:
 | 
				
			||||||
 | 
							fillstr = "Disabled";
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case Transceiver::FILLER_NORM_RAND:
 | 
				
			||||||
 | 
							fillstr = "Normal busrts with random payload";
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case Transceiver::FILLER_EDGE_RAND:
 | 
				
			||||||
 | 
							fillstr = "EDGE busrts with random payload";
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case Transceiver::FILLER_ACCESS_RAND:
 | 
				
			||||||
 | 
							fillstr = "Access busrts with random payload";
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::ostringstream ost("");
 | 
						std::ostringstream ost("");
 | 
				
			||||||
	ost << "Config Settings" << std::endl;
 | 
						ost << "Config Settings" << std::endl;
 | 
				
			||||||
@@ -175,11 +194,15 @@ bool trx_setup_config(struct trx_config *config)
 | 
				
			|||||||
	ost << "   TRX Base Port........... " << config->port << std::endl;
 | 
						ost << "   TRX Base Port........... " << config->port << std::endl;
 | 
				
			||||||
	ost << "   TRX Address............. " << config->addr << std::endl;
 | 
						ost << "   TRX Address............. " << config->addr << std::endl;
 | 
				
			||||||
	ost << "   Channels................ " << config->chans << std::endl;
 | 
						ost << "   Channels................ " << config->chans << std::endl;
 | 
				
			||||||
	ost << "   Samples-per-Symbol...... " << config->sps << std::endl;
 | 
						ost << "   Tx Samples-per-Symbol... " << config->tx_sps << std::endl;
 | 
				
			||||||
 | 
						ost << "   Rx Samples-per-Symbol... " << config->rx_sps << std::endl;
 | 
				
			||||||
 | 
						ost << "   EDGE support............ " << edgestr << std::endl;
 | 
				
			||||||
	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 << "   Tuning offset........... " << config->offset << std::endl;
 | 
						ost << "   Tuning offset........... " << config->offset << std::endl;
 | 
				
			||||||
 | 
						ost << "   RSSI to dBm offset...... " << config->rssi_offset << std::endl;
 | 
				
			||||||
 | 
						ost << "   Swap channels........... " << config->swap_channels << std::endl;
 | 
				
			||||||
	std::cout << ost << std::endl;
 | 
						std::cout << ost << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
@@ -197,18 +220,23 @@ RadioInterface *makeRadioInterface(struct trx_config *config,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	RadioInterface *radio = NULL;
 | 
						RadioInterface *radio = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((config->rx_sps != 1) && (type != RadioDevice::NORMAL)) {
 | 
				
			||||||
 | 
							LOG(ALERT) << "Unsupported radio interface configuration";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (type) {
 | 
						switch (type) {
 | 
				
			||||||
	case RadioDevice::NORMAL:
 | 
						case RadioDevice::NORMAL:
 | 
				
			||||||
		radio = new RadioInterface(usrp, config->sps, config->chans);
 | 
							radio = new RadioInterface(usrp, config->tx_sps,
 | 
				
			||||||
 | 
										   config->rx_sps, config->chans);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case RadioDevice::RESAMP_64M:
 | 
						case RadioDevice::RESAMP_64M:
 | 
				
			||||||
	case RadioDevice::RESAMP_100M:
 | 
						case RadioDevice::RESAMP_100M:
 | 
				
			||||||
		radio = new RadioInterfaceResamp(usrp,
 | 
							radio = new RadioInterfaceResamp(usrp, config->tx_sps,
 | 
				
			||||||
						 config->sps, config->chans);
 | 
											 config->chans);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case RadioDevice::DIVERSITY:
 | 
						case RadioDevice::DIVERSITY:
 | 
				
			||||||
		radio = new RadioInterfaceDiversity(usrp,
 | 
							radio = new RadioInterfaceDiversity(usrp, config->tx_sps,
 | 
				
			||||||
						    config->sps, config->chans);
 | 
											    config->chans);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		LOG(ALERT) << "Unsupported radio interface configuration";
 | 
							LOG(ALERT) << "Unsupported radio interface configuration";
 | 
				
			||||||
@@ -234,9 +262,10 @@ Transceiver *makeTransceiver(struct trx_config *config, RadioInterface *radio)
 | 
				
			|||||||
	Transceiver *trx;
 | 
						Transceiver *trx;
 | 
				
			||||||
	VectorFIFO *fifo;
 | 
						VectorFIFO *fifo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	trx = new Transceiver(config->port, config->addr.c_str(), config->sps,
 | 
						trx = new Transceiver(config->port, config->addr.c_str(),
 | 
				
			||||||
			      config->chans, GSM::Time(3,0), radio);
 | 
								      config->tx_sps, config->rx_sps, config->chans,
 | 
				
			||||||
	if (!trx->init(config->filler)) {
 | 
								      GSM::Time(3,0), radio, config->rssi_offset);
 | 
				
			||||||
 | 
						if (!trx->init(config->filler, config->rtsc)) {
 | 
				
			||||||
		LOG(ALERT) << "Failed to initialize transceiver";
 | 
							LOG(ALERT) << "Failed to initialize transceiver";
 | 
				
			||||||
		delete trx;
 | 
							delete trx;
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
@@ -281,12 +310,17 @@ static void print_help()
 | 
				
			|||||||
		"  -l    Logging level (%s)\n"
 | 
							"  -l    Logging level (%s)\n"
 | 
				
			||||||
		"  -i    IP address of GSM core\n"
 | 
							"  -i    IP address of GSM core\n"
 | 
				
			||||||
		"  -p    Base port number\n"
 | 
							"  -p    Base port number\n"
 | 
				
			||||||
 | 
							"  -e    Enable EDGE receiver\n"
 | 
				
			||||||
		"  -d    Enable dual channel diversity receiver\n"
 | 
							"  -d    Enable dual channel diversity receiver\n"
 | 
				
			||||||
		"  -x    Enable external 10 MHz reference\n"
 | 
							"  -x    Enable external 10 MHz reference\n"
 | 
				
			||||||
		"  -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"
 | 
				
			||||||
		"  -o    Set baseband frequency offset (default=auto)\n",
 | 
							"  -o    Set baseband frequency offset (default=auto)\n"
 | 
				
			||||||
 | 
							"  -r    Random burst test mode with TSC\n"
 | 
				
			||||||
 | 
							"  -A    Random burst test mode with Access Bursts\n"
 | 
				
			||||||
 | 
							"  -R    RSSI to dBm offset in dB (default=0)\n"
 | 
				
			||||||
 | 
							"  -S    Swap channels (UmTRX only)\n",
 | 
				
			||||||
		"EMERG, ALERT, CRT, ERR, WARNING, NOTICE, INFO, DEBUG");
 | 
							"EMERG, ALERT, CRT, ERR, WARNING, NOTICE, INFO, DEBUG");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -295,14 +329,19 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
 | 
				
			|||||||
	int option;
 | 
						int option;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config->port = 0;
 | 
						config->port = 0;
 | 
				
			||||||
	config->sps = 0;
 | 
						config->tx_sps = DEFAULT_TX_SPS;
 | 
				
			||||||
	config->chans = 0;
 | 
						config->rx_sps = DEFAULT_RX_SPS;
 | 
				
			||||||
 | 
						config->chans = DEFAULT_CHANS;
 | 
				
			||||||
 | 
						config->rtsc = 0;
 | 
				
			||||||
	config->extref = false;
 | 
						config->extref = false;
 | 
				
			||||||
	config->filler = false;
 | 
						config->filler = Transceiver::FILLER_ZERO;
 | 
				
			||||||
	config->diversity = false;
 | 
						config->diversity = false;
 | 
				
			||||||
	config->offset = 0.0;
 | 
						config->offset = 0.0;
 | 
				
			||||||
 | 
						config->rssi_offset = 0.0;
 | 
				
			||||||
 | 
						config->swap_channels = false;
 | 
				
			||||||
 | 
						config->edge = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while ((option = getopt(argc, argv, "ha:l:i:p:c:dxfo:s:")) != -1) {
 | 
						while ((option = getopt(argc, argv, "ha:l:i:p:c:dxfo:s:r:AR:Se")) != -1) {
 | 
				
			||||||
		switch (option) {
 | 
							switch (option) {
 | 
				
			||||||
		case 'h':
 | 
							case 'h':
 | 
				
			||||||
			print_help();
 | 
								print_help();
 | 
				
			||||||
@@ -330,24 +369,57 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
 | 
				
			|||||||
			config->extref = true;
 | 
								config->extref = true;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 'f':
 | 
							case 'f':
 | 
				
			||||||
			config->filler = true;
 | 
								config->filler = Transceiver::FILLER_DUMMY;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 'o':
 | 
							case 'o':
 | 
				
			||||||
			config->offset = atof(optarg);
 | 
								config->offset = atof(optarg);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 's':
 | 
							case 's':
 | 
				
			||||||
			config->sps = atoi(optarg);
 | 
								config->tx_sps = atoi(optarg);
 | 
				
			||||||
			if ((config->sps != 1) && (config->sps != 4)) {
 | 
								break;
 | 
				
			||||||
				printf("Unsupported samples-per-symbol\n\n");
 | 
							case 'r':
 | 
				
			||||||
				print_help();
 | 
								config->rtsc = atoi(optarg);
 | 
				
			||||||
				exit(0);
 | 
								config->filler = Transceiver::FILLER_NORM_RAND;
 | 
				
			||||||
			}
 | 
								break;
 | 
				
			||||||
 | 
							case 'A':
 | 
				
			||||||
 | 
								config->filler = Transceiver::FILLER_ACCESS_RAND;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'R':
 | 
				
			||||||
 | 
								config->rssi_offset = atof(optarg);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'S':
 | 
				
			||||||
 | 
								config->swap_channels = true;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'e':
 | 
				
			||||||
 | 
								config->edge = true;
 | 
				
			||||||
 | 
								config->rx_sps = 4;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			print_help();
 | 
								print_help();
 | 
				
			||||||
			exit(0);
 | 
								exit(0);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (config->edge && (config->filler == Transceiver::FILLER_NORM_RAND))
 | 
				
			||||||
 | 
							config->filler = Transceiver::FILLER_EDGE_RAND;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((config->tx_sps != 1) && (config->tx_sps != 4)) {
 | 
				
			||||||
 | 
							printf("Unsupported samples-per-symbol %i\n\n", config->tx_sps);
 | 
				
			||||||
 | 
							print_help();
 | 
				
			||||||
 | 
							exit(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (config->edge && (config->tx_sps != 4)) {
 | 
				
			||||||
 | 
							printf("EDGE only supported at 4 samples per symbol\n\n");
 | 
				
			||||||
 | 
							print_help();
 | 
				
			||||||
 | 
							exit(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (config->rtsc > 7) {
 | 
				
			||||||
 | 
							printf("Invalid training sequence %i\n\n", config->rtsc);
 | 
				
			||||||
 | 
							print_help();
 | 
				
			||||||
 | 
							exit(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char *argv[])
 | 
					int main(int argc, char *argv[])
 | 
				
			||||||
@@ -373,9 +445,9 @@ int main(int argc, char *argv[])
 | 
				
			|||||||
	srandom(time(NULL));
 | 
						srandom(time(NULL));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Create the low level device object */
 | 
						/* Create the low level device object */
 | 
				
			||||||
	usrp = RadioDevice::make(config.sps, config.chans,
 | 
						usrp = RadioDevice::make(config.tx_sps, config.rx_sps, config.chans,
 | 
				
			||||||
				 config.diversity, config.offset);
 | 
									 config.diversity, config.offset);
 | 
				
			||||||
	type = usrp->open(config.dev_args, config.extref);
 | 
						type = usrp->open(config.dev_args, config.extref, config.swap_channels);
 | 
				
			||||||
	if (type < 0) {
 | 
						if (type < 0) {
 | 
				
			||||||
		LOG(ALERT) << "Failed to create radio device" << std::endl;
 | 
							LOG(ALERT) << "Failed to create radio device" << std::endl;
 | 
				
			||||||
		goto shutdown;
 | 
							goto shutdown;
 | 
				
			||||||
@@ -391,8 +463,6 @@ int main(int argc, char *argv[])
 | 
				
			|||||||
	if (!trx)
 | 
						if (!trx)
 | 
				
			||||||
		goto shutdown;
 | 
							goto shutdown;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	trx->start();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	chans = trx->numChans();
 | 
						chans = trx->numChans();
 | 
				
			||||||
	std::cout << "-- Transceiver active with "
 | 
						std::cout << "-- Transceiver active with "
 | 
				
			||||||
		  << chans << " channel(s)" << std::endl;
 | 
							  << chans << " channel(s)" << std::endl;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,32 +23,27 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void RadioClock::set(const GSM::Time& wTime)
 | 
					void RadioClock::set(const GSM::Time& wTime)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	mLock.lock();
 | 
						ScopedLock lock(mLock);
 | 
				
			||||||
	mClock = wTime;
 | 
						mClock = wTime;
 | 
				
			||||||
	updateSignal.signal();
 | 
						updateSignal.signal();
 | 
				
			||||||
	mLock.unlock();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void RadioClock::incTN()
 | 
					void RadioClock::incTN()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	mLock.lock();
 | 
						ScopedLock lock(mLock);
 | 
				
			||||||
	mClock.incTN();
 | 
						mClock.incTN();
 | 
				
			||||||
	updateSignal.signal();
 | 
						updateSignal.signal();
 | 
				
			||||||
	mLock.unlock();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GSM::Time RadioClock::get()
 | 
					GSM::Time RadioClock::get()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	mLock.lock();
 | 
						ScopedLock lock(mLock);
 | 
				
			||||||
	GSM::Time retVal = mClock;
 | 
						GSM::Time retVal = mClock;
 | 
				
			||||||
	mLock.unlock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return retVal;
 | 
						return retVal;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void RadioClock::wait()
 | 
					void RadioClock::wait()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	mLock.lock();
 | 
						ScopedLock lock(mLock);
 | 
				
			||||||
	updateSignal.wait(mLock,1);
 | 
						updateSignal.wait(mLock,1);
 | 
				
			||||||
	mLock.unlock();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,11 +37,11 @@ class RadioDevice {
 | 
				
			|||||||
  /* Radio interface types */
 | 
					  /* Radio interface types */
 | 
				
			||||||
  enum RadioInterfaceType { NORMAL, RESAMP_64M, RESAMP_100M, DIVERSITY };
 | 
					  enum RadioInterfaceType { NORMAL, RESAMP_64M, RESAMP_100M, DIVERSITY };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static RadioDevice *make(size_t sps, size_t chans = 1,
 | 
					  static RadioDevice *make(size_t tx_sps, size_t rx_sps = 1, size_t chans = 1,
 | 
				
			||||||
                           bool diversity = false, double offset = 0.0);
 | 
					                           bool diversity = false, double offset = 0.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Initialize the USRP */
 | 
					  /** Initialize the USRP */
 | 
				
			||||||
  virtual int open(const std::string &args = "", bool extref = false)=0;
 | 
					  virtual int open(const std::string &args = "", bool extref = false, bool swap_channels = false)=0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual ~RadioDevice() { }
 | 
					  virtual ~RadioDevice() { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,12 +33,12 @@ extern "C" {
 | 
				
			|||||||
#define CHUNK		625
 | 
					#define CHUNK		625
 | 
				
			||||||
#define NUMCHUNKS	4
 | 
					#define NUMCHUNKS	4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RadioInterface::RadioInterface(RadioDevice *wRadio,
 | 
					RadioInterface::RadioInterface(RadioDevice *wRadio, size_t tx_sps,
 | 
				
			||||||
                               size_t sps, size_t chans, size_t diversity,
 | 
					                               size_t rx_sps, size_t chans, size_t diversity,
 | 
				
			||||||
                               int wReceiveOffset, GSM::Time wStartTime)
 | 
					                               int wReceiveOffset, GSM::Time wStartTime)
 | 
				
			||||||
  : mRadio(wRadio), mSPSTx(sps), mSPSRx(1), mChans(chans), mMIMO(diversity),
 | 
					  : mRadio(wRadio), mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans),
 | 
				
			||||||
    sendCursor(0), recvCursor(0), underrun(false), overrun(false),
 | 
					    mMIMO(diversity), sendCursor(0), recvCursor(0), underrun(false),
 | 
				
			||||||
    receiveOffset(wReceiveOffset), mOn(false)
 | 
					    overrun(false), receiveOffset(wReceiveOffset), mOn(false)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  mClock.set(wStartTime);
 | 
					  mClock.set(wStartTime);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -106,23 +106,27 @@ double RadioInterface::fullScaleOutputValue(void) {
 | 
				
			|||||||
  return mRadio->fullScaleOutputValue();
 | 
					  return mRadio->fullScaleOutputValue();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int RadioInterface::setPowerAttenuation(int atten, size_t chan)
 | 
				
			||||||
void RadioInterface::setPowerAttenuation(double atten, size_t chan)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  double rfGain, digAtten;
 | 
					  double rfGain, digAtten;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (chan >= mChans) {
 | 
					  if (chan >= mChans) {
 | 
				
			||||||
    LOG(ALERT) << "Invalid channel requested";
 | 
					    LOG(ALERT) << "Invalid channel requested";
 | 
				
			||||||
    return;
 | 
					    return -1;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  rfGain = mRadio->setTxGain(mRadio->maxTxGain() - atten, chan);
 | 
					  if (atten < 0.0)
 | 
				
			||||||
  digAtten = atten - mRadio->maxTxGain() + rfGain;
 | 
					    atten = 0.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  rfGain = mRadio->setTxGain(mRadio->maxTxGain() - (double) atten, chan);
 | 
				
			||||||
 | 
					  digAtten = (double) atten - mRadio->maxTxGain() + rfGain;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (digAtten < 1.0)
 | 
					  if (digAtten < 1.0)
 | 
				
			||||||
    powerScaling[chan] = 1.0;
 | 
					    powerScaling[chan] = 1.0;
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
    powerScaling[chan] = 1.0 / sqrt(pow(10, digAtten / 10.0));
 | 
					    powerScaling[chan] = 1.0 / sqrt(pow(10, digAtten / 10.0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return atten;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int RadioInterface::radioifyVector(signalVector &wVector,
 | 
					int RadioInterface::radioifyVector(signalVector &wVector,
 | 
				
			||||||
@@ -167,15 +171,23 @@ bool RadioInterface::tuneRx(double freq, size_t chan)
 | 
				
			|||||||
  return mRadio->setRxFreq(freq, chan);
 | 
					  return mRadio->setRxFreq(freq, chan);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool RadioInterface::start()
 | 
				
			||||||
void RadioInterface::start()
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  LOG(INFO) << "Starting radio";
 | 
					  if (mOn)
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  LOG(INFO) << "Starting radio device";
 | 
				
			||||||
#ifdef USRP1
 | 
					#ifdef USRP1
 | 
				
			||||||
  mAlignRadioServiceLoopThread.start((void * (*)(void*))AlignRadioServiceLoopAdapter,
 | 
					  mAlignRadioServiceLoopThread.start((void * (*)(void*))AlignRadioServiceLoopAdapter,
 | 
				
			||||||
                                     (void*)this);
 | 
					                                     (void*)this);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  mRadio->start();
 | 
					
 | 
				
			||||||
 | 
					  if (!mRadio->start())
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  recvCursor = 0;
 | 
				
			||||||
 | 
					  sendCursor = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  writeTimestamp = mRadio->initialWriteTimestamp();
 | 
					  writeTimestamp = mRadio->initialWriteTimestamp();
 | 
				
			||||||
  readTimestamp = mRadio->initialReadTimestamp();
 | 
					  readTimestamp = mRadio->initialReadTimestamp();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -184,6 +196,23 @@ void RadioInterface::start()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  mOn = true;
 | 
					  mOn = true;
 | 
				
			||||||
  LOG(INFO) << "Radio started";
 | 
					  LOG(INFO) << "Radio started";
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Stop the radio device
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is a pass-through call to the device interface. Because the underlying
 | 
				
			||||||
 | 
					 * stop command issuance generally doesn't return confirmation on device status,
 | 
				
			||||||
 | 
					 * this call will only return false if the device is already stopped.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool RadioInterface::stop()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  if (!mOn || !mRadio->stop())
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mOn = false;
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USRP1
 | 
					#ifdef USRP1
 | 
				
			||||||
@@ -233,7 +262,12 @@ bool RadioInterface::driveReceiveRadio()
 | 
				
			|||||||
  int recvSz = recvCursor;
 | 
					  int recvSz = recvCursor;
 | 
				
			||||||
  int readSz = 0;
 | 
					  int readSz = 0;
 | 
				
			||||||
  const int symbolsPerSlot = gSlotLen + 8;
 | 
					  const int symbolsPerSlot = gSlotLen + 8;
 | 
				
			||||||
  int burstSize = (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx;
 | 
					  int burstSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (mSPSRx == 4)
 | 
				
			||||||
 | 
					    burstSize = 625;
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    burstSize = symbolsPerSlot + (tN % 4 == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* 
 | 
					  /* 
 | 
				
			||||||
   * Pre-allocate head room for the largest correlation size
 | 
					   * Pre-allocate head room for the largest correlation size
 | 
				
			||||||
@@ -268,6 +302,7 @@ bool RadioInterface::driveReceiveRadio()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    tN = rcvClock.TN();
 | 
					    tN = rcvClock.TN();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (mSPSRx != 4)
 | 
				
			||||||
      burstSize = (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx;
 | 
					      burstSize = (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,7 +78,8 @@ private:
 | 
				
			|||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** start the interface */
 | 
					  /** start the interface */
 | 
				
			||||||
  void start();
 | 
					  bool start();
 | 
				
			||||||
 | 
					  bool stop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** intialization */
 | 
					  /** intialization */
 | 
				
			||||||
  virtual bool init(int type);
 | 
					  virtual bool init(int type);
 | 
				
			||||||
@@ -86,7 +87,8 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /** constructor */
 | 
					  /** constructor */
 | 
				
			||||||
  RadioInterface(RadioDevice* wRadio = NULL,
 | 
					  RadioInterface(RadioDevice* wRadio = NULL,
 | 
				
			||||||
                 size_t sps = 4, size_t chans = 1, size_t diversity = 1,
 | 
					                 size_t tx_sps = 4, size_t rx_sps = 1,
 | 
				
			||||||
 | 
							 size_t chans = 1, size_t diversity = 1,
 | 
				
			||||||
                 int receiveOffset = 3, GSM::Time wStartTime = GSM::Time(0));
 | 
					                 int receiveOffset = 3, GSM::Time wStartTime = GSM::Time(0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** destructor */
 | 
					  /** destructor */
 | 
				
			||||||
@@ -120,7 +122,7 @@ public:
 | 
				
			|||||||
  /** drive reception of GSM bursts */
 | 
					  /** drive reception of GSM bursts */
 | 
				
			||||||
  bool driveReceiveRadio();
 | 
					  bool driveReceiveRadio();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void setPowerAttenuation(double atten, size_t chan = 0);
 | 
					  int setPowerAttenuation(int atten, size_t chan = 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** returns the full-scale transmit amplitude **/
 | 
					  /** returns the full-scale transmit amplitude **/
 | 
				
			||||||
  double fullScaleInputValue();
 | 
					  double fullScaleInputValue();
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -20,6 +20,11 @@
 | 
				
			|||||||
#include "BitVector.h"
 | 
					#include "BitVector.h"
 | 
				
			||||||
#include "signalVector.h"
 | 
					#include "signalVector.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Burst lengths */
 | 
				
			||||||
 | 
					#define NORMAL_BURST_NBITS		148
 | 
				
			||||||
 | 
					#define EDGE_BURST_NBITS		444
 | 
				
			||||||
 | 
					#define EDGE_BURST_NSYMS		(EDGE_BURST_NBITS / 3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Convolution type indicator */
 | 
					/** Convolution type indicator */
 | 
				
			||||||
enum ConvType {
 | 
					enum ConvType {
 | 
				
			||||||
  START_ONLY,
 | 
					  START_ONLY,
 | 
				
			||||||
@@ -49,7 +54,7 @@ float vectorNorm2(const signalVector &x);
 | 
				
			|||||||
float vectorPower(const signalVector &x);
 | 
					float vectorPower(const signalVector &x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Setup the signal processing library */
 | 
					/** Setup the signal processing library */
 | 
				
			||||||
bool sigProcLibSetup(int sps);
 | 
					bool sigProcLibSetup();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Destroy the signal processing library */
 | 
					/** Destroy the signal processing library */
 | 
				
			||||||
void sigProcLibDestroy(void);
 | 
					void sigProcLibDestroy(void);
 | 
				
			||||||
@@ -104,6 +109,25 @@ signalVector *modulateBurst(const BitVector &wBurst,
 | 
				
			|||||||
			    int guardPeriodLength,
 | 
								    int guardPeriodLength,
 | 
				
			||||||
			    int sps, bool emptyPulse = false);
 | 
								    int sps, bool emptyPulse = false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 8-PSK modulate a burst of bits */
 | 
				
			||||||
 | 
					signalVector *modulateEdgeBurst(const BitVector &bits,
 | 
				
			||||||
 | 
					                                int sps, bool emptyPulse = false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Generate a EDGE burst with random payload - 4 SPS (625 samples) only */
 | 
				
			||||||
 | 
					signalVector *generateEdgeBurst(int tsc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Generate an empty burst - 4 or 1 SPS */
 | 
				
			||||||
 | 
					signalVector *generateEmptyBurst(int sps, int tn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Generate a normal GSM burst with random payload - 4 or 1 SPS */
 | 
				
			||||||
 | 
					signalVector *genRandNormalBurst(int tsc, int sps, int tn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Generate an access GSM burst with random payload - 4 or 1 SPS */
 | 
				
			||||||
 | 
					signalVector *genRandAccessBurst(int sps, int tn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Generate a dummy GSM burst - 4 or 1 SPS */
 | 
				
			||||||
 | 
					signalVector *generateDummyBurst(int sps, int tn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Sinc function */
 | 
					/** Sinc function */
 | 
				
			||||||
float sinc(float x);
 | 
					float sinc(float x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -151,22 +175,6 @@ complex peakDetect(const signalVector &rxBurst,
 | 
				
			|||||||
void scaleVector(signalVector &x,
 | 
					void scaleVector(signalVector &x,
 | 
				
			||||||
		 complex scale);
 | 
							 complex scale);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
        Generate a modulated GSM midamble, stored within the library.
 | 
					 | 
				
			||||||
        @param gsmPulse The GSM pulse used for modulation.
 | 
					 | 
				
			||||||
        @param sps The number of samples per GSM symbol.
 | 
					 | 
				
			||||||
        @param TSC The training sequence [0..7]
 | 
					 | 
				
			||||||
        @return Success.
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
bool generateMidamble(int sps, int tsc);
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
        Generate a modulated RACH sequence, stored within the library.
 | 
					 | 
				
			||||||
        @param gsmPulse The GSM pulse used for modulation.
 | 
					 | 
				
			||||||
        @param sps The number of samples per GSM symbol.
 | 
					 | 
				
			||||||
        @return Success.
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
bool generateRACHSequence(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.
 | 
				
			||||||
        @param rxBurst The received GSM burst of interest.
 | 
					        @param rxBurst The received GSM burst of interest.
 | 
				
			||||||
@@ -187,13 +195,15 @@ bool energyDetect(signalVector &rxBurst,
 | 
				
			|||||||
        @param sps The number of samples per GSM symbol.
 | 
					        @param sps The number of samples per GSM symbol.
 | 
				
			||||||
        @param amplitude The estimated amplitude of received RACH burst.
 | 
					        @param amplitude The estimated amplitude of received RACH burst.
 | 
				
			||||||
        @param TOA The estimate time-of-arrival of received RACH burst.
 | 
					        @param TOA The estimate time-of-arrival of received RACH burst.
 | 
				
			||||||
 | 
					        @param maxTOA The maximum expected time-of-arrival
 | 
				
			||||||
        @return positive if threshold value is reached, negative on error, zero otherwise
 | 
					        @return positive if threshold value is reached, negative on error, zero otherwise
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
int detectRACHBurst(signalVector &rxBurst,
 | 
					int detectRACHBurst(signalVector &rxBurst,
 | 
				
			||||||
                    float detectThreshold,
 | 
					                    float detectThreshold,
 | 
				
			||||||
                    int sps,
 | 
					                    int sps,
 | 
				
			||||||
                    complex *amplitude,
 | 
					                    complex &litude,
 | 
				
			||||||
                    float* TOA);
 | 
					                    float &TOA,
 | 
				
			||||||
 | 
					                    unsigned maxTOA);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
        Normal burst correlator, detector, channel estimator.
 | 
					        Normal burst correlator, detector, channel estimator.
 | 
				
			||||||
@@ -213,12 +223,36 @@ int analyzeTrafficBurst(signalVector &rxBurst,
 | 
				
			|||||||
                        unsigned TSC,
 | 
					                        unsigned TSC,
 | 
				
			||||||
                        float detectThreshold,
 | 
					                        float detectThreshold,
 | 
				
			||||||
                        int sps,
 | 
					                        int sps,
 | 
				
			||||||
			complex *amplitude,
 | 
					                        complex &litude,
 | 
				
			||||||
			float *TOA,
 | 
					                        float &TOA,
 | 
				
			||||||
                        unsigned maxTOA,
 | 
					                        unsigned maxTOA);
 | 
				
			||||||
                        bool requestChannel = false,
 | 
					
 | 
				
			||||||
			signalVector** channelResponse = NULL,
 | 
					/**
 | 
				
			||||||
			float *channelResponseOffset = NULL);
 | 
					        EDGE burst detector
 | 
				
			||||||
 | 
					        @param burst The received GSM burst of interest
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					        @param detectThreshold The threshold that the received burst's post-correlator SNR is compared against to determine validity.
 | 
				
			||||||
 | 
					        @param sps The number of samples per GSM symbol.
 | 
				
			||||||
 | 
					        @param amplitude The estimated amplitude of received TSC burst.
 | 
				
			||||||
 | 
					        @param TOA The estimate time-of-arrival of received TSC burst.
 | 
				
			||||||
 | 
					        @param maxTOA The maximum expected time-of-arrival
 | 
				
			||||||
 | 
					        @return positive if threshold value is reached, negative on error, zero otherwise
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					int detectEdgeBurst(signalVector &burst,
 | 
				
			||||||
 | 
					                    unsigned TSC,
 | 
				
			||||||
 | 
					                    float detectThreshold,
 | 
				
			||||||
 | 
					                    int sps,
 | 
				
			||||||
 | 
					                    complex &litude,
 | 
				
			||||||
 | 
					                    float &TOA,
 | 
				
			||||||
 | 
					                    unsigned maxTOA);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
						Downsample 4 SPS to 1 SPS using a polyphase filterbank
 | 
				
			||||||
 | 
					        @param burst Input burst of at least 624 symbols
 | 
				
			||||||
 | 
					        @return Decimated signal vector of 156 symbols
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					signalVector *downsampleBurst(signalVector &burst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
	Decimate a vector.
 | 
						Decimate a vector.
 | 
				
			||||||
@@ -241,33 +275,14 @@ SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
 | 
				
			|||||||
                            complex channel, float TOA);
 | 
					                            complex channel, float TOA);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
	Design the necessary filters for a decision-feedback equalizer.
 | 
					        Demodulate 8-PSK EDGE burst with soft symbol ooutput
 | 
				
			||||||
	@param channelResponse The multipath channel that we're mitigating.
 | 
						@param rxBurst The burst to be demodulated.
 | 
				
			||||||
	@param SNRestimate The signal-to-noise estimate of the channel, a linear value
 | 
					 | 
				
			||||||
	@param Nf The number of taps in the feedforward filter.
 | 
					 | 
				
			||||||
	@param feedForwardFilter The designed feed forward filter.
 | 
					 | 
				
			||||||
	@param feedbackFilter The designed feedback filter.
 | 
					 | 
				
			||||||
	@return True if DFE can be designed.
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
bool designDFE(signalVector &channelResponse,
 | 
					 | 
				
			||||||
	       float SNRestimate,
 | 
					 | 
				
			||||||
	       int Nf,
 | 
					 | 
				
			||||||
	       signalVector **feedForwardFilter,
 | 
					 | 
				
			||||||
	       signalVector **feedbackFilter);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
	Equalize/demodulate a received burst via a decision-feedback equalizer.
 | 
					 | 
				
			||||||
	@param rxBurst The received burst to be demodulated.
 | 
					 | 
				
			||||||
	@param TOA The time-of-arrival of the received burst.
 | 
					 | 
				
			||||||
        @param sps The number of samples per GSM symbol.
 | 
					        @param sps The number of samples per GSM symbol.
 | 
				
			||||||
	@param w The feed forward filter of the DFE.
 | 
					        @param channel The amplitude estimate of the received burst.
 | 
				
			||||||
	@param b The feedback filter of the DFE.
 | 
					        @param TOA The time-of-arrival of the received burst.
 | 
				
			||||||
        @return The demodulated bit sequence.
 | 
					        @return The demodulated bit sequence.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
SoftVector *equalizeBurst(signalVector &rxBurst,
 | 
					SoftVector *demodEdgeBurst(signalVector &rxBurst, int sps,
 | 
				
			||||||
		       float TOA,
 | 
					                           complex channel, float TOA);
 | 
				
			||||||
		       int sps,
 | 
					 | 
				
			||||||
		       signalVector &w, 
 | 
					 | 
				
			||||||
		       signalVector &b);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* SIGPROCLIB_H */
 | 
					#endif /* SIGPROCLIB_H */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* 16*N 16-bit signed integer converted to single precision floats */
 | 
					/* 16*N 16-bit signed integer converted to single precision floats */
 | 
				
			||||||
static void _sse_convert_si16_ps_16n(float *restrict out,
 | 
					static void _sse_convert_si16_ps_16n(float *restrict out,
 | 
				
			||||||
				     short *restrict in,
 | 
									     const short *restrict in,
 | 
				
			||||||
				     int len)
 | 
									     int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	__m128i m0, m1, m2, m3, m4, m5;
 | 
						__m128i m0, m1, m2, m3, m4, m5;
 | 
				
			||||||
@@ -69,7 +69,7 @@ static void _sse_convert_si16_ps_16n(float *restrict out,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* 16*N 16-bit signed integer conversion with remainder */
 | 
					/* 16*N 16-bit signed integer conversion with remainder */
 | 
				
			||||||
static void _sse_convert_si16_ps(float *restrict out,
 | 
					static void _sse_convert_si16_ps(float *restrict out,
 | 
				
			||||||
				 short *restrict in,
 | 
									 const short *restrict in,
 | 
				
			||||||
				 int len)
 | 
									 int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int start = len / 16 * 16;
 | 
						int start = len / 16 * 16;
 | 
				
			||||||
@@ -83,7 +83,7 @@ static void _sse_convert_si16_ps(float *restrict out,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* 8*N single precision floats scaled and converted to 16-bit signed integer */
 | 
					/* 8*N single precision floats scaled and converted to 16-bit signed integer */
 | 
				
			||||||
static void _sse_convert_scale_ps_si16_8n(short *restrict out,
 | 
					static void _sse_convert_scale_ps_si16_8n(short *restrict out,
 | 
				
			||||||
					  float *restrict in,
 | 
										  const float *restrict in,
 | 
				
			||||||
					  float scale, int len)
 | 
										  float scale, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	__m128 m0, m1, m2;
 | 
						__m128 m0, m1, m2;
 | 
				
			||||||
@@ -111,7 +111,7 @@ static void _sse_convert_scale_ps_si16_8n(short *restrict out,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* 8*N single precision floats scaled and converted with remainder */
 | 
					/* 8*N single precision floats scaled and converted with remainder */
 | 
				
			||||||
static void _sse_convert_scale_ps_si16(short *restrict out,
 | 
					static void _sse_convert_scale_ps_si16(short *restrict out,
 | 
				
			||||||
				       float *restrict in,
 | 
									       const float *restrict in,
 | 
				
			||||||
				       float scale, int len)
 | 
									       float scale, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int start = len / 8 * 8;
 | 
						int start = len / 8 * 8;
 | 
				
			||||||
@@ -124,7 +124,7 @@ static void _sse_convert_scale_ps_si16(short *restrict out,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* 16*N single precision floats scaled and converted to 16-bit signed integer */
 | 
					/* 16*N single precision floats scaled and converted to 16-bit signed integer */
 | 
				
			||||||
static void _sse_convert_scale_ps_si16_16n(short *restrict out,
 | 
					static void _sse_convert_scale_ps_si16_16n(short *restrict out,
 | 
				
			||||||
					   float *restrict in,
 | 
										   const float *restrict in,
 | 
				
			||||||
					   float scale, int len)
 | 
										   float scale, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	__m128 m0, m1, m2, m3, m4;
 | 
						__m128 m0, m1, m2, m3, m4;
 | 
				
			||||||
@@ -158,7 +158,8 @@ static void _sse_convert_scale_ps_si16_16n(short *restrict out,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#else /* HAVE_SSE3 */
 | 
					#else /* HAVE_SSE3 */
 | 
				
			||||||
static void convert_scale_ps_si16(short *out, float *in, float scale, int len)
 | 
					static void convert_scale_ps_si16(short *out, const float *in,
 | 
				
			||||||
 | 
									  float scale, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	for (int i = 0; i < len; i++)
 | 
						for (int i = 0; i < len; i++)
 | 
				
			||||||
		out[i] = in[i] * scale;
 | 
							out[i] = in[i] * scale;
 | 
				
			||||||
@@ -166,14 +167,14 @@ static void convert_scale_ps_si16(short *out, float *in, float scale, int len)
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef HAVE_SSE4_1
 | 
					#ifndef HAVE_SSE4_1
 | 
				
			||||||
static void convert_si16_ps(float *out, short *in, int len)
 | 
					static void convert_si16_ps(float *out, const short *in, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	for (int i = 0; i < len; i++)
 | 
						for (int i = 0; i < len; i++)
 | 
				
			||||||
		out[i] = in[i];
 | 
							out[i] = in[i];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void convert_float_short(short *out, float *in, float scale, int len)
 | 
					void convert_float_short(short *out, const float *in, float scale, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef HAVE_SSE3
 | 
					#ifdef HAVE_SSE3
 | 
				
			||||||
	if (!(len % 16))
 | 
						if (!(len % 16))
 | 
				
			||||||
@@ -187,7 +188,7 @@ void convert_float_short(short *out, float *in, float scale, int len)
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void convert_short_float(float *out, short *in, int len)
 | 
					void convert_short_float(float *out, const short *in, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef HAVE_SSE4_1
 | 
					#ifdef HAVE_SSE4_1
 | 
				
			||||||
	if (!(len % 16))
 | 
						if (!(len % 16))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,14 +27,14 @@
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Forward declarations from base implementation */
 | 
					/* Forward declarations from base implementation */
 | 
				
			||||||
int _base_convolve_real(float *x, int x_len,
 | 
					int _base_convolve_real(const float *x, int x_len,
 | 
				
			||||||
			float *h, int h_len,
 | 
								const float *h, int h_len,
 | 
				
			||||||
			float *y, int y_len,
 | 
								float *y, int y_len,
 | 
				
			||||||
			int start, int len,
 | 
								int start, int len,
 | 
				
			||||||
			int step, int offset);
 | 
								int step, int offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int _base_convolve_complex(float *x, int x_len,
 | 
					int _base_convolve_complex(const float *x, int x_len,
 | 
				
			||||||
			   float *h, int h_len,
 | 
								   const float *h, int h_len,
 | 
				
			||||||
			   float *y, int y_len,
 | 
								   float *y, int y_len,
 | 
				
			||||||
			   int start, int len,
 | 
								   int start, int len,
 | 
				
			||||||
			   int step, int offset);
 | 
								   int step, int offset);
 | 
				
			||||||
@@ -47,8 +47,8 @@ int bounds_check(int x_len, int h_len, int y_len,
 | 
				
			|||||||
#include <pmmintrin.h>
 | 
					#include <pmmintrin.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 4-tap SSE complex-real convolution */
 | 
					/* 4-tap SSE complex-real convolution */
 | 
				
			||||||
static void sse_conv_real4(float *restrict x,
 | 
					static void sse_conv_real4(const float *restrict x,
 | 
				
			||||||
			   float *restrict h,
 | 
								   const float *restrict h,
 | 
				
			||||||
			   float *restrict y,
 | 
								   float *restrict y,
 | 
				
			||||||
			   int len)
 | 
								   int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -81,8 +81,8 @@ static void sse_conv_real4(float *restrict x,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 8-tap SSE complex-real convolution */
 | 
					/* 8-tap SSE complex-real convolution */
 | 
				
			||||||
static void sse_conv_real8(float *restrict x,
 | 
					static void sse_conv_real8(const float *restrict x,
 | 
				
			||||||
			   float *restrict h,
 | 
								   const float *restrict h,
 | 
				
			||||||
			   float *restrict y,
 | 
								   float *restrict y,
 | 
				
			||||||
			   int len)
 | 
								   int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -128,8 +128,8 @@ static void sse_conv_real8(float *restrict x,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 12-tap SSE complex-real convolution */
 | 
					/* 12-tap SSE complex-real convolution */
 | 
				
			||||||
static void sse_conv_real12(float *restrict x,
 | 
					static void sse_conv_real12(const float *restrict x,
 | 
				
			||||||
			    float *restrict h,
 | 
								    const float *restrict h,
 | 
				
			||||||
			    float *restrict y,
 | 
								    float *restrict y,
 | 
				
			||||||
			    int len)
 | 
								    int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -190,8 +190,8 @@ static void sse_conv_real12(float *restrict x,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 16-tap SSE complex-real convolution */
 | 
					/* 16-tap SSE complex-real convolution */
 | 
				
			||||||
static void sse_conv_real16(float *restrict x,
 | 
					static void sse_conv_real16(const float *restrict x,
 | 
				
			||||||
			    float *restrict h,
 | 
								    const float *restrict h,
 | 
				
			||||||
			    float *restrict y,
 | 
								    float *restrict y,
 | 
				
			||||||
			    int len)
 | 
								    int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -265,8 +265,8 @@ static void sse_conv_real16(float *restrict x,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 20-tap SSE complex-real convolution */
 | 
					/* 20-tap SSE complex-real convolution */
 | 
				
			||||||
static void sse_conv_real20(float *restrict x,
 | 
					static void sse_conv_real20(const float *restrict x,
 | 
				
			||||||
			    float *restrict h,
 | 
								    const float *restrict h,
 | 
				
			||||||
			    float *restrict y,
 | 
								    float *restrict y,
 | 
				
			||||||
			    int len)
 | 
								    int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -351,7 +351,10 @@ static void sse_conv_real20(float *restrict x,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 4*N-tap SSE complex-real convolution */
 | 
					/* 4*N-tap SSE complex-real convolution */
 | 
				
			||||||
static void sse_conv_real4n(float *x, float *h, float *y, int h_len, int len)
 | 
					static void sse_conv_real4n(const float *x,
 | 
				
			||||||
 | 
								    const float *h,
 | 
				
			||||||
 | 
								    float *y,
 | 
				
			||||||
 | 
								    int h_len, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	__m128 m0, m1, m2, m4, m5, m6, m7;
 | 
						__m128 m0, m1, m2, m4, m5, m6, m7;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -391,7 +394,10 @@ static void sse_conv_real4n(float *x, float *h, float *y, int h_len, int len)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 4*N-tap SSE complex-complex convolution */
 | 
					/* 4*N-tap SSE complex-complex convolution */
 | 
				
			||||||
static void sse_conv_cmplx_4n(float *x, float *h, float *y, int h_len, int len)
 | 
					static void sse_conv_cmplx_4n(const float *x,
 | 
				
			||||||
 | 
								      const float *h,
 | 
				
			||||||
 | 
								      float *y,
 | 
				
			||||||
 | 
								      int h_len, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	__m128 m0, m1, m2, m3, m4, m5, m6, m7;
 | 
						__m128 m0, m1, m2, m3, m4, m5, m6, m7;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -439,7 +445,10 @@ static void sse_conv_cmplx_4n(float *x, float *h, float *y, int h_len, int len)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 8*N-tap SSE complex-complex convolution */
 | 
					/* 8*N-tap SSE complex-complex convolution */
 | 
				
			||||||
static void sse_conv_cmplx_8n(float *x, float *h, float *y, int h_len, int len)
 | 
					static void sse_conv_cmplx_8n(const float *x,
 | 
				
			||||||
 | 
								      const float *h,
 | 
				
			||||||
 | 
								      float *y,
 | 
				
			||||||
 | 
								      int h_len, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	__m128 m0, m1, m2, m3, m4, m5, m6, m7;
 | 
						__m128 m0, m1, m2, m3, m4, m5, m6, m7;
 | 
				
			||||||
	__m128 m8, m9, m10, m11, m12, m13, m14, m15;
 | 
						__m128 m8, m9, m10, m11, m12, m13, m14, m15;
 | 
				
			||||||
@@ -511,14 +520,16 @@ static void sse_conv_cmplx_8n(float *x, float *h, float *y, int h_len, int len)
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* API: Aligned complex-real */
 | 
					/* API: Aligned complex-real */
 | 
				
			||||||
int convolve_real(float *x, int x_len,
 | 
					int convolve_real(const float *x, int x_len,
 | 
				
			||||||
		  float *h, int h_len,
 | 
							  const float *h, int h_len,
 | 
				
			||||||
		  float *y, int y_len,
 | 
							  float *y, int y_len,
 | 
				
			||||||
		  int start, int len,
 | 
							  int start, int len,
 | 
				
			||||||
		  int step, int offset)
 | 
							  int step, int offset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	void (*conv_func)(float *, float *, float *, int) = NULL;
 | 
						void (*conv_func)(const float *, const float *,
 | 
				
			||||||
	void (*conv_func_n)(float *, float *, float *, int, int) = NULL;
 | 
								  float *, int) = NULL;
 | 
				
			||||||
 | 
						void (*conv_func_n)(const float *, const float *,
 | 
				
			||||||
 | 
								    float *, int, int) = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (bounds_check(x_len, h_len, y_len, start, len, step) < 0)
 | 
						if (bounds_check(x_len, h_len, y_len, start, len, step) < 0)
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
@@ -566,13 +577,14 @@ int convolve_real(float *x, int x_len,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* API: Aligned complex-complex */
 | 
					/* API: Aligned complex-complex */
 | 
				
			||||||
int convolve_complex(float *x, int x_len,
 | 
					int convolve_complex(const float *x, int x_len,
 | 
				
			||||||
		     float *h, int h_len,
 | 
							     const float *h, int h_len,
 | 
				
			||||||
		     float *y, int y_len,
 | 
							     float *y, int y_len,
 | 
				
			||||||
		     int start, int len,
 | 
							     int start, int len,
 | 
				
			||||||
		     int step, int offset)
 | 
							     int step, int offset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	void (*conv_func)(float *, float *, float *, int, int) = NULL;
 | 
						void (*conv_func)(const float *, const float *,
 | 
				
			||||||
 | 
								  float *, int, int) = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (bounds_check(x_len, h_len, y_len, start, len, step) < 0)
 | 
						if (bounds_check(x_len, h_len, y_len, start, len, step) < 0)
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								configure.ac
									
									
									
									
									
								
							@@ -29,7 +29,7 @@ AC_CANONICAL_BUILD
 | 
				
			|||||||
AC_CANONICAL_HOST
 | 
					AC_CANONICAL_HOST
 | 
				
			||||||
AC_CANONICAL_TARGET
 | 
					AC_CANONICAL_TARGET
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AM_INIT_AUTOMAKE
 | 
					AM_INIT_AUTOMAKE([subdir-objects])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dnl Linux kernel KBuild style compile messages
 | 
					dnl Linux kernel KBuild style compile messages
 | 
				
			||||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
 | 
					m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
 | 
				
			||||||
@@ -78,6 +78,11 @@ AC_ARG_WITH(neon-vfpv4, [
 | 
				
			|||||||
        [enable ARM NEON FMA support])
 | 
					        [enable ARM NEON FMA support])
 | 
				
			||||||
])
 | 
					])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AC_ARG_WITH(sse, [
 | 
				
			||||||
 | 
					    AS_HELP_STRING([--with-sse],
 | 
				
			||||||
 | 
					        [enable x86 SSE support (default)])
 | 
				
			||||||
 | 
					])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AS_IF([test "x$with_neon" = "xyes"], [
 | 
					AS_IF([test "x$with_neon" = "xyes"], [
 | 
				
			||||||
    AC_DEFINE(HAVE_NEON, 1, Support ARM NEON)
 | 
					    AC_DEFINE(HAVE_NEON, 1, Support ARM NEON)
 | 
				
			||||||
])
 | 
					])
 | 
				
			||||||
@@ -92,8 +97,11 @@ AS_IF([test "x$with_usrp1" = "xyes"], [
 | 
				
			|||||||
])
 | 
					])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AS_IF([test "x$with_usrp1" != "xyes"],[
 | 
					AS_IF([test "x$with_usrp1" != "xyes"],[
 | 
				
			||||||
    PKG_CHECK_MODULES(UHD, uhd >= 003.004.000)
 | 
					    PKG_CHECK_MODULES(UHD, uhd >= 003.009,
 | 
				
			||||||
    AC_DEFINE(USE_UHD, 1, Define to 1 if using UHD)
 | 
					        [AC_DEFINE(USE_UHD_3_9, 1, UHD version 3.9.0 or higher)],
 | 
				
			||||||
 | 
					        [PKG_CHECK_MODULES(UHD, uhd >= 003.005.004)]
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    AC_DEFINE(USE_UHD, 1, All UHD versions)
 | 
				
			||||||
])
 | 
					])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AS_IF([test "x$with_singledb" = "xyes"], [
 | 
					AS_IF([test "x$with_singledb" = "xyes"], [
 | 
				
			||||||
@@ -101,7 +109,9 @@ AS_IF([test "x$with_singledb" = "xyes"], [
 | 
				
			|||||||
])
 | 
					])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Find and define supported SIMD extensions
 | 
					# Find and define supported SIMD extensions
 | 
				
			||||||
 | 
					AS_IF([test "x$with_sse" != "xno"], [
 | 
				
			||||||
    AX_EXT
 | 
					    AX_EXT
 | 
				
			||||||
 | 
					])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AM_CONDITIONAL(USRP1, [test "x$with_usrp1" = "xyes"])
 | 
					AM_CONDITIONAL(USRP1, [test "x$with_usrp1" = "xyes"])
 | 
				
			||||||
AM_CONDITIONAL(ARCH_ARM, [test "x$with_neon" = "xyes" || test "x$with_neon_vfpv4" = "xyes"])
 | 
					AM_CONDITIONAL(ARCH_ARM, [test "x$with_neon" = "xyes" || test "x$with_neon_vfpv4" = "xyes"])
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,9 @@
 | 
				
			|||||||
 | 
					osmo-trx (0.1.9) trusty; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  * Ask Ivan, really
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Kirill Zakharenko <earwin@gmail.com>  Thu, 16 Jul 2015 12:13:46 +0000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
osmo-trx (0.1.8) precise; urgency=low
 | 
					osmo-trx (0.1.8) precise; urgency=low
 | 
				
			||||||
 | 
					
 | 
				
			||||||
     * Initial release (Closes: #nnnn) <nnnn is the bug number of your ITP
 | 
					     * Initial release (Closes: #nnnn) <nnnn is the bug number of your ITP
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@@ -3,7 +3,7 @@ Maintainer: Ivan Klyuchnikov <ivan.kluchnikov@fairwaves.ru>
 | 
				
			|||||||
Section: net
 | 
					Section: net
 | 
				
			||||||
Priority: optional
 | 
					Priority: optional
 | 
				
			||||||
Standards-Version: 3.9.3
 | 
					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
 | 
					Build-Depends: debhelper (>= 9), autotools-dev, libdbd-sqlite3, pkg-config, dh-autoreconf, libuhd-dev, libusb-1.0-0-dev, libboost-all-dev, hardening-wrapper
 | 
				
			||||||
Homepage: http://openbsc.osmocom.org/trac/wiki/OsmoTRX
 | 
					Homepage: http://openbsc.osmocom.org/trac/wiki/OsmoTRX
 | 
				
			||||||
Vcs-Git: git://git.osmocom.org/osmo-trx
 | 
					Vcs-Git: git://git.osmocom.org/osmo-trx
 | 
				
			||||||
Vcs-Browser: http://cgit.osmocom.org/osmo-trx
 | 
					Vcs-Browser: http://cgit.osmocom.org/osmo-trx
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							@@ -1,7 +1,6 @@
 | 
				
			|||||||
#!/usr/bin/make -f
 | 
					#!/usr/bin/make -f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export DEB_BUILD_HARDENING=1
 | 
					DEB_BUILD_HARDENING=1
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
%:
 | 
					%:
 | 
				
			||||||
	dh $@ --with autoreconf
 | 
						dh $@ --with autoreconf
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								utils/clockdump.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										3
									
								
								utils/clockdump.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					sudo tcpdump -i lo0 -A udp port 5700
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Reference in New Issue
	
	Block a user