/* * Copyright 2008, 2009, 2010 Free Software Foundation, Inc. * Copyright 2010 Kestrel Signal Processing, Inc. * Copyright 2011 Range Networks, Inc. * * This software is distributed under the terms of the GNU Affero Public License. * See the COPYING file in the main directory for details. * * This use of this software may be subject to additional restrictions. * See the LEGAL file in the main directory for details. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #include #include #include // Load configuration from a file. ConfigurationTable gConfig("/etc/OpenBTS/OpenBTS.db"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace GSM; const char* gDateTime = __DATE__ " " __TIME__; // All of the other globals that rely on the global configuration file need to // be declared here. // The TMSI Table. Control::TMSITable gTMSITable; // 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.getNum("GSM.Radio.ARFCNs"), gConfig.getStr("TRX.IP").c_str(), gConfig.getNum("TRX.Port")); // Subscriber registry SubscriberRegistry gSubscriberRegistry; /** 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(); } const char* transceiverPath = "./transceiver"; pid_t gTransceiverPid = 0; void startTransceiver() { // 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",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[]) { int sock = socket(AF_UNIX,SOCK_DGRAM,0); if (sock<0) { perror("opening cmd datagram socket"); exit(1); } 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(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; itune(ARFCN); } // 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,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