/* * Copyright 2008, 2010 Free Software Foundation, Inc. * Copyright 2012, 2014 Range Networks, Inc. * * This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribution. * * This use of this software may be subject to additional restrictions. * See the LEGAL file in the main directory for details. 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. */ #include #include "TRXManager.h" #include #include #include #include #include #include #include #include #include #include #undef WARNING using namespace GSM; using namespace std; TransceiverManager::TransceiverManager(int numARFCNs, const char* wTRXAddress, int wBasePort) :mHaveClock(false), mClockSocket(wBasePort+100) { // set up the ARFCN managers for (int i=0; istart(); } } void* ClockLoopAdapter(TransceiverManager *transceiver) { // This loop checks the clock messages from the transceiver. // These messages keep the BTS clock in sync with the hardware, // and also serve as a heartbeat for the radiomodem. // This is a convenient place for other periodic housekeeping as well. // This loop has a period of about 3 seconds. gResetWatchdog(); while (! gBTS.btsShutdown()) { transceiver->clockHandler(); LOG(DEBUG) << "watchdog timer expires in " << gWatchdogRemaining() << " seconds"; if (gWatchdogExpired()) { LOG(ALERT) << "restarting OpenBTS on expiration of watchdog timer"; gReports.incr("OpenBTS.Exit.Error.Watchdog"); exit(-2); } } return NULL; } void TransceiverManager::clockHandler() { char buffer[MAX_UDP_LENGTH]; int msgLen; try { msgLen = mClockSocket.read(buffer,gConfig.getNum("TRX.Timeout.Clock")*1000); } catch (SocketError) { LOG(ERR) <<"Transceiver Clock Interface read error:"<ARFCN(); } ::ARFCNManager::ARFCNManager(const char* wTRXAddress, int wBasePort, TransceiverManager &wTransceiver) :mTransceiver(wTransceiver), mDataSocket(wBasePort+100+1,wTRXAddress,wBasePort+1), mControlSocket(wBasePort+100,wTRXAddress,wBasePort) { // The default demux table is full of NULL pointers. for (int i=0; i<8; i++) { for (unsigned j=0; jTN(); const TDMAMapping& mapping = wL1d->mapping(); // Is this mapping a valid uplink on this slot? assert(mapping.uplink()); assert(mapping.allowedSlot(TN)); LOG(DEBUG) << "ARFCNManager::installDecoder TN: " << TN << " repeatLength: " << mapping.repeatLength(); mTableLock.lock(); for (unsigned i=0; i0) { response[msgLen] = '\0'; break; } LOG(WARNING) << "TRX link timeout on attempt " << retry+1; // Dont wait so long. if (gConfig.defines("DeveloperMode") && 0 == strcmp(command,"CMD POWERON")) { printf("Developer mode, curtailing transceiver poweron test\n"); fflush(stdout); return 0; } } mControlLock.unlock(); LOG(INFO) << "response " << response; if ((msgLen>4) && (strncmp(response,"RSP ",4)==0)) { return msgLen; } LOG(NOTICE) << "lost control link to transceiver"; return 0; } // TODO : lots of duplicate code in these sendCommand()s int ::ARFCNManager::sendCommand(const char*command, const char*param, int *responseParam) { // Send command and get response. char cmdBuf[MAX_UDP_LENGTH]; char response[MAX_UDP_LENGTH]; sprintf(cmdBuf,"CMD %s %s", command, param); int rspLen = sendCommandPacket(cmdBuf,response); if (rspLen<=0) return -1; // Parse and check status. char cmdNameTest[15]; int status; cmdNameTest[0]='\0'; if (!responseParam) sscanf(response,"RSP %15s %d", cmdNameTest, &status); else sscanf(response,"RSP %15s %d %d", cmdNameTest, &status, responseParam); if (strcmp(cmdNameTest,command)!=0) return -1; return status; } int ::ARFCNManager::sendCommand(const char*command, int param, int *responseParam) { // Send command and get response. char cmdBuf[MAX_UDP_LENGTH]; char response[MAX_UDP_LENGTH]; sprintf(cmdBuf,"CMD %s %d", command, param); int rspLen = sendCommandPacket(cmdBuf,response); if (rspLen<=0) return -1; // Parse and check status. char cmdNameTest[15]; int status; cmdNameTest[0]='\0'; if (!responseParam) sscanf(response,"RSP %15s %d", cmdNameTest, &status); else sscanf(response,"RSP %15s %d %d", cmdNameTest, &status, responseParam); if (strcmp(cmdNameTest,command)!=0) return -1; return status; } int ::ARFCNManager::sendCommand(const char*command, const char* param) { // Send command and get response. char cmdBuf[MAX_UDP_LENGTH]; char response[MAX_UDP_LENGTH]; sprintf(cmdBuf,"CMD %s %s", command, param); int rspLen = sendCommandPacket(cmdBuf,response); if (rspLen<=0) return -1; // Parse and check status. char cmdNameTest[15]; int status; cmdNameTest[0]='\0'; sscanf(response,"RSP %15s %d", cmdNameTest, &status); if (strcmp(cmdNameTest,command)!=0) return -1; return status; } int ::ARFCNManager::sendCommand(const char*command) { // Send command and get response. char cmdBuf[MAX_UDP_LENGTH]; char response[MAX_UDP_LENGTH]; sprintf(cmdBuf,"CMD %s", command); int rspLen = sendCommandPacket(cmdBuf,response); if (rspLen<=0) return -1; // Parse and check status. char cmdNameTest[15]; int status; cmdNameTest[0]='\0'; sscanf(response,"RSP %15s %d", cmdNameTest, &status); if (strcmp(cmdNameTest,command)!=0) return -1; return status; } bool ::ARFCNManager::tune(int wARFCN) { // convert ARFCN number to a frequency unsigned rxFreq = uplinkFreqKHz(gBTS.band(),wARFCN); unsigned txFreq = downlinkFreqKHz(gBTS.band(),wARFCN); // tune rx int status = sendCommand("RXTUNE",rxFreq); if (status!=0) { LOG(ALERT) << "RXTUNE("<writeLowSideRx(inBurst); } // vim: ts=4 sw=4