示例#1
0
void startTransceiver()
{
	//if local kill the process currently listening on this port
	char killCmd[32];
	if (gConfig.getStr("TRX.IP") == "127.0.0.1"){
		sprintf(killCmd,"fuser -k -n udp %d",(int)gConfig.getNum("TRX.Port"));
		if (system(killCmd)) {}
	}

	// Start the transceiver binary, if the path is defined.
	// If the path is not defined, the transceiver must be started by some other process.
	char TRXnumARFCN[4];
	sprintf(TRXnumARFCN,"%1d",(int)gConfig.getNum("GSM.Radio.ARFCNs"));
	std::string extra_args = gConfig.getStr("TRX.Args");
	LOG(NOTICE) << "starting transceiver " << transceiverPath << " w/ " << TRXnumARFCN << " ARFCNs and Args:" << extra_args;
	gTransceiverPid = vfork();
	LOG_ASSERT(gTransceiverPid>=0);
	if (gTransceiverPid==0) {
		// Pid==0 means this is the process that starts the transceiver.
	    execlp(transceiverPath,transceiverPath,TRXnumARFCN,extra_args.c_str(),(void*)NULL);
		LOG(EMERG) << "cannot find " << transceiverPath;
		_exit(1);
	} else {
		int status;
		waitpid(gTransceiverPid, &status,0);
		LOG(EMERG) << "Transceiver quit with status " << status << ". Exiting.";
		exit(2);
	}
}
示例#2
0
/** Add an alarm to the alarm list. */
void addAlarm(const string& s)
{
    alarmsLock.lock();
    alarmsList.push_back(s);
	unsigned maxAlarms = gConfig.getNum("Log.Alarms.Max");
    while (alarmsList.size() > maxAlarms) alarmsList.pop_front();
    alarmsLock.unlock();
}
示例#3
0
// Add an alarm to the alarm list, and send it out via udp
//
// On the first call we read the ip and port from the configuration
// TODO - is there any global setup function where this should be done? -- Alon
void addAlarm(const string& s)
{
	// Socket open and close on every alarm - wise?
	// Probably.  That way we are sure to pick up changes in the target address.
	// Alarms should not happen often.
	if (gConfig.defines("Log.Alarms.TargetIP")) {
		UDPSocket alarmsocket(0,
			gConfig.getStr("Log.Alarms.TargetIP"),
			gConfig.getNum("Log.Alarms.TargetPort"));
		alarmsocket.write(s.c_str());
	}
    // append to list and reduce list to max alarm count
    alarmsLock.lock();
    alarmsList.push_back(s);
	unsigned maxAlarms = gConfig.getNum("Log.Alarms.Max");
    while (alarmsList.size() > maxAlarms) alarmsList.pop_front();
    alarmsLock.unlock();
}
int SubscriberRegistry::init()
{
	string ldb = gConfig.getStr("SubscriberRegistry.db");
	size_t p = ldb.find_last_of('/');
	if (p == string::npos) {
		LOG(EMERG) << "SubscriberRegistry.db not in a directory?";
		mDB = NULL;
		return 1;
	}
	string dir = ldb.substr(0, p);
	struct stat buf;
	if (stat(dir.c_str(), &buf)) {
		LOG(EMERG) << dir << " does not exist";
		mDB = NULL;
		return 1;
	}
	mNumSQLTries=gConfig.getNum("Control.NumSQLTries"); 
	int rc = sqlite3_open(ldb.c_str(),&mDB);
	if (rc) {
		LOG(EMERG) << "Cannot open SubscriberRegistry database: " << ldb << " error: " << sqlite3_errmsg(mDB);
		sqlite3_close(mDB);
		mDB = NULL;
		return 1;
	}
	if (!sqlite3_command(mDB,createRRLPTable,mNumSQLTries)) {
		LOG(EMERG) << "Cannot create RRLP table";
		return 1;
	}
	if (!sqlite3_command(mDB,createDDTable,mNumSQLTries)) {
		LOG(EMERG) << "Cannot create DIALDATA_TABLE table";
		return 1;
	}
	if (!sqlite3_command(mDB,createRateTable,mNumSQLTries)) {
		LOG(EMERG) << "Cannot create rate table";
		return 1;
	}
	if (!sqlite3_command(mDB,createSBTable,mNumSQLTries)) {
		LOG(EMERG) << "Cannot create SIP_BUDDIES table";
		return 1;
	}
	// Set high-concurrency WAL mode.
	if (!sqlite3_command(mDB,enableWAL,mNumSQLTries)) {
		LOG(EMERG) << "Cannot enable WAL mode on database at " << ldb << ", error message: " << sqlite3_errmsg(mDB);
	}
	if (!getCLIDLocal("IMSI001010000000000")) {
		// This is a test SIM provided with the BTS.
		if (addUser("IMSI001010000000000", "2100") != SUCCESS) {
        		LOG(EMERG) << "Cannot insert test SIM";
		}
	}
	return 0;
}
示例#5
0
void startTransceiver()
{
	// kill any stray transceiver process
	system("killall transceiver");

	// Start the transceiver binary, if the path is defined.
	// If the path is not defined, the transceiver must be started by some other process.
    char TRXnumARFCN[16];
    sprintf(TRXnumARFCN,"%1d", static_cast<int>(gConfig.getNum("GSM.Radio.ARFCNs")));
	LOG(NOTICE) << "starting transceiver " << transceiverPath << " " << TRXnumARFCN;
	gTransceiverPid = vfork();
	LOG_ASSERT(gTransceiverPid>=0);
	if (gTransceiverPid==0) {
		// Pid==0 means this is the process that starts the transceiver.
		execlp(transceiverPath,transceiverPath,TRXnumARFCN,NULL);
		LOG(EMERG) << "cannot find " << transceiverPath;
		_exit(1);
	} else {
		int status;
		waitpid(gTransceiverPid, &status,0);
		LOG(EMERG) << "Transceiver quit with status " << status << ". Exiting.";
		exit(2);
	}
}
int
main(int argc, char **argv)
{
	// TODO: Properly parse and handle any arguments
	if (argc > 1) {
		for (int argi = 0; argi < argc; argi++) {
			if (!strcmp(argv[argi], "--version") ||
			    !strcmp(argv[argi], "-v")) {
				cout << gVersionString << endl;
			}
			if (!strcmp(argv[argi], "--gensql")) {
				cout << gConfig.getDefaultSQL(string(argv[0]), gVersionString) << endl;
			}
			if (!strcmp(argv[argi], "--gentex")) {
				cout << gConfig.getTeX(string(argv[0]), gVersionString) << endl;
			}
		}

		return 0;
	}

	sockaddr_in si_me;
	sockaddr_in si_other;
	int aSocket;
	char buf[BUFLEN];

	LOG(ALERT) << argv[0] << " (re)starting";
	srand ( time(NULL) + (int)getpid() );
	my_udp_port = gConfig.getNum("SubscriberRegistry.Port");
	gSubscriberRegistry.init();
	gNodeManager.setAppLogicHandler(&nmHandler);
	gNodeManager.start(45064);

	// init osip lib
	osip_t *osip;
	int i=osip_init(&osip);
	if (i!=0) {
		LOG(ALERT) << "cannot init sip lib";
		exit(1);
	}

	if ((aSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
		LOG(ALERT) << "can't initialize socket";
		exit(1);
	}

	memset((char *) &si_me, 0, sizeof(si_me));
	si_me.sin_family = AF_INET;
	si_me.sin_port = htons(my_udp_port);
	si_me.sin_addr.s_addr = htonl(INADDR_ANY);
	if (bind(aSocket, (sockaddr*)&si_me, sizeof(si_me)) == -1) {
		LOG(ALERT) << "can't bind socket on port " << my_udp_port;
		exit(1);
	}

	LOG(NOTICE) << "binding on port " << my_udp_port;

	while (true) {
		gConfig.purge();
		socklen_t slen = sizeof(si_other);
		memset(buf, 0, BUFLEN);
		if (recvfrom(aSocket, buf, BUFLEN, 0, (sockaddr*)&si_other, &slen) == -1) {
			LOG(ERR) << "recvfrom problem";
			continue;
		}

		LOG(INFO) << " receiving " << buf;

		char *dest = processBuffer(buf);
		if (dest == NULL) {
			continue;
		}

		if (sendto(aSocket, dest, strlen(dest), 0, (sockaddr*)&si_other, sizeof(si_other)) == -1) {
			LOG(ERR) << "sendto problem";
			continue;
		}
		osip_free(dest);
	}

	close(aSocket);
	return 0;
}
int main(int argc, char *argv[])
{

	try {

	srandom(time(NULL));

	gConfig.setUpdateHook(purgeConfig);
	gLogInit("openbts",gConfig.getStr("Log.Level").c_str(),LOG_LOCAL7);
	LOG(ALERT) << "OpenBTS starting, ver " << VERSION << " build date " << __DATE__;

	COUT("\n\n" << gOpenBTSWelcome << "\n");
	gTMSITable.open(gConfig.getStr("Control.Reporting.TMSITable").c_str());
	gTransactionTable.init();
	gPhysStatus.open(gConfig.getStr("Control.Reporting.PhysStatusTable").c_str());
	gBTS.init();
	gSubscriberRegistry.init();
	gParser.addCommands();

	COUT("\nStarting the system...");

	Thread transceiverThread;
	transceiverThread.start((void*(*)(void*)) startTransceiver, NULL);

	// Start the SIP interface.
	gSIPInterface.start();


	//
	// Configure the radio.
	//

	// Start the transceiver interface.
	// Sleep long enough for the USRP to bootload.
	sleep(5);
	gTRX.start();

	// Set up the interface to the radio.
	// Get a handle to the C0 transceiver interface.
	ARFCNManager* C0radio = gTRX.ARFCN();

	// Tuning.
	// Make sure its off for tuning.
	C0radio->powerOff();
	// Get the ARFCN list.
	unsigned C0 = gConfig.getNum("GSM.Radio.C0");
	// Tune the radio.
	LOG(INFO) << "tuning TRX to ARFCN " << C0;
	ARFCNManager* radio = gTRX.ARFCN();
	radio->tune(C0);

	// Set TSC same as BCC everywhere.
	C0radio->setTSC(gBTS.BCC());

	// Set maximum expected delay spread.
	C0radio->setMaxDelay(gConfig.getNum("GSM.Radio.MaxExpectedDelaySpread"));

	// Set Receiver Gain
	C0radio->setRxGain(gConfig.getNum("GSM.Radio.RxGain"));

	// Turn on and power up.
	C0radio->powerOn();
	C0radio->setPower(gConfig.getNum("GSM.Radio.PowerManager.MinAttenDB"));

	//
	// Create a C-V channel set on C0T0.
	//

	// C-V on C0T0
	C0radio->setSlot(0,5);
	// SCH
	SCHL1FEC SCH;
	SCH.downstream(C0radio);
	SCH.open();
	// FCCH
	FCCHL1FEC FCCH;
	FCCH.downstream(C0radio);
	FCCH.open();
	// BCCH
	BCCHL1FEC BCCH;
	BCCH.downstream(C0radio);
	BCCH.open();
	// RACH
	RACHL1FEC RACH(gRACHC5Mapping);
	RACH.downstream(C0radio);
	RACH.open();
	// CCCHs
	CCCHLogicalChannel CCCH0(gCCCH_0Mapping);
	CCCH0.downstream(C0radio);
	CCCH0.open();
	CCCHLogicalChannel CCCH1(gCCCH_1Mapping);
	CCCH1.downstream(C0radio);
	CCCH1.open();
	CCCHLogicalChannel CCCH2(gCCCH_2Mapping);
	CCCH2.downstream(C0radio);
	CCCH2.open();
	// use CCCHs as AGCHs
	gBTS.addAGCH(&CCCH0);
	gBTS.addAGCH(&CCCH1);
	gBTS.addAGCH(&CCCH2);

	// C-V C0T0 SDCCHs
	SDCCHLogicalChannel C0T0SDCCH[4] = {
		SDCCHLogicalChannel(0,gSDCCH_4_0),
		SDCCHLogicalChannel(0,gSDCCH_4_1),
		SDCCHLogicalChannel(0,gSDCCH_4_2),
		SDCCHLogicalChannel(0,gSDCCH_4_3),
	};
	Thread C0T0SDCCHControlThread[4];
	for (int i=0; i<4; i++) {
		C0T0SDCCH[i].downstream(C0radio);
		C0T0SDCCHControlThread[i].start((void*(*)(void*))Control::DCCHDispatcher,&C0T0SDCCH[i]);
		C0T0SDCCH[i].open();
		gBTS.addSDCCH(&C0T0SDCCH[i]);
	}


	//
	// Configure the other slots.
	//

	// Count configured slots.
	unsigned sCount = 1;

	if (gConfig.defines("GSM.Channels.C1sFirst")) {
		// Create C-I slots.
		for (int i=0; i<gConfig.getNum("GSM.Channels.NumC1s"); i++) {
			gBTS.createCombinationI(gTRX,sCount);
			sCount++;
		}
	}

	// Create C-VII slots.
	for (int i=0; i<gConfig.getNum("GSM.Channels.NumC7s"); i++) {
		gBTS.createCombinationVII(gTRX,sCount);
		sCount++;
	}

	if (!gConfig.defines("GSM.Channels.C1sFirst")) {
		// Create C-I slots.
		for (int i=0; i<gConfig.getNum("GSM.Channels.NumC1s"); i++) {
			gBTS.createCombinationI(gTRX,sCount);
			sCount++;
		}
	}


	// Set up idle filling on C0 as needed.
	while (sCount<8) {
		gBTS.createCombination0(gTRX,sCount);
		sCount++;
	}

	/*
		Note: The number of different paging subchannels on       
		the CCCH is:                                        
                                                           
		MAX(1,(3 - BS-AG-BLKS-RES)) * BS-PA-MFRMS           
			if CCCH-CONF = "001"                        
		(9 - BS-AG-BLKS-RES) * BS-PA-MFRMS                  
			for other values of CCCH-CONF               
	*/

	// Set up the pager.
	// Set up paging channels.
	// HACK -- For now, use a single paging channel, since paging groups are broken.
	gBTS.addPCH(&CCCH2);

	// Be sure we are not over-reserving.
	LOG_ASSERT(gConfig.getNum("GSM.CCCH.PCH.Reserve")<(int)gBTS.numAGCHs());

	// OK, now it is safe to start the BTS.
	gBTS.start();

#ifdef HAVE_LIBREADLINE // [
	// start console
	using_history();

	static const char * const history_file_name = "/.openbts_history";
	char *history_name = 0;
	char *home_dir = getenv("HOME");

	if(home_dir) {
		size_t home_dir_len = strlen(home_dir);
		size_t history_file_len = strlen(history_file_name);
		size_t history_len = home_dir_len + history_file_len + 1;
		if(history_len > home_dir_len) {
			if(!(history_name = (char *)malloc(history_len))) {
				LOG(ERR) << "malloc failed: " << strerror(errno);
				exit(2);
			}
			memcpy(history_name, home_dir, home_dir_len);
			memcpy(history_name + home_dir_len, history_file_name,
			   history_file_len + 1);
			read_history(history_name);
		}
	}
#endif // HAVE_LIBREADLINE ]



	LOG(INFO) << "system ready";
	COUT("\n\nWelcome to OpenBTS.  Type \"help\" to see available commands.");
        // FIXME: We want to catch control-d (emacs keybinding for exit())


	// The logging parts were removed from this loop.
	// If we want them back, they will need to go into their own thread.
	while (1) {
#ifdef HAVE_LIBREADLINE // [
		char *inbuf = readline(gConfig.getStr("CLI.Prompt").c_str());
		if (!inbuf) break;
		if (*inbuf) {
			add_history(inbuf);
			// The parser returns -1 on exit.
			if (gParser.process(inbuf, cout, cin)<0) {
				free(inbuf);
				break;
			}
		}
		free(inbuf);
#else // HAVE_LIBREADLINE ][
		cout << endl << gConfig.getStr("CLI.Prompt");
		cout.flush();
		char inbuf[1024];
		cin.getline(inbuf,1024,'\n');
		// The parser returns -1 on exit.
		if (gParser.process(inbuf,cout,cin)<0) break;
#endif // !HAVE_LIBREADLINE ]
	}

#ifdef HAVE_LIBREADLINE // [
	if(history_name) {
		int e = write_history(history_name);
		if(e) {
			fprintf(stderr, "error: history: %s\n", strerror(e));
		}
		free(history_name);
		history_name = 0;
	}
#endif // HAVE_LIBREADLINE ]

	if (gTransceiverPid) kill(gTransceiverPid, SIGKILL);


	}

	catch (ConfigurationTableKeyNotFound e) {

		LOG(ALERT) << "configuration key " << e.key() << " not defined";
		exit(2);
	}

}
// The transaction table.
Control::TransactionTable gTransactionTable;

// Physical status reporting
GSM::PhysicalStatus gPhysStatus;

// The global SIPInterface object.
SIP::SIPInterface gSIPInterface;

// Configure the BTS object based on the config file.
// So don't create this until AFTER loading the config file.
GSMConfig gBTS;

// Our interface to the software-defined radio.
TransceiverManager gTRX(gConfig.getStr("TRX.IP").c_str(), gConfig.getNum("TRX.Port"));

// Subscriber registry
SubscriberRegistry gSubscriberRegistry;

// Create a Global Handover Decision Class
GSM::GSMHandover gHandover;


/** Define a function to call any time the configuration database changes. */
void purgeConfig(void*,int,char const*, char const*, sqlite3_int64)
{
	LOG(INFO) << "purging configuration cache";
	gConfig.purge();
	gBTS.regenerateBeacon();
}
示例#9
0
int main(int argc, char *argv[])
{
	srandom(time(NULL));

	COUT("\n\n" << gOpenBTSWelcome << "\n");
	COUT("\nStarting the system...");

	gSetLogLevel(gConfig.getStr("LogLevel"));
	if (gConfig.defines("LogFileName")) {
		gSetLogFile(gConfig.getStr("LogFileName"));
	}

	// Start the transceiver binary, if the path is defined.
	// If the path is not defined, the transceiver must be started by some other process.
	const char *TRXPath = NULL;
	if (gConfig.defines("TRX.Path")) TRXPath=gConfig.getStr("TRX.Path");
	pid_t transceiverPid = 0;
	if (TRXPath) {
		const char *TRXLogLevel = gConfig.getStr("TRX.LogLevel");
		const char *TRXLogFileName = NULL;
		if (gConfig.defines("TRX.LogFileName")) TRXLogFileName=gConfig.getStr("TRX.LogFileName");
		transceiverPid = vfork();
		assert(transceiverPid>=0);
		if (transceiverPid==0) {
			execl(TRXPath,"transceiver",TRXLogLevel,TRXLogFileName,NULL);
			LOG(ERROR) << "cannot start transceiver";
			_exit(0);
		}
	}

	// Start the SIP interface.
	gSIPInterface.start();

	// Start the transceiver interface.
	gTRX.start();

	// Set up the interface to the radio.
	// Get a handle to the C0 transceiver interface.
	ARFCNManager* radio = gTRX.ARFCN(0);

	// Tuning.
	// Make sure its off for tuning.
	radio->powerOff();
	// Set TSC same as BSC everywhere.
	radio->setTSC(gBTS.BCC());
	// Tune.
      	radio->tune(gConfig.getNum("GSM.ARFCN"));
	// C-V on C0T0
	radio->setSlot(0,5);

	// Turn on and power up.
	radio->powerOn();
       	radio->setPower(gConfig.getNum("GSM.PowerAttenDB"));

	// set up a combination V beacon set

	// SCH
	SCHL1FEC SCH;
	SCH.downstream(radio);
	SCH.open();
	// FCCH
	FCCHL1FEC FCCH;
	FCCH.downstream(radio);
	FCCH.open();
	// BCCH
	BCCHL1FEC BCCH;
	BCCH.downstream(radio);
	BCCH.open();
	// RACH
	RACHL1FEC RACH(gRACHC5Mapping);
	RACH.downstream(radio);
	RACH.open();
	// CCCHs
	CCCHLogicalChannel CCCH0(gCCCH_0Mapping);
	CCCH0.downstream(radio);
	CCCH0.open();
	CCCHLogicalChannel CCCH1(gCCCH_1Mapping);
	CCCH1.downstream(radio);
	CCCH1.open();
	CCCHLogicalChannel CCCH2(gCCCH_2Mapping);
	CCCH2.downstream(radio);
	CCCH2.open();
	// use CCCHs as AGCHs
	gBTS.addAGCH(&CCCH0);
	gBTS.addAGCH(&CCCH1);
	gBTS.addAGCH(&CCCH2);

	// C-V C0T0 SDCCHs
	SDCCHLogicalChannel SDCCH[4] = { 
		SDCCHLogicalChannel(0,gSDCCH_4_0),
		SDCCHLogicalChannel(0,gSDCCH_4_1),
		SDCCHLogicalChannel(0,gSDCCH_4_2),
		SDCCHLogicalChannel(0,gSDCCH_4_3)
	};
	Thread SDCCHControlThread[4];
	for (int i=0; i<4; i++) {
		SDCCH[i].downstream(radio);
		SDCCHControlThread[i].start((void*(*)(void*))Control::DCCHDispatcher,&SDCCH[i]);
		SDCCH[i].open();
		gBTS.addSDCCH(&SDCCH[i]);
	}


	// Count configured slots.
	unsigned sCount = 1;

	// Create C-VII slots on C0Tn
	for (unsigned i=0; i<gConfig.getNum("GSM.NumC7s"); i++) {
		radio->setSlot(sCount,7);
		for (unsigned sub=0; sub<8; sub++) {
			SDCCHLogicalChannel* chan = new SDCCHLogicalChannel(sCount,gSDCCH8[sub]);
			chan->downstream(radio);
			Thread* thread = new Thread;
			thread->start((void*(*)(void*))Control::DCCHDispatcher,chan);
			chan->open();
			gBTS.addSDCCH(chan);
		}
		sCount++;
	}


	// Create C-I slots on C0Tn
	for (unsigned i=0; i<gConfig.getNum("GSM.NumC1s"); i++) {
		radio->setSlot(sCount,1);
		TCHFACCHLogicalChannel* chan = new TCHFACCHLogicalChannel(sCount,gTCHF_T[sCount]);
		chan->downstream(radio);
		Thread* thread = new Thread;
		thread->start((void*(*)(void*))Control::DCCHDispatcher,chan);
		chan->open();
		gBTS.addTCH(chan);
		sCount++;
	}

	assert(sCount<=8);



	/*
		Note: The number of different paging subchannels on       
		the CCCH is:                                        
                                                           
		MAX(1,(3 - BS-AG-BLKS-RES)) * BS-PA-MFRMS           
			if CCCH-CONF = "001"                        
		(9 - BS-AG-BLKS-RES) * BS-PA-MFRMS                  
			for other values of CCCH-CONF               
	*/

	// Set up the pager.
	// Set up paging channels.
	gBTS.addPCH(&CCCH2);
	// Start the paging generator
	// Don't start the pager until some PCHs exist!!
	gBTS.pager().start();

	LOG(INFO) << "system ready";
	COUT("\n\nWelcome to OpenBTS.  Type \"help\" to see available commands.");
        // FIXME: We want to catch control-d (emacs keybinding for exit())

	while (1) {
		char inbuf[1024];
		cout << "\nOpenBTS> ";
		cin.getline(inbuf,1024,'\n');
		if (strcmp(inbuf,"exit")==0) break;
		gParser.process(inbuf,cout,cin);
	}

	if (transceiverPid) kill(transceiverPid,SIGKILL);
}
示例#10
0
/** Return warning strings about a potential conflicting value */
vector<string> configurationCrossCheck(const string& key) {
	vector<string> warnings;
	ostringstream warning;

	// GSM.Timer.T3113 should equal SIP.Timer.B
	if (key.compare("GSM.Timer.T3113") == 0 || key.compare("SIP.Timer.B") == 0) {
		string gsm = gConfig.getStr("GSM.Timer.T3113");
		string sip = gConfig.getStr("SIP.Timer.B");
		if (gsm.compare(sip) != 0) {
			warning << "GSM.Timer.T3113 (" << gsm << ") and SIP.Timer.B (" << sip << ") should usually have the same value";
			warnings.push_back(warning.str());
			warning.str(std::string());
		}

	// Control.VEA depends on GSM.CellSelection.NECI
	} else if (key.compare("Control.VEA") == 0 || key.compare("GSM.CellSelection.NECI") == 0) {
		if (gConfig.getBool("Control.VEA") && gConfig.getStr("GSM.CellSelection.NECI").compare("1") != 0) {
			warning << "Control.VEA is enabled but will not be functional until GSM.CellSelection.NECI is set to \"1\"";
			warnings.push_back(warning.str());
			warning.str(std::string());
		}

	// GSM.Timer.T3212 should be a factor of six and shorter than SIP.RegistrationPeriod
	} else if (key.compare("GSM.Timer.T3212") == 0 || key.compare("SIP.RegistrationPeriod") == 0) {
		int gsm = gConfig.getNum("GSM.Timer.T3212");
		int sip = gConfig.getNum("SIP.RegistrationPeriod");
		if (key.compare("GSM.Timer.T3212") == 0 && gsm % 6) {
			warning << "GSM.Timer.T3212 should be a factor of 6";
			warnings.push_back(warning.str());
			warning.str(std::string());
		}
		if (gsm >= sip) {
			warning << "GSM.Timer.T3212 (" << gsm << ") should be shorter than SIP.RegistrationPeriod (" << sip << ")";
			warnings.push_back(warning.str());
			warning.str(std::string());
		}

	// GPRS.ChannelCodingControl.RSSI should normally be 10db more than GSM.Radio.RSSITarget
	} else if (key.compare("GPRS.ChannelCodingControl.RSSI") == 0 || key.compare("GSM.Radio.RSSITarget") == 0) {
		int gprs = gConfig.getNum("GPRS.ChannelCodingControl.RSSI");
		int gsm = gConfig.getNum("GSM.Radio.RSSITarget");
		if ((gprs - gsm) != 10) {
			warning << "GPRS.ChannelCodingControl.RSSI (" << gprs << ") should normally be 10db greater than GSM.Radio.RSSITarget (" << gsm << ")";
			warnings.push_back(warning.str());
			warning.str(std::string());
		}

	// TODO : This NEEDS to be an error not a warning. OpenBTS will fail to start because of an assert if an invalid value is used.
	// GSM.Radio.C0 needs to be inside the valid range of ARFCNs for GSM.Radio.Band
	} else if (key.compare("GSM.Radio.C0") == 0 || key.compare("GSM.Radio.Band") == 0) {
		int c0 = gConfig.getNum("GSM.Radio.C0");
		string band = gConfig.getStr("GSM.Radio.Band");
		string range;
		if (band.compare("850") == 0 && (c0 < 128 || 251 < c0)) {
			range = "128-251";
		} else if (band.compare("900") == 0 && (c0 < 1 || 124 < c0)) {
			range = "1-124";
		} else if (band.compare("1800") == 0 && (c0 < 512 || 885 < c0)) {
			range = "512-885";
		} else if (band.compare("1900") == 0 && (c0 < 512 || 810 < c0)) {
			range = "512-810";
		}
		if (range.length()) {
			warning << "GSM.Radio.C0 (" << c0 << ") falls outside the valid range of ARFCNs " << range << " for GSM.Radio.Band (" << band << ")";
			warnings.push_back(warning.str());
			warning.str(std::string());
		}

	// SGSN.Timer.ImplicitDetach should be at least 240 seconds greater than SGSN.Timer.RAUpdate"
	} else if (key.compare("SGSN.Timer.ImplicitDetach") == 0 || key.compare("SGSN.Timer.RAUpdate") == 0) {
		int detach = gConfig.getNum("SGSN.Timer.ImplicitDetach");
		int update = gConfig.getNum("SGSN.Timer.RAUpdate");
		if ((detach - update) < 240) {
			warning << "SGSN.Timer.ImplicitDetach (" << detach << ") should be at least 240 seconds greater than SGSN.Timer.RAUpdate (" << update << ")";
			warnings.push_back(warning.str());
			warning.str(std::string());
		}

	// Control.LUR.FailedRegistration.Message depends on Control.LUR.FailedRegistration.ShortCode
	} else if (key.compare("Control.LUR.FailedRegistration.Message") == 0 || key.compare("Control.LUR.FailedRegistration.ShortCode") == 0) {
		if (gConfig.getStr("Control.LUR.FailedRegistration.Message").length() && !gConfig.getStr("Control.LUR.FailedRegistration.ShortCode").length()) {
			warning << "Control.LUR.FailedRegistration.Message is enabled but will not be functional until Control.LUR.FailedRegistration.ShortCode is set";
			warnings.push_back(warning.str());
			warning.str(std::string());
		}

	// Control.LUR.NormalRegistration.Message depends on Control.LUR.NormalRegistration.ShortCode
	} else if (key.compare("Control.LUR.NormalRegistration.Message") == 0 || key.compare("Control.LUR.NormalRegistration.ShortCode") == 0) {
		if (gConfig.getStr("Control.LUR.NormalRegistration.Message").length() && !gConfig.getStr("Control.LUR.NormalRegistration.ShortCode").length()) {
			warning << "Control.LUR.NormalRegistration.Message is enabled but will not be functional until Control.LUR.NormalRegistration.ShortCode is set";
			warnings.push_back(warning.str());
			warning.str(std::string());
		}

	// Control.LUR.OpenRegistration depends on Control.LUR.OpenRegistration.ShortCode
	} else if (key.compare("Control.LUR.OpenRegistration") == 0 || key.compare("Control.LUR.OpenRegistration.ShortCode") == 0) {
		if (gConfig.getStr("Control.LUR.OpenRegistration").length() && !gConfig.getStr("Control.LUR.OpenRegistration.ShortCode").length()) {
			warning << "Control.LUR.OpenRegistration is enabled but will not be functional until Control.LUR.OpenRegistration.ShortCode is set";
			warnings.push_back(warning.str());
			warning.str(std::string());
		}

	// TODO : SIP.SMSC is actually broken with the verification bits, no way to set value as null
	// SIP.SMSC should normally be NULL if SMS.MIMIEType is "text/plain" and "smsc" if SMS.MIMEType is "application/vnd.3gpp".
	} else if (key.compare("SMS.MIMEType") == 0 || key.compare("SIP.SMSC") == 0) {
		string sms = gConfig.getStr("SMS.MIMEType");
		string sip = gConfig.getStr("SIP.SMSC");
		if (sms.compare("application/vnd.3gpp.sms") == 0 && sip.compare("smsc") != 0) {
			warning << "SMS.MIMEType is set to \"application/vnc.3gpp.sms\", SIP.SMSC should usually be set to \"smsc\"";
			warnings.push_back(warning.str());
			warning.str(std::string());
		} else if (sms.compare("text/plain") == 0 && sip.compare("") != 0) {
			warning << "SMS.MIMEType is set to \"text/plain\", SIP.SMSC should usually be empty (use unconfig to clear)";
			warnings.push_back(warning.str());
			warning.str(std::string());
		}

	// SIP.Local.IP cannot be 127.0.0.1 when any of the SIP.Proxy.* settings are non-localhost
	} else if (key.compare("SIP.Local.IP") == 0 ||
				key.compare("SIP.Proxy.Registration") == 0 || key.compare("SIP.Proxy.SMS") == 0 ||
				key.compare("SIP.Proxy.Speech") == 0 || key.compare("SIP.Proxy.USSD") == 0) {
		string loopback = "127.0.0.1";
		string local = gConfig.getStr("SIP.Local.IP");
		if (local.compare(loopback) == 0) {
			string registration = gConfig.getStr("SIP.Proxy.Registration");
			string sms = gConfig.getStr("SIP.Proxy.SMS");
			string speech = gConfig.getStr("SIP.Proxy.Speech");
			string ussd = gConfig.getStr("SIP.Proxy.USSD");
			if (registration.find(loopback) == std::string::npos ||
				sms.find(loopback) == std::string::npos || speech.find(loopback) == std::string::npos ||
				(ussd.length() && ussd.find(loopback) == std::string::npos)) {
				warning << "A non-local IP is being used for one or more SIP.Proxy.* settings but SIP.Local.IP is still set to 127.0.0.1. ";
				warning << "Set SIP.Local.IP to the IP address of this machine as seen by the proxies.";
				warnings.push_back(warning.str());
				warning.str(std::string());
			}
		}

	// GSM.MS.Power.Min cannot be higher than GSM.MS.Power.Max
	} else if (key.compare("GSM.MS.Power.Min") == 0 || key.compare("GSM.MS.Power.Max") == 0) {
		if (gConfig.getNum("GSM.MS.Power.Min") > gConfig.getNum("GSM.MS.Power.Max")) {
			warning << "GSM.MS.Power.Min is set higher than GSM.MS.Power.Max. Swap the values or set a new minimum.";
			warnings.push_back(warning.str());
			warning.str(std::string());
		}

	// GSM.Channels.NumC1s + GSM.Channels.NumC1s must fall within 8 * GSM.Radio.ARFCNs
	} else if (key.compare("GSM.Radio.ARFCNs") == 0 || key.compare("GSM.Channels.NumC1s") == 0 || key.compare("GSM.Channels.NumC7s") == 0) {
		int max = (8 * gConfig.getNum("GSM.Radio.ARFCNs")) - 1;
		int current = gConfig.getNum("GSM.Channels.NumC1s") + gConfig.getNum("GSM.Channels.NumC7s");
		if (max < current) {
			warning << "There are only " << max << " channels available but " << current << " are configured. ";
			warning << "Reduce GSM.Channels.NumC1s and/or GSM.Channels.NumC7s accordingly.";
			warnings.push_back(warning.str());
			warning.str(std::string());
		} else if (max > current) {
			int avail = max-current;
			if (avail == 1) {
				warning << "There is still " << avail << " channel available for additional capacity. ";
			} else {
				warning << "There are still " << avail << " channels available for additional capacity. ";
			}
			warning << "Increase GSM.Channels.NumC1s and/or GSM.Channels.NumC7s accordingly.";
			warnings.push_back(warning.str());
			warning.str(std::string());
		}
	}

	return warnings;
}
int
main(int argc, char **argv)
{
	sockaddr_in si_me;
	sockaddr_in si_other;
	int aSocket;
	char buf[BUFLEN];

	LOG(ALERT) << argv[0] << " (re)starting";
	srand ( time(NULL) + (int)getpid() );
	my_udp_port = gConfig.getNum("SubscriberRegistry.Port");
	gSubscriberRegistry.init();

	// init osip lib
	osip_t *osip;
	int i=osip_init(&osip);
	if (i!=0) {
		LOG(ALERT) << "cannot init sip lib";
		return NULL;
	}

	if ((aSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
		LOG(ALERT) << "can't initialize socket";
		exit(1);
	}

	memset((char *) &si_me, 0, sizeof(si_me));
	si_me.sin_family = AF_INET;
	si_me.sin_port = htons(my_udp_port);
	si_me.sin_addr.s_addr = htonl(INADDR_ANY);
	if (bind(aSocket, (sockaddr*)&si_me, sizeof(si_me)) == -1) {
		LOG(ALERT) << "can't bind socket on port " << my_udp_port;
		exit(1);
	}

	LOG(NOTICE) << "binding on port " << my_udp_port;

	while (true) {
		gConfig.purge();
		socklen_t slen = sizeof(si_other);
		memset(buf, 0, BUFLEN);
		if (recvfrom(aSocket, buf, BUFLEN, 0, (sockaddr*)&si_other, &slen) == -1) {
			LOG(ERR) << "recvfrom problem";
			continue;
		}

		LOG(INFO) << " receiving " << buf;

		char *dest = processBuffer(buf);
		if (dest == NULL) {
			continue;
		}

		if (sendto(aSocket, dest, strlen(dest), 0, (sockaddr*)&si_other, sizeof(si_other)) == -1) {
			LOG(ERR) << "sendto problem";
			continue;
		}
		osip_free(dest);
	}

	close(aSocket);
	return 0;
}
示例#12
0
// Physical status reporting
GSM::PhysicalStatus gPhysStatus;

// Configure the BTS object based on the config file.
// So don't create this until AFTER loading the config file.
GSMConfig gBTS;

// Note to all from pat:
// It is inadvisable to statically initialize any non-trivial entity here because
// the underlying dependencies may not yet have undergone their static initialization.
// For example, if any of these throw an alarm, the system will crash because
// the Logger may not have been initialized yet.

// Our interface to the software-defined radio.
TransceiverManager gTRX(gConfig.getNum("GSM.Radio.ARFCNs"), gConfig.getStr("TRX.IP").c_str(), gConfig.getNum("TRX.Port"));

/** The global peering interface. */
Peering::PeerInterface gPeerInterface;

/** The global neighbor table. */
Peering::NeighborTable gNeighborTable;


/** Define a function to call any time the configuration database changes. */
void purgeConfig(void*,int,char const*, char const*, sqlite3_int64)
{
	// (pat) NO NO NO.  Do not call LOG from here - it may result in infinite recursion.
	// LOG(INFO) << "purging configuration cache";
	gConfig.purge();
	gBTS.regenerateBeacon();
示例#13
0
int main(int argc, char *argv[])
{
	// TODO: Properly parse and handle any arguments
	if (argc > 1) {
		for (int argi = 0; argi < argc; argi++) {
			if (!strcmp(argv[argi], "--version") ||
			    !strcmp(argv[argi], "-v")) {
				cout << gVersionString << endl;
			}
		}

		return 0;
	}

	createStats();
 
	gReports.incr("OpenBTS.Starts");

	int sock = socket(AF_UNIX,SOCK_DGRAM,0);
	if (sock<0) {
		perror("creating CLI datagram socket");
		LOG(ALERT) << "cannot create socket for CLI";
		gReports.incr("OpenBTS.Exit.CLI.Socket");
		exit(1);
	}

	try {

	srandom(time(NULL));

	gConfig.setUpdateHook(purgeConfig);
	gLogInit("openbts",gConfig.getStr("Log.Level").c_str());
	LOG(ALERT) << "OpenBTS starting, ver " << VERSION << " build date " << __DATE__;

	COUT("\n\n" << gOpenBTSWelcome << "\n");
	gTMSITable.open(gConfig.getStr("Control.Reporting.TMSITable").c_str());
	gTransactionTable.init(gConfig.getStr("Control.Reporting.TransactionTable").c_str());
	gPhysStatus.open(gConfig.getStr("Control.Reporting.PhysStatusTable").c_str());
	gBTS.init();
	gSubscriberRegistry.init();
	gParser.addCommands();

	COUT("\nStarting the system...");

	// is the radio running?
	// Start the transceiver interface.
	LOG(INFO) << "checking transceiver";
	//gTRX.ARFCN(0)->powerOn();
	//sleep(gConfig.getNum("TRX.Timeout.Start",2));
	bool haveTRX = gTRX.ARFCN(0)->powerOn(false);

	Thread transceiverThread;
	if (!haveTRX) {
		transceiverThread.start((void*(*)(void*)) startTransceiver, NULL);
		// sleep to let the FPGA code load
		// TODO: we should be "pinging" the radio instead of sleeping
		sleep(5);
	} else {
		LOG(NOTICE) << "transceiver already running";
	}

	// Start the SIP interface.
	gSIPInterface.start();


	//
	// Configure the radio.
	//

	gTRX.start();

	// Set up the interface to the radio.
	// Get a handle to the C0 transceiver interface.
	ARFCNManager* C0radio = gTRX.ARFCN(0);

	// Tuning.
	// Make sure its off for tuning.
	//C0radio->powerOff();
	// Get the ARFCN list.
	unsigned C0 = gConfig.getNum("GSM.Radio.C0");
	unsigned numARFCNs = gConfig.getNum("GSM.Radio.ARFCNs");
	for (unsigned i=0; i<numARFCNs; i++) {
		// Tune the radios.
		unsigned ARFCN = C0 + i*2;
		LOG(INFO) << "tuning TRX " << i << " to ARFCN " << ARFCN;
		ARFCNManager* radio = gTRX.ARFCN(i);
		radio->tune(ARFCN);
	}

	// Send either TSC or full BSIC depending on radio need
	if (gConfig.getBool("GSM.Radio.NeedBSIC")) {
		// Send BSIC to 
		C0radio->setBSIC(gBTS.BSIC());
	} else {
		// Set TSC same as BCC everywhere.
		C0radio->setTSC(gBTS.BCC());
	}

	// Set maximum expected delay spread.
	C0radio->setMaxDelay(gConfig.getNum("GSM.Radio.MaxExpectedDelaySpread"));

	// Set Receiver Gain
	C0radio->setRxGain(gConfig.getNum("GSM.Radio.RxGain"));

	// Turn on and power up.
	C0radio->powerOn(true);
	C0radio->setPower(gConfig.getNum("GSM.Radio.PowerManager.MinAttenDB"));

	//
	// Create a C-V channel set on C0T0.
	//

	// C-V on C0T0
	C0radio->setSlot(0,5);
	// SCH
	SCHL1FEC SCH;
	SCH.downstream(C0radio);
	SCH.open();
	// FCCH
	FCCHL1FEC FCCH;
	FCCH.downstream(C0radio);
	FCCH.open();
	// BCCH
	BCCHL1FEC BCCH;
	BCCH.downstream(C0radio);
	BCCH.open();
	// RACH
	RACHL1FEC RACH(gRACHC5Mapping);
	RACH.downstream(C0radio);
	RACH.open();
	// CCCHs
	CCCHLogicalChannel CCCH0(gCCCH_0Mapping);
	CCCH0.downstream(C0radio);
	CCCH0.open();
	CCCHLogicalChannel CCCH1(gCCCH_1Mapping);
	CCCH1.downstream(C0radio);
	CCCH1.open();
	CCCHLogicalChannel CCCH2(gCCCH_2Mapping);
	CCCH2.downstream(C0radio);
	CCCH2.open();
	// use CCCHs as AGCHs
	gBTS.addAGCH(&CCCH0);
	gBTS.addAGCH(&CCCH1);
	gBTS.addAGCH(&CCCH2);

	// C-V C0T0 SDCCHs
	SDCCHLogicalChannel C0T0SDCCH[4] = {
		SDCCHLogicalChannel(0,0,gSDCCH_4_0),
		SDCCHLogicalChannel(0,0,gSDCCH_4_1),
		SDCCHLogicalChannel(0,0,gSDCCH_4_2),
		SDCCHLogicalChannel(0,0,gSDCCH_4_3),
	};
	Thread C0T0SDCCHControlThread[4];
	for (int i=0; i<4; i++) {
		C0T0SDCCH[i].downstream(C0radio);
		C0T0SDCCHControlThread[i].start((void*(*)(void*))Control::DCCHDispatcher,&C0T0SDCCH[i]);
		C0T0SDCCH[i].open();
		gBTS.addSDCCH(&C0T0SDCCH[i]);
	}


	//
	// Configure the other slots.
	//

	// Count configured slots.
	unsigned sCount = 1;

	if (gConfig.defines("GSM.Channels.C1sFirst")) {
		// Create C-I slots.
		for (int i=0; i<gConfig.getNum("GSM.Channels.NumC1s"); i++) {
			gBTS.createCombinationI(gTRX,sCount/8,sCount%8);
			sCount++;
		}
	}

	// Create C-VII slots.
	for (int i=0; i<gConfig.getNum("GSM.Channels.NumC7s"); i++) {
		gBTS.createCombinationVII(gTRX,sCount/8,sCount%8);
		sCount++;
	}

	if (!gConfig.defines("GSM.Channels.C1sFirst")) {
		// Create C-I slots.
		for (int i=0; i<gConfig.getNum("GSM.Channels.NumC1s"); i++) {
			gBTS.createCombinationI(gTRX,sCount/8,sCount%8);
			sCount++;
		}
	}


	// Set up idle filling on C0 as needed.
	while (sCount<8) {
		gBTS.createCombination0(gTRX,sCount);
		sCount++;
	}

	/*
		Note: The number of different paging subchannels on       
		the CCCH is:                                        
                                                           
		MAX(1,(3 - BS-AG-BLKS-RES)) * BS-PA-MFRMS           
			if CCCH-CONF = "001"                        
		(9 - BS-AG-BLKS-RES) * BS-PA-MFRMS                  
			for other values of CCCH-CONF               
	*/

	// Set up the pager.
	// Set up paging channels.
	// HACK -- For now, use a single paging channel, since paging groups are broken.
	gBTS.addPCH(&CCCH2);

	// Be sure we are not over-reserving.
	if (gConfig.getNum("GSM.Channels.SDCCHReserve")>=(int)gBTS.SDCCHTotal()) {
		unsigned val = gBTS.SDCCHTotal() - 1;
		LOG(CRIT) << "GSM.Channels.SDCCHReserve too big, changing to " << val;
		gConfig.set("GSM.Channels.SDCCHReserve",val);
	}


	// OK, now it is safe to start the BTS.
	gBTS.start();


	cout << "\nsystem ready\n";
	cout << "\nuse the OpenBTSCLI utility to access CLI\n";
	LOG(INFO) << "system ready";

	struct sockaddr_un cmdSockName;
	cmdSockName.sun_family = AF_UNIX;
	const char* sockpath = gConfig.getStr("CLI.SocketPath").c_str();
	char rmcmd[strlen(sockpath)+5];
	sprintf(rmcmd,"rm %s",sockpath);
	system(rmcmd);
	strcpy(cmdSockName.sun_path,sockpath);
	if (bind(sock, (struct sockaddr *) &cmdSockName, sizeof(struct sockaddr_un))) {
		perror("binding name to cmd datagram socket");
		LOG(ALERT) << "cannot bind socket for CLI at " << sockpath;
		gReports.incr("OpenBTS.Exit.CLI.Socket");
		exit(1);
	}

	while (1) {
		char cmdbuf[1000];
		struct sockaddr_un source;
		socklen_t sourceSize = sizeof(source);
		int nread = recvfrom(sock,cmdbuf,sizeof(cmdbuf)-1,0,(struct sockaddr*)&source,&sourceSize);
		gReports.incr("OpenBTS.CLI.Command");
		cmdbuf[nread]='\0';
		LOG(INFO) << "received command \"" << cmdbuf << "\" from " << source.sun_path;
		std::ostringstream sout;
		int res = gParser.process(cmdbuf,sout);
		const std::string rspString= sout.str();
		const char* rsp = rspString.c_str();
		LOG(INFO) << "sending " << strlen(rsp) << "-char result to " << source.sun_path;
		if (sendto(sock,rsp,strlen(rsp)+1,0,(struct sockaddr*)&source,sourceSize)<0) {
			LOG(ERR) << "can't send CLI response to " << source.sun_path;
			gReports.incr("OpenBTS.CLI.Command.ResponseFailure");
		}
		// res<0 means to exit the application
		if (res<0) break;
		gReports.incr("OpenBTS.Exit.Normal.CLI");
	}

	} // try

	catch (ConfigurationTableKeyNotFound e) {
		LOG(EMERG) << "required configuration parameter " << e.key() << " not defined, aborting";
		gReports.incr("OpenBTS.Exit.Error.ConfigurationParamterNotFound");
	}

	//if (gTransceiverPid) kill(gTransceiverPid, SIGKILL);
	close(sock);

}
示例#14
0
int main(int argc, char *argv[])
{

	gConfig.setUpdateHook(purgeConfig);

	const char *keys[5] = {"key1", "key2", "key3", "key4", "key5"};

	for (int i=0; i<5; i++) {
		gConfig.set(keys[i],i);
	}

	for (int i=0; i<5; i++) {
		cout << "table[" << keys[i] << "]=" << gConfig.getStr(keys[i]) <<  endl;
		cout << "table[" << keys[i] << "]=" << gConfig.getNum(keys[i]) <<  endl;
	}

	for (int i=0; i<5; i++) {
		cout << "defined table[" << keys[i] << "]=" << gConfig.defines(keys[i]) <<  endl;
	}

	gConfig.set("key5","100 200 300  400 ");
	std::vector<unsigned> vect = gConfig.getVector("key5");
	cout << "vect length " << vect.size() << ": ";
	for (unsigned i=0; i<vect.size(); i++) cout << " " << vect[i];
	cout << endl;
	std::vector<string> svect = gConfig.getVectorOfStrings("key5");
	cout << "vect length " << svect.size() << ": ";
	for (unsigned i=0; i<svect.size(); i++) cout << " " << svect[i] << ":";
	cout << endl;

	cout << "bool " << gConfig.getBool("booltest") << endl;
	gConfig.set("booltest",1);
	cout << "bool " << gConfig.getBool("booltest") << endl;
	gConfig.set("booltest",0);
	cout << "bool " << gConfig.getBool("booltest") << endl;

	gConfig.getStr("newstring");
	gConfig.getNum("numnumber");


	SimpleKeyValue pairs;
	pairs.addItems(" a=1 b=34 dd=143 ");
	cout<< pairs.get("a") << endl;
	cout<< pairs.get("b") << endl;
	cout<< pairs.get("dd") << endl;

	gConfig.set("fkey","123.456");
	float fval = gConfig.getFloat("fkey");
	cout << "fkey " << fval << endl;

	cout << "search fkey:" << endl;
	gConfig.find("fkey",cout);
	cout << "search fkey:" << endl;
	gConfig.find("fkey",cout);
	gConfig.remove("fkey");
	cout << "search fkey:" << endl;
	gConfig.find("fkey",cout);

	try {
		gConfig.getNum("supposedtoabort");
	} catch (ConfigurationTableKeyNotFound) {
		cout << "ConfigurationTableKeyNotFound exception successfully caught." << endl;
	}
}
示例#15
0
int main(int argc, char *argv[])
{
  if ( signal( SIGINT, ctrlCHandler ) == SIG_ERR )
  {
    cerr << "Couldn't install signal handler for SIGINT" << endl;
    exit(1);
  }

  if ( signal( SIGTERM, ctrlCHandler ) == SIG_ERR )
  {
    cerr << "Couldn't install signal handler for SIGTERM" << endl;
    exit(1);
  }
  // Configure logger.
  gLogInit("transceiver",gConfig.getStr("Log.Level").c_str(),LOG_LOCAL7);
  if (gLogConn.valid())
    Log::gHook = Connection::LogConnection::hook;

  // Device specific global initialization
  RadioDevice::staticInit();

  int numARFCN=1;
  if (argc>1) numARFCN = atoi(argv[1]);

  std::string deviceArgs = "";
  if (argc>2) deviceArgs = argv[2];

  srandom(time(NULL));

  int mOversamplingRate = 1;
  switch(numARFCN) {

	  // DAVID COMMENT: I have no way to test this, but I would bet that you can
	  // just change these numbers to get different oversampling rates for single-ARFCN
	  // operation..

  case 1: 
	mOversamplingRate = 1;
	break;
  case 2:
	mOversamplingRate = 6;
 	break;
  case 3:
	mOversamplingRate = 8;
	break;
  case 4:
	mOversamplingRate = 12;
	break;
  case 5:
	mOversamplingRate = 16;
	break;
  default:
	break;
  }
  int minOver = gConfig.getNum("TRX.MinOversampling");
  if (mOversamplingRate < minOver)
    mOversamplingRate = minOver;
  //int mOversamplingRate = numARFCN/2 + numARFCN;
  //mOversamplingRate = 15; //mOversamplingRate*2;
  //if ((numARFCN > 1) && (mOversamplingRate % 2)) mOversamplingRate++;

/*
  RAD1Device *usrp = new RAD1Device(mOversamplingRate*1625.0e3/6.0);
  //DummyLoad *usrp = new DummyLoad(mOversamplingRate*1625.0e3/6.0);
  usrp->make(false, deviceID); 
*/
  RadioDevice* usrp = RadioDevice::make(mOversamplingRate);
  if (!usrp->open(deviceArgs)) {
    LOG(ALERT) << "Transceiver exiting..." << std::endl;
    return EXIT_FAILURE;
  }

  RadioInterface* radio = new RadioInterface(usrp,3,SAMPSPERSYM,SAMPSPERSYM*mOversamplingRate,false,numARFCN);
  Transceiver *trx = new Transceiver(gConfig.getNum("TRX.Port"),gConfig.getStr("TRX.IP").c_str(),SAMPSPERSYM,GSM::Time(2,0),radio,
				     numARFCN,mOversamplingRate,false);
  trx->receiveFIFO(radio->receiveFIFO());

/*
  signalVector *gsmPulse = generateGSMPulse(2,1);
  BitVector normalBurstSeg = "0000101010100111110010101010010110101110011000111001101010000";
  BitVector normalBurst(BitVector(normalBurstSeg,gTrainingSequence[0]),normalBurstSeg);
  signalVector *modBurst = modulateBurst(normalBurst,*gsmPulse,8,1);
  signalVector *modBurst9 = modulateBurst(normalBurst,*gsmPulse,9,1);
  signalVector *interpolationFilter = createLPF(0.6/mOversamplingRate,6*mOversamplingRate,1);
  signalVector totalBurst1(*modBurst,*modBurst9);
  signalVector totalBurst2(*modBurst,*modBurst);
  signalVector totalBurst(totalBurst1,totalBurst2);
  scaleVector(totalBurst,usrp->fullScaleInputValue());
  double beaconFreq = -1.0*(numARFCN-1)*200e3;
  signalVector finalVec(625*mOversamplingRate);
  for (int j = 0; j < numARFCN; j++) {
	signalVector *frequencyShifter = new signalVector(625*mOversamplingRate);
	frequencyShifter->fill(1.0);
	frequencyShift(frequencyShifter,frequencyShifter,2.0*M_PI*(beaconFreq+j*400e3)/(1625.0e3/6.0*mOversamplingRate));
  	signalVector *interpVec = polyphaseResampleVector(totalBurst,mOversamplingRate,1,interpolationFilter);
	multVector(*interpVec,*frequencyShifter);
	addVector(finalVec,*interpVec); 	
  }
  signalVector::iterator itr = finalVec.begin();
  short finalVecShort[2*finalVec.size()];
  short *shortItr = finalVecShort;
  while (itr < finalVec.end()) {
	*shortItr++ = (short) (itr->real());
	*shortItr++ = (short) (itr->imag());
	itr++;
  }
  usrp->loadBurst(finalVecShort,finalVec.size());
*/
  trx->start();
  gLogConn.write("Starting transceiver");
  //int i = 0;
  while(!gbShutdown) { sleep(1); } //i++; if (i==60) exit(1);}

  cout << "Shutting down transceiver..." << endl;

//  trx->stop();
  delete trx;
//  delete radio;
}
示例#16
0
int main(int argc, char *argv[])
{
  if ( signal( SIGINT, ctrlCHandler ) == SIG_ERR )
  {
    cerr << "Couldn't install signal handler for SIGINT" << endl;
    exit(1);
  }

  if ( signal( SIGTERM, ctrlCHandler ) == SIG_ERR )
  {
    cerr << "Couldn't install signal handler for SIGTERM" << endl;
    exit(1);
  }
  // Configure logger.
  gLogInit("transceiver",gConfig.getStr("Log.Level").c_str(),LOG_LOCAL7);

  int numARFCN=1;
  if (argc>1) numARFCN = atoi(argv[1]);

  int deviceID = 0;
  if (argc>2) deviceID = atoi(argv[2]);

  gFactoryCalibration.readEEPROM(deviceID);
 

  srandom(time(NULL));

  int mOversamplingRate = 1;
  switch(numARFCN) {
   
  case 1: 
	mOversamplingRate = 1;
	break;
  case 2:
	mOversamplingRate = 6;
 	break;
  case 3:
	mOversamplingRate = 8;
	break;
  case 4:
	mOversamplingRate = 12;
	break;
  case 5:
	mOversamplingRate = 16;
	break;
  default:
	break;
  }
  //int mOversamplingRate = numARFCN/2 + numARFCN;
  //mOversamplingRate = 15; //mOversamplingRate*2;
  //if ((numARFCN > 1) && (mOversamplingRate % 2)) mOversamplingRate++;
  RAD1Device *usrp = new RAD1Device(mOversamplingRate*1625.0e3/6.0);
  //DummyLoad *usrp = new DummyLoad(mOversamplingRate*1625.0e3/6.0);
  usrp->make(false, deviceID); 

  RadioInterface* radio = new RadioInterface(usrp,3,SAMPSPERSYM,mOversamplingRate,false,numARFCN);
  Transceiver *trx = new Transceiver(gConfig.getNum("TRX.Port"),gConfig.getStr("TRX.IP").c_str(),SAMPSPERSYM,GSM::Time(2,0),radio,
				     numARFCN,mOversamplingRate,false);
  trx->receiveFIFO(radio->receiveFIFO());

/*
  signalVector *gsmPulse = generateGSMPulse(2,1);
  BitVector normalBurstSeg = "0000101010100111110010101010010110101110011000111001101010000";
  BitVector normalBurst(BitVector(normalBurstSeg,gTrainingSequence[0]),normalBurstSeg);
  signalVector *modBurst = modulateBurst(normalBurst,*gsmPulse,8,1);
  signalVector *modBurst9 = modulateBurst(normalBurst,*gsmPulse,9,1);
  signalVector *interpolationFilter = createLPF(0.6/mOversamplingRate,6*mOversamplingRate,1);
  signalVector totalBurst1(*modBurst,*modBurst9);
  signalVector totalBurst2(*modBurst,*modBurst);
  signalVector totalBurst(totalBurst1,totalBurst2);
  scaleVector(totalBurst,usrp->fullScaleInputValue());
  double beaconFreq = -1.0*(numARFCN-1)*200e3;
  signalVector finalVec(625*mOversamplingRate);
  for (int j = 0; j < numARFCN; j++) {
	signalVector *frequencyShifter = new signalVector(625*mOversamplingRate);
	frequencyShifter->fill(1.0);
	frequencyShift(frequencyShifter,frequencyShifter,2.0*M_PI*(beaconFreq+j*400e3)/(1625.0e3/6.0*mOversamplingRate));
  	signalVector *interpVec = polyphaseResampleVector(totalBurst,mOversamplingRate,1,interpolationFilter);
	multVector(*interpVec,*frequencyShifter);
	addVector(finalVec,*interpVec); 	
  }
  signalVector::iterator itr = finalVec.begin();
  short finalVecShort[2*finalVec.size()];
  short *shortItr = finalVecShort;
  while (itr < finalVec.end()) {
	*shortItr++ = (short) (itr->real());
	*shortItr++ = (short) (itr->imag());
	itr++;
  }
  usrp->loadBurst(finalVecShort,finalVec.size());
*/
  trx->start();
  //int i = 0;
  while(!gbShutdown) { sleep(1); } //i++; if (i==60) exit(1);}

  cout << "Shutting down transceiver..." << endl;

//  trx->stop();
  delete trx;
//  delete radio;
}
示例#17
0
int main(int argc, char *argv[])
{
	//mtrace();       // (pat) Enable memory leak detection.  Unfortunately, huge amounts of code have been started in the constructors above.
	gLogGroup.setAll();
	// TODO: Properly parse and handle any arguments
	if (argc > 1) {
		bool testflag = false;
		for (int argi = 1; argi < argc; argi++) {		// Skip argv[0] which is the program name.
			if (!strcmp(argv[argi], "--version") || !strcmp(argv[argi], "-v")) {
				// Print the version number and exit immediately.
				cout << gVersionString << endl;
				return 0;
			}
			if (!strcmp(argv[argi], "--test")) {
				testflag = true;
				continue;
			}
			if (!strcmp(argv[argi], "--gensql")) {
				cout << gConfig.getDefaultSQL(string(argv[0]), gVersionString) << endl;
				return 0;
			}
			if (!strcmp(argv[argi], "--gentex")) {
				cout << gConfig.getTeX(string(argv[0]), gVersionString) << endl;
				return 0;
			}

			// (pat) Adding support for specified sql file.
			// Unfortunately, the Config table was inited quite some time ago,
			// so stick this arg in the environment, whence the ConfigurationTable can find it, and then reboot.
			if (!strcmp(argv[argi],"--config")) {
				if (++argi == argc) {
					LOG(ALERT) <<"Missing argument to --config option";
					exit(2);
				}
				setenv(cOpenBTSConfigEnv,argv[argi],1);
				execl(argv[0],"OpenBTS",NULL);
				LOG(ALERT) <<"execl failed?  Exiting...";
				exit(0);
			}
			if (!strcmp(argv[argi],"--help")) {
				printf("OpenBTS [--version --gensql --gentex] [--config file.db]\n");
				printf("OpenBTS exiting...\n");
				exit(0);
			}

			printf("OpenBTS: unrecognized argument: %s\nexiting...\n",argv[argi]);
		}

		if (testflag) { GSM::TestTCHL1FEC(); return 0; }
	}

	createStats();

	gConfig.setCrossCheckHook(&configurationCrossCheck);

	gReports.incr("OpenBTS.Starts");

	gNeighborTable.NeighborTableInit(
		gConfig.getStr("Peering.NeighborTable.Path").c_str());

	int sock = socket(AF_UNIX,SOCK_DGRAM,0);
	if (sock<0) {
		perror("creating CLI datagram socket");
		LOG(ALERT) << "cannot create socket for CLI";
		gReports.incr("OpenBTS.Exit.CLI.Socket");
		exit(1);
	}

	try {

	srandom(time(NULL));

	gConfig.setUpdateHook(purgeConfig);
	LOG(ALERT) << "OpenBTS (re)starting, ver " << VERSION << " build date " << __DATE__;
	LOG(ALERT) << "OpenBTS reading config file "<<cOpenBTSConfigFile;

	COUT("\n\n" << gOpenBTSWelcome << "\n");
	Control::controlInit();		// init Layer3: TMSITable, TransactionTable.
	gPhysStatus.open(gConfig.getStr("Control.Reporting.PhysStatusTable").c_str());
	gBTS.init();
	gParser.addCommands();

	COUT("\nStarting the system...");

	// is the radio running?
	// Start the transceiver interface.
	LOG(INFO) << "checking transceiver";
	//gTRX.ARFCN(0)->powerOn();
	//sleep(gConfig.getNum("TRX.Timeout.Start"));
	//bool haveTRX = gTRX.ARFCN(0)->powerOn(false);		This prints an inapplicable warning message.
	bool haveTRX = gTRX.ARFCN(0)->trxRunning();			// This does not print an inapplicable warning message.

	Thread transceiverThread;
	if (!haveTRX) {
		LOG(ALERT) << "starting the transceiver";
		transceiverThread.start((void*(*)(void*)) startTransceiver, NULL);
		// sleep to let the FPGA code load
		// TODO: we should be "pinging" the radio instead of sleeping
		sleep(5);
	} else {
		LOG(NOTICE) << "transceiver already running";
	}

	// Start the SIP interface.
	SIP::SIPInterfaceStart();

	// Start the peer interface
	gPeerInterface.start();

	// Sync factory calibration as defaults from radio EEPROM
	signed sdrsn = gTRX.ARFCN(0)->getFactoryCalibration("sdrsn");
	if (sdrsn != 0 && sdrsn != 65535) {
		signed val;

		val = gTRX.ARFCN(0)->getFactoryCalibration("band");
		if (gConfig.isValidValue("GSM.Radio.Band", val)) {
			gConfig.mSchema["GSM.Radio.Band"].updateDefaultValue(val);
		}

		val = gTRX.ARFCN(0)->getFactoryCalibration("freq");
		if (gConfig.isValidValue("TRX.RadioFrequencyOffset", val)) {
			gConfig.mSchema["TRX.RadioFrequencyOffset"].updateDefaultValue(val);
		}

		val = gTRX.ARFCN(0)->getFactoryCalibration("rxgain");
		if (gConfig.isValidValue("GSM.Radio.RxGain", val)) {
			gConfig.mSchema["GSM.Radio.RxGain"].updateDefaultValue(val);
		}

		val = gTRX.ARFCN(0)->getFactoryCalibration("txgain");
		if (gConfig.isValidValue("TRX.TxAttenOffset", val)) {
			gConfig.mSchema["TRX.TxAttenOffset"].updateDefaultValue(val);
		}
	}

	// Limit valid ARFCNs to current band
	gConfig.mSchema["GSM.Radio.C0"].updateValidValues(getARFCNsString(gConfig.getNum("GSM.Radio.Band")));

	//
	// Configure the radio.
	//

	gTRX.start();

	// Set up the interface to the radio.
	// Get a handle to the C0 transceiver interface.
	ARFCNManager* C0radio = gTRX.ARFCN(0);

	// Tuning.
	// Make sure its off for tuning.
	//C0radio->powerOff();
	// Get the ARFCN list.
	unsigned C0 = gConfig.getNum("GSM.Radio.C0");
	unsigned numARFCNs = gConfig.getNum("GSM.Radio.ARFCNs");
	for (unsigned i=0; i<numARFCNs; i++) {
		// Tune the radios.
		unsigned ARFCN = C0 + i*2;
		LOG(INFO) << "tuning TRX " << i << " to ARFCN " << ARFCN;
		ARFCNManager* radio = gTRX.ARFCN(i);
		radio->tune(ARFCN);
	}

	// Send either TSC or full BSIC depending on radio need
	if (gConfig.getBool("GSM.Radio.NeedBSIC")) {
		// Send BSIC to 
		C0radio->setBSIC(gBTS.BSIC());
	} else {
		// Set TSC same as BCC everywhere.
		C0radio->setTSC(gBTS.BCC());
	}

	// Set maximum expected delay spread.
	C0radio->setMaxDelay(gConfig.getNum("GSM.Radio.MaxExpectedDelaySpread"));

	// Set Receiver Gain
	C0radio->setRxGain(gConfig.getNum("GSM.Radio.RxGain"));

	// Turn on and power up.
	C0radio->powerOn(true);
	C0radio->setPower(gConfig.getNum("GSM.Radio.PowerManager.MinAttenDB"));

	//
	// Create a C-V channel set on C0T0.
	//

	// C-V on C0T0
	C0radio->setSlot(0,5);
	// SCH
	SCHL1FEC SCH;
	SCH.downstream(C0radio);
	SCH.open();
	// FCCH
	FCCHL1FEC FCCH;
	FCCH.downstream(C0radio);
	FCCH.open();
	// BCCH
	BCCHL1FEC BCCH;
	BCCH.downstream(C0radio);
	BCCH.open();
	// RACH
	RACHL1FEC RACH(gRACHC5Mapping);
	RACH.downstream(C0radio);
	RACH.open();
	// CCCHs
	CCCHLogicalChannel CCCH0(gCCCH_0Mapping);
	CCCH0.downstream(C0radio);
	CCCH0.open();
	CCCHLogicalChannel CCCH1(gCCCH_1Mapping);
	CCCH1.downstream(C0radio);
	CCCH1.open();
	CCCHLogicalChannel CCCH2(gCCCH_2Mapping);
	CCCH2.downstream(C0radio);
	CCCH2.open();
	// use CCCHs as AGCHs
	gBTS.addAGCH(&CCCH0);
	gBTS.addAGCH(&CCCH1);
	gBTS.addAGCH(&CCCH2);

	// C-V C0T0 SDCCHs
	// (pat) I thought config 'GSM.CCCH.CCCH-CONF' was supposed to control the number of SDCCH allocated?
	SDCCHLogicalChannel C0T0SDCCH[4] = {
		SDCCHLogicalChannel(0,0,gSDCCH_4_0),
		SDCCHLogicalChannel(0,0,gSDCCH_4_1),
		SDCCHLogicalChannel(0,0,gSDCCH_4_2),
		SDCCHLogicalChannel(0,0,gSDCCH_4_3),
	};
	Thread C0T0SDCCHControlThread[4];
	// Subchannel 2 used for CBCH if SMSCB enabled.
	bool SMSCB = (gConfig.getStr("Control.SMSCB.Table").length() != 0);
	CBCHLogicalChannel CBCH(gSDCCH_4_2);
	Thread CBCHControlThread;
	for (int i=0; i<4; i++) {
		if (SMSCB && (i==2)) continue;
		C0T0SDCCH[i].downstream(C0radio);
		C0T0SDCCHControlThread[i].start((void*(*)(void*))Control::DCCHDispatcher,&C0T0SDCCH[i]);
		C0T0SDCCH[i].open();
		gBTS.addSDCCH(&C0T0SDCCH[i]);
	}
	// Install CBCH if used.
	if (SMSCB) {
		LOG(INFO) << "creating CBCH for SMSCB";
		CBCH.downstream(C0radio);
		CBCH.open();
		gBTS.addCBCH(&CBCH);
		CBCHControlThread.start((void*(*)(void*))Control::SMSCBSender,NULL);
	}


	//
	// Configure the other slots.
	//

	// Count configured slots.
	unsigned sCount = 1;


	if (!gConfig.defines("GSM.Channels.NumC1s")) {
		int numChan = numARFCNs*7;
		LOG(CRIT) << "GSM.Channels.NumC1s not defined. Defaulting to " << numChan << ".";
		gConfig.set("GSM.Channels.NumC1s",numChan);
	}
	if (!gConfig.defines("GSM.Channels.NumC7s")) {
		int numChan = numARFCNs-1;
		LOG(CRIT) << "GSM.Channels.NumC7s not defined. Defaulting to " << numChan << ".";
		gConfig.set("GSM.Channels.NumC7s",numChan);
	}

	// sanity check on channel counts
	// the clamp here could be improved to take the customer's current ratio of C1:C7 and scale it back to fit in the window
	if (((numARFCNs * 8) - 1) < (gConfig.getNum("GSM.Channels.NumC1s") + gConfig.getNum("GSM.Channels.NumC7s"))) {
		LOG(CRIT) << "scaling back GSM.Channels.NumC1s and GSM.Channels.NumC7s to fit inside number of available timeslots";
		gConfig.set("GSM.Channels.NumC1s",numARFCNs*7);
		gConfig.set("GSM.Channels.NumC7s",numARFCNs-1);
	}

	if (gConfig.getBool("GSM.Channels.C1sFirst")) {
		// Create C-I slots.
		for (int i=0; i<gConfig.getNum("GSM.Channels.NumC1s"); i++) {
			gBTS.createCombinationI(gTRX,sCount/8,sCount%8);
			sCount++;
		}
	}

	// Create C-VII slots.
	for (int i=0; i<gConfig.getNum("GSM.Channels.NumC7s"); i++) {
		gBTS.createCombinationVII(gTRX,sCount/8,sCount%8);
		sCount++;
	}

	if (!gConfig.getBool("GSM.Channels.C1sFirst")) {
		// Create C-I slots.
		for (int i=0; i<gConfig.getNum("GSM.Channels.NumC1s"); i++) {
			gBTS.createCombinationI(gTRX,sCount/8,sCount%8);
			sCount++;
		}
	}

	if (sCount<(numARFCNs*8)) {
		LOG(CRIT) << "Only " << sCount << " timeslots configured in an " << numARFCNs << "-ARFCN system.";
	}

	// Set up idle filling on C0 as needed for unconfigured slots..
	while (sCount<8) {
		gBTS.createCombination0(gTRX,sCount);
		sCount++;
	}

	/* (pat) See GSM 05.02 6.5.2 and 3.3.2.3
		Note: The number of different paging subchannels on       
		the CCCH is:                                        
                                                           
		MAX(1,(3 - BS-AG-BLKS-RES)) * BS-PA-MFRMS           
			if CCCH-CONF = "001"                        
		(9 - BS-AG-BLKS-RES) * BS-PA-MFRMS                  
			for other values of CCCH-CONF               
	*/

	// Set up the pager.
	// Set up paging channels.
	// HACK -- For now, use a single paging channel, since paging groups are broken.
	gBTS.addPCH(&CCCH2);

	// Be sure we are not over-reserving.
	if (gConfig.getNum("GSM.Channels.SDCCHReserve")>=(int)gBTS.SDCCHTotal()) {
		unsigned val = gBTS.SDCCHTotal() - 1;
		LOG(CRIT) << "GSM.Channels.SDCCHReserve too big, changing to " << val;
		gConfig.set("GSM.Channels.SDCCHReserve",val);
	}


	// OK, now it is safe to start the BTS.
	gBTS.start();


	struct sockaddr_un cmdSockName;
	cmdSockName.sun_family = AF_UNIX;
	const char* sockpath = gConfig.getStr("CLI.SocketPath").c_str();
	char rmcmd[strlen(sockpath)+5];
	sprintf(rmcmd,"rm -f %s",sockpath);
	if (system(rmcmd)) {}	// The 'if' shuts up gcc warnings.
	strcpy(cmdSockName.sun_path,sockpath);
	LOG(INFO) "binding CLI datagram socket at " << sockpath;
	if (bind(sock, (struct sockaddr *) &cmdSockName, sizeof(struct sockaddr_un))) {
		perror("binding name to cmd datagram socket");
		LOG(ALERT) << "cannot bind socket for CLI at " << sockpath;
		gReports.incr("OpenBTS.Exit.CLI.Socket");
		exit(1);
	}
	COUT("\nsystem ready\n");
	if (chmod(sockpath, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) < 0)
	{
		perror("sockpath");
		// don't exit, at this point, we must run CLI as root
		COUT("\nuse the OpenBTSCLI utility to access CLI as root\n");
	} else
	{
		COUT("\nuse the OpenBTSCLI utility to access CLI\n");
	}
	LOG(INFO) << "system ready";

	gParser.startCommandLine();

	while (1) {
		char cmdbuf[1000];
		struct sockaddr_un source;
		socklen_t sourceSize = sizeof(source);
		int nread = recvfrom(sock,cmdbuf,sizeof(cmdbuf)-1,0,(struct sockaddr*)&source,&sourceSize);
		gReports.incr("OpenBTS.CLI.Command");
		cmdbuf[nread]='\0';
		LOG(INFO) << "received command \"" << cmdbuf << "\" from " << source.sun_path;
		std::ostringstream sout;
		int res = gParser.process(cmdbuf,sout);
		const std::string rspString= sout.str();
		const char* rsp = rspString.c_str();
		LOG(INFO) << "sending " << strlen(rsp) << "-char result to " << source.sun_path;
		if (sendto(sock,rsp,strlen(rsp)+1,0,(struct sockaddr*)&source,sourceSize)<0) {
			LOG(ERR) << "can't send CLI response to " << source.sun_path;
			gReports.incr("OpenBTS.CLI.Command.ResponseFailure");
		}
		// res<0 means to exit the application
		if (res<0) break;
	}

	} // try

	catch (ConfigurationTableKeyNotFound e) {
		LOG(EMERG) << "required configuration parameter " << e.key() << " not defined, aborting";
		gReports.incr("OpenBTS.Exit.Error.ConfigurationParamterNotFound");
	}
	LOG(ALERT) << "exiting OpenBTS as directed by command line...";


	//if (gTransceiverPid) kill(gTransceiverPid, SIGKILL);
	close(sock);

}
示例#18
0
/* Setup configuration values
 *     Don't query the existence of the Log.Level because it's a
 *     mandatory value. That is, if it doesn't exist, the configuration
 *     table will crash or will have already crashed. Everything else we
 *     can survive without and use default values if the database entries
 *     are empty.
 */
bool trx_setup_config(struct trx_config *config)
{
    std::string refstr, fillstr, divstr;

    if (!testConfig())
        return false;

    if (config->log_level == "")
        config->log_level = gConfig.getStr("Log.Level");

    if (!config->port) {
        if (gConfig.defines("TRX.Port"))
            config->port = gConfig.getNum("TRX.Port");
        else
            config->port = DEFAULT_TRX_PORT;
    }

    if (config->addr == "") {
        if (gConfig.defines("TRX.IP"))
            config->addr = gConfig.getStr("TRX.IP");
        else
            config->addr = DEFAULT_TRX_IP;
    }

    if (!config->extref) {
        if (gConfig.defines("TRX.Reference"))
            config->extref = gConfig.getNum("TRX.Reference");
        else
            config->extref = DEFAULT_EXTREF;
    }

    if (!config->diversity) {
        if (gConfig.defines("TRX.Diversity"))
            config->diversity = gConfig.getNum("TRX.Diversity");
        else
            config->diversity = DEFAULT_DIVERSITY;
    }

    /* Diversity only supported on 2 channels */
    if (config->diversity)
        config->chans = 2;

    refstr = config->extref ? "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_RAND:
        fillstr = "Normal busrts with random payload";
        break;
    }

    std::ostringstream ost("");
    ost << "Config Settings" << std::endl;
    ost << "   Log Level............... " << config->log_level << std::endl;
    ost << "   Device args............. " << config->dev_args << std::endl;
    ost << "   TRX Base Port........... " << config->port << std::endl;
    ost << "   TRX Address............. " << config->addr << std::endl;
    ost << "   Channels................ " << config->chans << std::endl;
    ost << "   Samples-per-Symbol...... " << config->sps << std::endl;
    ost << "   External Reference...... " << refstr << std::endl;
    ost << "   C0 Filler Table......... " << fillstr << std::endl;
    ost << "   Diversity............... " << divstr << std::endl;
    ost << "   Tuning offset........... " << config->offset << std::endl;
    ost << "   RSSI to dBm offset...... " << config->rssi_offset << std::endl;
    ost << "   Swap channels........... " << config->swap_channels << std::endl;
    std::cout << ost << std::endl;

    return true;
}