/* * Copyright 2008, 2010 Free Software Foundation, 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 "TRXManager.h" #include "GSMCommon.h" #include "GSMTransfer.h" #include "GSMLogicalChannel.h" #include "GSMConfig.h" #include "GSML1FEC.h" #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) { Timeval nextContact; while (1) { transceiver->clockHandler(); } return NULL; } void TransceiverManager::clockHandler() { char buffer[MAX_UDP_LENGTH]; int msgLen = mClockSocket.read(buffer,gConfig.getNum("TRX.Timeout.Clock",10)*1000); // Did the transceiver die?? if (msgLen<0) { LOG(ALERT) << "TRX clock interface timed out, assuming TRX is dead."; gReports.incr("OpenBTS.Exit.Error.TransceiverHeartbeat"); abort(); } if (msgLen==0) { LOG(ALERT) << "read error on TRX clock interface, return " << msgLen; return; } if (strncmp(buffer,"IND CLOCK",9)==0) { uint32_t FN; sscanf(buffer,"IND CLOCK %u", &FN); LOG(DEBUG) << "CLOCK indication, clock="<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; i>24) & 0x0ff; *wp++ = (FN>>16) & 0x0ff; *wp++ = (FN>>8) & 0x0ff; *wp++ = (FN) & 0x0ff; // power level /// FIXME -- We hard-code gain to 0 dB for now. *wp++ = 0; // copy data const char *dp = burst.begin(); for (unsigned i=0; idriveRx(); pthread_testcancel(); } return NULL; } int ::ARFCNManager::sendCommandPacket(const char* command, char* response) { int msgLen = 0; response[0] = '\0'; LOG(INFO) << "command " << command; mControlLock.lock(); for (int retry=0; retry<5; retry++) { mControlSocket.write(command); msgLen = mControlSocket.read(response,1000); if (msgLen>0) { response[msgLen] = '\0'; break; } LOG(WARNING) << "TRX link timeout on attempt " << retry+1; } 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; } 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[10]; int status; cmdNameTest[0]='\0'; if (!responseParam) sscanf(response,"RSP %10s %d", cmdNameTest, &status); else sscanf(response,"RSP %10s %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[10]; int status; cmdNameTest[0]='\0'; sscanf(response,"RSP %10s %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[10]; int status; cmdNameTest[0]='\0'; sscanf(response,"RSP %10s %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 failed with status " << status; return false; } // tune tx status = sendCommand("TXTUNE",txFreq); if (status!=0) { LOG(ALERT) << "TXTUNE failed with status " << status; return false; } // done mARFCN=wARFCN; return true; } bool ::ARFCNManager::tuneLoopback(int wARFCN) { // convert ARFCN number to a frequency unsigned txFreq = downlinkFreqKHz(gBTS.band(),wARFCN); // tune rx int status = sendCommand("RXTUNE",txFreq); if (status!=0) { LOG(ALERT) << "RXTUNE failed with status " << status; return false; } // tune tx status = sendCommand("TXTUNE",txFreq); if (status!=0) { LOG(ALERT) << "TXTUNE failed with status " << status; return false; } // done mARFCN=wARFCN; return true; } bool ::ARFCNManager::powerOff() { int status = sendCommand("POWEROFF"); if (status!=0) { LOG(ALERT) << "POWEROFF failed with status " << status; return false; } return true; } bool ::ARFCNManager::powerOn(bool warn) { int status = sendCommand("POWERON"); if (status!=0) { if (warn){ LOG(ALERT) << "POWERON failed with status " << status; } else { LOG(INFO) << "POWERON failed with status " << status; } return false; } return true; } bool ::ARFCNManager::setPower(int dB) { int status = sendCommand("SETPOWER",dB); if (status!=0) { LOG(ALERT) << "SETPOWER failed with status " << status; return false; } return true; } bool ::ARFCNManager::setTSC(unsigned TSC) { assert(TSC<8); int status = sendCommand("SETTSC",TSC); if (status!=0) { LOG(ALERT) << "SETTSC failed with status " << status; return false; } return true; } bool ::ARFCNManager::setBSIC(unsigned BSIC) { assert(BSIC < 64); int status = sendCommand("SETBSIC",BSIC); if (status!=0) { LOG(ALERT) << "SETBSIC failed with status " << status; return false; } return true; } bool ::ARFCNManager::setSlot(unsigned TN, unsigned combination) { assert(TN<8); assert(combination<8); char paramBuf[MAX_UDP_LENGTH]; sprintf(paramBuf,"%d %d", TN, combination); int status = sendCommand("SETSLOT",paramBuf); if (status!=0) { LOG(ALERT) << "SETSLOT failed with status " << status; return false; } return true; } bool ::ARFCNManager::setMaxDelay(unsigned km) { int status = sendCommand("SETMAXDLY",km); if (status!=0) { LOG(ALERT) << "SETMAXDLY failed with status " << status; return false; } return true; } signed ::ARFCNManager::setRxGain(signed rxGain) { signed newRxGain; int status = sendCommand("SETRXGAIN",rxGain,&newRxGain); if (status!=0) { LOG(ALERT) << "SETRXGAIN failed with status " << status; return false; } return newRxGain; } signed ::ARFCNManager::getNoiseLevel(void) { signed noiselevel; int status = sendCommand("NOISELEV",0,&noiselevel); if (status!=0) { LOG(ALERT) << "NOISELEV failed with status " << status; return false; } return noiselevel; } void ::ARFCNManager::receiveBurst(const RxBurst& inBurst) { LOG(DEBUG) << "receiveBurst: " << inBurst; uint32_t FN = inBurst.time().FN() % maxModulus; unsigned TN = inBurst.time().TN(); mTableLock.lock(); L1Decoder *proc = mDemuxTable[TN][FN]; if (proc==NULL) { LOG(DEBUG) << "ARFNManager::receiveBurst in unconfigured TDMA position TN: " << TN << " FN: " << FN << "."; mTableLock.unlock(); return; } proc->writeLowSide(inBurst); mTableLock.unlock(); } // vim: ts=4 sw=4