/*
* 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 "TRXManager.h"
#include "GSMCommon.h"
#include "GSMTransfer.h"
#include "GSMLogicalChannel.h"
#include "GSMConfig.h"
#include "GSML1FEC.h"
#include
#include
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)
{
while (1) {
transceiver->clockHandler();
pthread_testcancel();
}
return NULL;
}
void TransceiverManager::clockHandler()
{
char buffer[MAX_UDP_LENGTH];
int msgLen = mClockSocket.read(buffer,3000);
// Did the transceiver die??
if (msgLen<0) {
LOG(ALARM) << "TRX clock interface timed out, assuming TRX is dead.";
abort();
}
if (msgLen==0) {
LOG(ALARM) << "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="<TN();
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<10; retry++) {
mControlSocket.write(command);
msgLen = mControlSocket.read(response,3000);
if (msgLen>0) {
response[msgLen] = '\0';
break;
}
LOG(WARN) << "TRX link timeout on attempt " << retry+1;
}
mControlLock.unlock();
LOG(DEBUG) << "response " << response;
if ((msgLen>4) && (strncmp(response,"RSP ",4)==0)) {
return msgLen;
}
LOG(ALARM) << "lost control link to transceiver";
SOCKET_ERROR;
}
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(ALARM) << "RXTUNE failed with status " << status;
return false;
}
// tune tx
status = sendCommand("TXTUNE",txFreq);
if (status!=0) {
LOG(ALARM) << "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(ALARM) << "RXTUNE failed with status " << status;
return false;
}
// tune tx
status = sendCommand("TXTUNE",txFreq);
if (status!=0) {
LOG(ALARM) << "TXTUNE failed with status " << status;
return false;
}
// done
mARFCN=wARFCN;
return true;
}
bool ::ARFCNManager::powerOff()
{
int status = sendCommand("POWEROFF");
if (status!=0) {
LOG(ALARM) << "POWEROFF failed with status " << status;
return false;
}
return true;
}
bool ::ARFCNManager::powerOn()
{
int status = sendCommand("POWERON");
if (status!=0) {
LOG(ALARM) << "POWERON failed with status " << status;
return false;
}
return true;
}
bool ::ARFCNManager::setPower(int dB)
{
int status = sendCommand("SETPOWER",dB);
if (status!=0) {
LOG(ALARM) << "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(ALARM) << "SETTSC 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(ALARM) << "SETSLOT failed with status " << status;
return false;
}
return true;
}
bool ::ARFCNManager::setMaxDelay(unsigned km)
{
int status = sendCommand("SETMAXDLY",km);
if (status!=0) {
LOG(ALARM) << "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(ALARM) << "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(ALARM) << "NOISELEV failed with status " << status;
return false;
}
return noiselevel;
}
void ::ARFCNManager::receiveBurst(const RxBurst& inBurst)
{
LOG(DEEPDEBUG) << "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