void gLogInit(const char* defaultLevel) { // Define defaults in the global config if (!gConfig.defines("Log.Level")) { gConfig.set("Log.Level",defaultLevel); LOG(FORCE) << "Setting initial global logging level to " << defaultLevel; } if (!gConfig.defines("Log.Alarms.TargetPort")) { gConfig.set("Log.Alarms.TargetPort",DEFAULT_ALARM_PORT); } if (!gConfig.defines("Log.Alarms.Max")) { gConfig.set("Log.Alarms.Max",DEFAULT_MAX_ALARMS); } }
void gLogInit(const char* name, const char* level, int facility) { // Set the level if one has been specified. if (level) { gConfig.set("Log.Level",level); } gPid = getpid(); // 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: string str = gConfig.getStr("Log.File"); if (gLogToFile==0 && str.length() && 0==strncmp(gCmdName,"Open",4)) { const char *fn = str.c_str(); 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. if (gLogToFile) { time_t now = time(NULL); std::string result; Timeval::isoTime(now, result); fprintf(gLogToFile,"Starting at %s",result.c_str()); fflush(gLogToFile); std::cout << name <<" logging to file: " << fn << "\n"; } } } // Open the log connection. openlog(name,0,facility); // We cant call this from the Mutex itself because the Logger uses Mutex. gMutexLogLevel = gGetLoggingLevel("Mutex.cpp"); }
/* Run sanity check on configuration table * The global table constructor cannot provide notification in the * event of failure. Make sure that we can access the database, * write to it, and that it contains the bare minimum required keys. */ bool testConfig() { int val = 9999; std::string test = "asldfkjsaldkf"; const char *key = "Log.Level"; /* Attempt to query */ try { gConfig.getStr(key); } catch (...) { std::cerr << std::endl; std::cerr << "Config: Failed query required key " << key << std::endl; return false; } /* Attempt to set a test value in the global config */ if (!gConfig.set(test, val)) { std::cerr << std::endl; std::cerr << "Config: Failed to set test key" << std::endl; return false; } else { gConfig.remove(test); } return true; }
// Allow applications to also pass in a filename. Filename should come from the database void gLogInitWithFile(const char* name, const char* level, int facility, char * LogFilePath) { // Set the level if one has been specified. if (level) { gConfig.set("Log.Level",level); } if (gLogToFile==0 && LogFilePath != 0 && *LogFilePath != 0 && strlen(LogFilePath) > 0) { gLogToFile = fopen(LogFilePath,"w"); // New log file each time we start. if (gLogToFile) { time_t now = time(NULL); std::string result; Timeval::isoTime(now, result); fprintf(gLogToFile,"Starting at %s",result.c_str()); fflush(gLogToFile); std::cout << name <<" logging to file: " << LogFilePath << "\n"; } } // Open the log connection. openlog(name,0,facility); // We cant call this from the Mutex itself because the Logger uses Mutex. gMutexLogLevel = gGetLoggingLevel("Mutex.cpp"); }
/** Given a string, return the corresponding level name. */ static int lookupLevel2(const string& key, const string &keyVal) { int level = levelStringToInt(keyVal); if (level == -1) { string defaultLevel = gConfig.mSchema["Log.Level"].getDefaultValue(); level = levelStringToInt(defaultLevel); _LOG(CRIT) << "undefined logging level (" << key << " = \"" << keyVal << "\") defaulting to \"" << defaultLevel << ".\" Valid levels are: EMERG, ALERT, CRIT, ERR, WARNING, NOTICE, INFO or DEBUG"; gConfig.set(key, defaultLevel); } return level; }
int main(int argc, char *argv[]) { SubscriberRegistry gHLR; gLogInit("HLRTest"); gConfig.set("Log.Level","DEBUG"); if (argc!=2) { std::cerr << "usage: " << argv[0] << " <number>" << std::endl; exit(-1); } const char *targ = argv[1]; char *IMSI = gHLR.getIMSI(targ); if (IMSI) std::cout << "IMSI for " << targ << " is " << IMSI << std::endl; else std::cout << "no IMSI found for " << targ << std::endl; char *CLID = gHLR.getCLIDLocal(IMSI); if (CLID) std::cout << "CLID for " << IMSI << " is " << CLID << std::endl; else std::cout << "no CLID found for " << IMSI << std::endl; char *regIP = gHLR.getRegistrationIP("234100223456161"); if (regIP) std::cout << "registration IP for " << IMSI << " is " << regIP << std::endl; else std::cout << "no regIP found for " << IMSI << std::endl; IMSI = gHLR.getIMSI(targ); if (IMSI) std::cout << "IMSI for " << targ << " is " << IMSI << std::endl; else std::cout << "no IMSI found for " << targ << std::endl; CLID = gHLR.getCLIDLocal(IMSI); if (CLID) std::cout << "CLID for " << IMSI << " is " << CLID << std::endl; else std::cout << "no CLID found for " << IMSI << std::endl; const char targ2[] = "1234567890"; gHLR.addUser("123456789012345",targ2); sleep(2); IMSI = gHLR.getIMSI(targ2); if (IMSI) std::cout << "IMSI for " << targ2 << " is " << IMSI << std::endl; else std::cout << "no IMSI found for " << targ2 << std::endl; CLID = gHLR.getCLIDLocal(IMSI); if (CLID) std::cout << "CLID for " << IMSI << " is " << CLID << std::endl; else std::cout << "no CLID found for " << IMSI << std::endl; }
void doVisibles() { gVisibleSipColumns = ""; map<string,string>::iterator it; bool first = true; for (it = gArgs.begin(); it != gArgs.end(); it++) { if (it->first == "what") continue; if (first) { first = false; } else { gVisibleSipColumns += " "; } gVisibleSipColumns += it->first; } if (!gConfig.set("SubscriberRegistry.Manager.VisibleColumns", gVisibleSipColumns)) { LOG(ERR) << "unable to update SubscriberRegistry.Manager.VisibleColumns"; } }
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); }
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); }
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; } }