/* * OpenBTS provides an open source alternative to legacy telco protocols and * traditionally complex, proprietary hardware systems. * * Copyright 2008, 2010 Free Software Foundation, Inc. * Copyright 2012, 2014 Range Networks, Inc. * * This software is distributed under the terms of the GNU Affero General * Public License version 3. See the COPYING and NOTICE files in the main * directory for licensing information. * * This use of this software may be subject to additional restrictions. * See the LEGAL file in the main directory for details. */ #include #include "TRXManager.h" #include "UMTSCommon.h" #include "UMTSTransfer.h" #include "UMTSLogicalChannel.h" #include "UMTSConfig.h" #include "UMTSL1FEC.h" #include #include #include #undef WARNING using namespace UMTS; using namespace std; int ::ARFCNManager::sendCommandPacket(const char* command, char* response) { int msgLen = 0; char cmdNameTest[15]; int status; int timeout = 6000; response[0] = '\0'; LOG(INFO) << "command " << command; mControlLock.lock(); mControlSocket.write(command); /* Check for RSP response */ msgLen = mControlSocket.read(response, timeout); if (msgLen == 0) { LOG(NOTICE) << "No RSP : lost control link to transceiver"; mControlLock.unlock(); return 0; } else { /* Check that it was a RSP message */ response[msgLen] = '\0'; /* Terminate message */ if ((msgLen>4) && (strncmp(response,"RSP ",4) == 0)) { mControlLock.unlock(); return msgLen; } else { LOG(NOTICE) << "Bad RSP : lost control link to transceiver"; LOG(ALERT) << "RSP response " << response; mControlLock.unlock(); return 0; } } /* Default */ mControlLock.unlock(); return 0; } bool ::ARFCNManager::powerOff() { int status = sendCommand("POWEROFF"); if (status!=0) { LOG(ALERT) << "POWEROFF 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::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::readTxPwr(void) { signed txPwr; int status = sendCommand("READTXPWR", 0, &txPwr); if (status!=0) { LOG(ALERT) << "READTXPWR failed with status " << status; return false; } return txPwr; } signed ::ARFCNManager::readRxPwrCoarse(void) { signed rxPwr; int status = sendCommand("READRXPWRCOARSE", 0, &rxPwr); if (status!=0) { LOG(ALERT) << "READRXPWRCOARSE failed with status " << status; return false; } return rxPwr; } long long ::ARFCNManager::readRxPwrFine() { long long rxPwr; int status = sendCommand("READRXPWRFINE", &rxPwr); if (status!=0) { LOG(ALERT) << "READRXPWRFINE failed with status " << status; return false; } return rxPwr; } signed ::ARFCNManager::setFreqOffset(signed offset) { signed newFreqOffset; int status = sendCommand("SETFREQOFFSET",offset,&newFreqOffset); if (status!=0) { LOG(ALERT) << "SETFREQOFFSET failed with status " << status; return false; } return newFreqOffset; } signed ::ARFCNManager::getTemperature(void) { signed temperature; int status = sendCommand("TEMPERATURE", 0, &temperature); if (status!=0) { LOG(ALERT) << "TEMPERATURE failed with status " << status; return false; } return temperature; } 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; } bool ::ARFCNManager::radioPowerOff() { int status = sendCommand("RADIOPOWEROFF"); if (status!=0) { LOG(ALERT) << "RADIOPOWEROFF failed with status " << status; return false; } return true; } bool ::ARFCNManager::radioPowerOn(bool warn) { int status = sendCommand("RADIOPOWERON"); if (status!=0) { if (warn) { LOG(ALERT) << "RADIOPOWERON failed with status " << status; } else { LOG(INFO) << "RADIOPOWERON failed with status " << status; } return false; } return true; } // (pat) There is a constructor race that culminates in UMTSRadioModem() failing // because the BitVectors in gRACHSignatures are not initialized. // The easiest fix is to do the TransceiverManager initialization in a function here // instead of in its constructor. void TransceiverManager::TransceiverManagerInit(int numARFCNs, const char* wTRXAddress, int wBasePort) { //mHaveClock = false; mClockSocket.open(wBasePort+100); // set up the ARFCN managers for (int i=0; iarfcnManagerStart(); } } void* ClockLoopAdapter(TransceiverManager *transceiver) { Timeval nextContact; while (1) { transceiver->clockHandler(); /*if (nextContact.passed()) { // FIXME -- Phone Home Here if (gConfig.defines("NTP.Server")) { string ntp = string("ntpdate ") + gConfig.getStr("NTP.Server"); system(ntp.c_str()); } nextContact.addMinutes(random() % (24*60)); }*/ } return NULL; } void TransceiverManager::clockHandler() { char buffer[MAX_UDP_LENGTH]; int msgLen = mClockSocket.read(buffer,3000); // Did the transceiver die?? if (msgLen<0) { LOG(ALERT) << "TRX clock interface timed out, assuming TRX is dead."; // FIXME: Pat removed abort to debug this thing. //abort(); return; } 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(INFO) << "CLOCK indication, clock="<transmitLoop(); // do not reach return NULL; // pacify the compiler } void* ReceiveLoopAdapter(::ARFCNManager* manager) { manager->receiveLoop(); // do not reach return NULL; // pacify the compiler } 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, long long *responseParam) { // 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'; if (!responseParam) sscanf(response,"RSP %15s %d", cmdNameTest, &status); else sscanf(response,"RSP %15s %d %llx", cmdNameTest, &status, responseParam); if (strcmp(cmdNameTest,command)!=0) { printf("TRXManager:sendCommand Failed because RSP cmdNameTest:%s != command:%s.\n\r", cmdNameTest, command); 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(unsigned wUARFCN) { // convert ARFCN number to a frequency unsigned txFreq = channelFreqKHz(gNodeB.band(),wUARFCN); unsigned rxFreq = txFreq-uplinkOffsetKHz(gNodeB.band()); // tune tx int status = sendCommand("TXTUNE",txFreq); if (status!=0) { LOG(ALERT) << "TXTUNE failed with status " << status; return false; } // tune rx status = sendCommand("RXTUNE",rxFreq); if (status!=0) { LOG(ALERT) << "RXTUNE failed with status " << status; return false; } // done mUARFCN=wUARFCN; return true; } bool ::ARFCNManager::tuneLoopback(int wARFCN) { // convert ARFCN number to a frequency unsigned txFreq = channelFreqKHz(gNodeB.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 mUARFCN=wARFCN; return true; } void ::ARFCNManager::writeHighSide(TxBitsBurst* txBurst) { // mTransmitLock.lock(); bool underrun; Time updateTime; mRadioModem.addBurst(txBurst,underrun,updateTime); if (underrun) { //LOG(NOTICE) << "tx underrun: " << *txBurst << " at time " << txBurst->time(); // XXX RPERRY LOG(NOTICE) << "tx underrun: "<