laforge
/
openbts-osmo
Archived
1
0
Fork 0
This repository has been archived on 2022-03-30. You can view files and clone it, but cannot push or open issues or pull requests.
openbts-osmo/public-trunk/TRXManager/TRXManager.cpp

499 lines
11 KiB
C++

/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "TRXManager.h"
#include "GSMCommon.h"
#include "GSMTransfer.h"
#include "GSMLogicalChannel.h"
#include "GSMConfig.h"
#include "GSML1FEC.h"
#include <string.h>
#include <stdexcept>
#include <Logger.h>
using namespace GSM;
using namespace std;
// From OpenBTS.cpp
extern void shutdownOpenbts();
TransceiverManager::TransceiverManager(int numARFCNs,
const char* wTRXAddress, int wBasePort)
:mHaveClock(false),
mClockSocket(wBasePort+100)
{
// set up the ARFCN managers
for (int i=0; i<numARFCNs; i++) {
int thisBasePort = wBasePort + 1 + 2*i;
mARFCNs.push_back(new ::ARFCNManager(wTRXAddress,thisBasePort,*this));
}
}
void TransceiverManager::start()
{
mClockThread.start((void*(*)(void*))ClockLoopAdapter,this);
for (unsigned i=0; i<mARFCNs.size(); i++) {
mARFCNs[i]->start();
}
}
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.";
shutdownOpenbts();
return;
}
if (msgLen==0) {
LOG(ALARM) << "read error on TRX clock interface, return " << msgLen;
shutdownOpenbts();
return;
}
if (strncmp(buffer,"IND CLOCK",9)==0) {
uint32_t FN;
sscanf(buffer,"IND CLOCK %u", &FN);
LOG(DEBUG) << "CLOCK indication, clock="<<FN;
gBTS.clock().set(FN);
mHaveClock = true;
return;
}
buffer[msgLen]='\0';
LOG(ALARM) << "bogus message " << buffer << " on clock interface";
}
::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; j<maxModulus; j++) {
mDemuxTable[i][j] = NULL;
}
}
}
void ::ARFCNManager::start()
{
mRxThread.start((void*(*)(void*))ReceiveLoopAdapter,this);
}
void ::ARFCNManager::installDecoder(GSM::L1Decoder *wL1d)
{
unsigned TN = wL1d->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<mapping.numFrames(); i++) {
unsigned FN = mapping.frameMapping(i);
while (FN<maxModulus) {
// Don't overwrite existing entries.
assert(mDemuxTable[TN][FN]==NULL);
mDemuxTable[TN][FN] = wL1d;
FN += mapping.repeatLength();
}
}
mTableLock.unlock();
}
void ::ARFCNManager::writeHighSide(const GSM::TxBurst& burst)
{
LOG(DEEPDEBUG) << "transmit at time " << gBTS.clock().get() << ": " << burst;
// format the transmission request message
static const int bufferSize = gSlotLen+1+4+1;
char buffer[bufferSize];
unsigned char *wp = (unsigned char*)buffer;
// slot
*wp++ = burst.time().TN();
// frame number
uint32_t FN = burst.time().FN();
*wp++ = (FN>>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; i<gSlotLen; i++) {
*wp++ = (unsigned char)((*dp++) & 0x01);
}
// write to the socket
mDataSocketLock.lock();
mDataSocket.write(buffer,bufferSize);
mDataSocketLock.unlock();
}
void ::ARFCNManager::driveRx()
{
// read the message
char buffer[MAX_UDP_LENGTH];
int msgLen = mDataSocket.read(buffer);
if (msgLen<=0) SOCKET_ERROR;
// decode
unsigned char *rp = (unsigned char*)buffer;
// timeslot number
unsigned TN = *rp++;
// frame number
int32_t FN = *rp++;
FN = (FN<<8) + (*rp++);
FN = (FN<<8) + (*rp++);
FN = (FN<<8) + (*rp++);
// physcial header data
signed char* srp = (signed char*)rp++;
// reported RSSI is negated dB wrt full scale
int RSSI = *srp;
srp = (signed char*)rp++;
// timing error comes in 1/256 symbol steps
// because that fits nicely in 2 bytes
int timingError = *srp;
timingError = (timingError<<8) | (*rp++);
// soft symbols
float data[gSlotLen];
for (unsigned i=0; i<gSlotLen; i++) data[i] = (*rp++) / 256.0F;
// demux
receiveBurst(RxBurst(data,GSM::Time(FN,TN),timingError/256.0F,-RSSI));
}
void* ReceiveLoopAdapter(::ARFCNManager* manager){
while (true) {
manager->driveRx();
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