Compare commits

...

20 Commits

Author SHA1 Message Date
Alexander Chemeris
f8f000cca1 fixup 2016-03-26 14:43:37 +03:00
Alexander Chemeris
f1c1379e97 fixup 2016-03-26 10:57:41 +03:00
Alexander Chemeris
bb7b057ec3 transceiver: Send packets to a different port in case of external demodulation.
We want to have external demodulation which is transparent for the osmo-trx user,
so osmo-trx will send data to the external demodulator and it will send data to
the osmo-trx user.
2015-11-13 11:10:04 -08:00
Alexander Chemeris
9155d8da94 transceiver: Add an option to stream raw samples instead of demodulated softbits. 2015-11-13 11:00:21 -08:00
Alexander Chemeris
8b8e7ecf8a fixup 2015-11-13 10:08:36 -08:00
Alexander Chemeris
e587cdb213 fixup 2015-11-13 10:02:46 -08:00
Alexander Chemeris
5d1eaaffcc transceiver: Remove remainings of the equalizer, restructure driveReceiveFIFO() for better modularity.
Equalizer has never worked properly and was always disabled. Now is a good time
to remove it completely to make the code cleaner.
2015-11-13 09:38:56 -08:00
Alexander Chemeris
511a662394 Common: Make sure gLogEarly() log to the same facilities as the normal log. 2015-09-10 19:57:03 -04:00
Alexander Chemeris
7d2866164b Common: Get rid of a compilation warning.
debugLogEarly was replaced to an empty space and arguments of the function
became operators, grouped together by ():
Configuration.cpp: In member function 'bool ConfigurationTable::defines(const string&)':
Configuration.cpp:272:28: warning: left operand of comma operator has no effect [-Wunused-value]
   debugLogEarly(LOG_ALERT, "configuration parameter %s not found", key.c_str());
                            ^

This fix removes debugLogEarly together with its arguments.
2015-09-10 19:57:03 -04:00
Kirill Zakharenko
a0f8ed8ecb Bumped version to 0.1.9~1 2015-09-10 19:57:03 -04:00
Kirill Zakharenko
c579c071f4 debian: correct dependency on libuhd, throw away dependency on umtrx-uhd 2015-09-10 19:57:03 -04:00
Kirill Zakharenko
2337e8f8aa debian: compile for atom arch with SSE3 optimizations 2015-09-10 19:57:03 -04:00
Kirill Zakharenko
afa28be3ef transceiver/x86: don’t use -march=native to build x86 specialized code
when this option is used, it is impossible to cross-compile for x86
 variants like atom.
2015-09-10 19:57:03 -04:00
Kirill Zakharenko
cab15655f3 debian: whitespace changes, more correct hardening stanza 2015-09-10 19:57:03 -04:00
Kirill Zakharenko
f8e8e57568 bumped version to 0.1.9 2015-09-10 19:57:03 -04:00
Kirill Zakharenko
441dd35a6f build with instruction set/tuning for atom processors
fix non-working hardening
2015-09-10 19:57:03 -04:00
Ivan Kluchnikov
bf7ed547ac debian: make it possible to install osmo-trx dependencies manually on the system 2015-09-10 19:57:03 -04:00
Ivan Kluchnikov
ab31d70678 debian: update osmo-trx dependencies
Now we use uhd and umtrx-uhd instead of libuhd-dev.
2015-09-10 19:57:03 -04:00
Ivan Kluchnikov
341869feb1 debian: Add debug package for the osmo-trx 2015-09-10 19:57:03 -04:00
Ivan Kluchnikov
31862c5e4c debian: Add debian directory to ease building packages 2015-09-10 19:57:03 -04:00
15 changed files with 333 additions and 489 deletions

View File

@@ -35,7 +35,7 @@
#ifdef DEBUG_CONFIG
#define debugLogEarly gLogEarly
#else
#define debugLogEarly
#define debugLogEarly(x,y,z)
#endif

View File

@@ -38,6 +38,14 @@
using namespace std;
// Switches to enable/disable logging targets
// MUST BE DEFINED BEFORE gConfig FOR gLogEarly() TO WORK CORRECTLY
bool gLogToConsole = true;
bool gLogToSyslog = false;
FILE *gLogToFile = NULL;
Mutex gLogToLock;
// Reference to a global config table, used all over the system.
extern ConfigurationTable gConfig;
@@ -67,10 +75,6 @@ const char *levelNames[] = {
"EMERG", "ALERT", "CRIT", "ERR", "WARNING", "NOTICE", "INFO", "DEBUG"
};
int numLevels = 8;
bool gLogToConsole = true;
bool gLogToSyslog = false;
FILE *gLogToFile = NULL;
Mutex gLogToLock;
int levelStringToInt(const string& name)
@@ -269,9 +273,32 @@ void gLogInit(const char* name, const char* level, int facility)
void gLogEarly(int level, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vsyslog(level | LOG_USER, fmt, args);
if (gLogToSyslog) {
va_list args_copy;
va_copy(args_copy, args);
vsyslog(level | LOG_USER, fmt, args_copy);
va_end(args_copy);
}
if (gLogToConsole) {
va_list args_copy;
va_copy(args_copy, args);
vprintf(fmt, args_copy);
printf("\n");
va_end(args_copy);
}
if (gLogToFile) {
va_list args_copy;
va_copy(args_copy, args);
vfprintf(gLogToFile, fmt, args_copy);
fprintf(gLogToFile, "\n");
va_end(args_copy);
}
va_end(args);
}

View File

@@ -50,9 +50,6 @@ TransceiverState::TransceiverState()
for (int i = 0; i < 8; i++) {
chanType[i] = Transceiver::NONE;
fillerModulus[i] = 26;
chanResponse[i] = NULL;
DFEForward[i] = NULL;
DFEFeedback[i] = NULL;
for (int n = 0; n < 102; n++)
fillerTable[n][i] = NULL;
@@ -62,10 +59,6 @@ TransceiverState::TransceiverState()
TransceiverState::~TransceiverState()
{
for (int i = 0; i < 8; i++) {
delete chanResponse[i];
delete DFEForward[i];
delete DFEFeedback[i];
for (int n = 0; n < 102; n++)
delete fillerTable[n][i];
}
@@ -141,16 +134,24 @@ bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc)
return false;
}
void Transceiver::reset()
{
for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
mTxPriorityQueues[i].clear();
}
Transceiver::Transceiver(int wBasePort,
const char *wTRXAddress,
size_t wSPS, size_t wChans,
GSM::Time wTransmitLatency,
RadioInterface *wRadioInterface,
double wRssiOffset)
double wRssiOffset,
bool wExternalDemod)
: mBasePort(wBasePort), mAddr(wTRXAddress),
mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
rssiOffset(wRssiOffset),
mExternalDemod(wExternalDemod),
mSPSTx(wSPS), mSPSRx(1), mChans(wChans), mOn(false),
mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelay(0), mWriteBurstToDiskMask(0)
{
@@ -222,7 +223,7 @@ bool Transceiver::init(int filler, size_t rtsc)
c_srcport = mBasePort + 2 * i + 1;
c_dstport = mBasePort + 2 * i + 101;
d_srcport = mBasePort + 2 * i + 2;
d_dstport = mBasePort + 2 * i + 102;
d_dstport = mBasePort + 2 * i + (mExternalDemod?202:102);
mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
@@ -556,11 +557,9 @@ Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
}
/*
* Detect RACH synchronization sequence within a burst. No equalization
* is used or available on the RACH channel.
* Detect RACH synchronization sequence within a burst.
*/
int Transceiver::detectRACH(TransceiverState *state,
signalVector &burst,
int Transceiver::detectRACH(signalVector &burst,
complex &amp, float &toa)
{
float threshold = 6.0;
@@ -569,76 +568,16 @@ int Transceiver::detectRACH(TransceiverState *state,
}
/*
* Detect normal burst training sequence midamble. Update equalization
* state information and channel estimate if necessary. Equalization
* is currently disabled.
* Detect normal burst training sequence midamble.
*/
int Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
complex &amp, float &toa, GSM::Time &time)
int Transceiver::detectTSC(signalVector &burst,
complex &amp, float &toa)
{
int success;
int tn = time.TN();
float chanOffset, threshold = 5.0;
bool needDFE = false, estimateChan = false;
double elapsed = time - state->chanEstimateTime[tn];
signalVector *chanResp;
/* Check equalization update state */
if (needDFE && ((elapsed > 50) || (!state->chanResponse[tn]))) {
delete state->DFEForward[tn];
delete state->DFEFeedback[tn];
state->DFEForward[tn] = NULL;
state->DFEFeedback[tn] = NULL;
estimateChan = true;
}
float threshold = 5.0;
/* Detect normal burst midambles */
success = analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, amp,
toa, mMaxExpectedDelay, estimateChan,
&chanResp, &chanOffset);
if (success <= 0) {
return success;
}
/* Set equalizer if unabled */
if (needDFE && estimateChan) {
float noise = state->mNoiseLev;
state->SNRestimate[tn] = amp.norm2() / (noise * noise + 1.0);
state->chanResponse[tn] = chanResp;
state->chanRespOffset[tn] = chanOffset;
state->chanRespAmplitude[tn] = amp;
scaleVector(*chanResp, complex(1.0, 0.0) / amp);
designDFE(*chanResp, state->SNRestimate[tn],
7, &state->DFEForward[tn], &state->DFEFeedback[tn]);
state->chanEstimateTime[tn] = time;
}
return 1;
}
/*
* Demodulate GMSK burst using equalization if requested. Otherwise
* demodulate by direct rotation and soft slicing.
*/
SoftVector *Transceiver::demodulate(TransceiverState *state,
signalVector &burst, complex amp,
float toa, size_t tn, bool equalize)
{
if (equalize) {
scaleVector(burst, complex(1.0, 0.0) / amp);
return equalizeBurst(burst,
toa - state->chanRespOffset[tn],
mSPSRx,
*state->DFEForward[tn],
*state->DFEFeedback[tn]);
}
return demodulateBurst(burst, mSPSRx, amp, toa);
return analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, amp,
toa, mMaxExpectedDelay);
}
void writeToFile(radioVector *radio_burst, size_t chan)
@@ -655,42 +594,47 @@ void writeToFile(radioVector *radio_burst, size_t chan)
* Pull bursts from the FIFO and handle according to the slot
* and burst correlation type. Equalzation is currently disabled.
*/
SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
double &timingOffset, double &noise,
size_t chan)
SoftVector *Transceiver::demodSignalVector(signalVector *burst,
CorrType type,
double &timingOffset)
{
int success;
bool equalize = false;
complex amp;
float toa, pow, max = -1.0, avg = 0.0;
int max_i = -1;
signalVector *burst;
float toa;
SoftVector *bits = NULL;
TransceiverState *state = &mStates[chan];
isRssiValid = false;
/* Blocking FIFO read */
radioVector *radio_burst = mReceiveFIFO[chan]->read();
if (!radio_burst)
return NULL;
/* Detect normal or RACH bursts */
if (type == TSC)
success = detectTSC(*burst, amp, toa);
else
success = detectRACH(*burst, amp, toa);
/* Set time and determine correlation type */
GSM::Time time = radio_burst->getTime();
CorrType type = expectedCorrType(time, chan);
/* Alert an error and exit */
if (success <= 0) {
if (success == -SIGERR_CLIP) {
LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
} else if (success != SIGERR_NONE) {
LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
}
/* Debug: dump bursts to disk */
/* bits 0-7 - chan 0 timeslots
* bits 8-15 - chan 1 timeslots */
if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
writeToFile(radio_burst, chan);
/* No processing if the timeslot is off.
* Not even power level or noise calculation. */
if (type == OFF) {
delete radio_burst;
return NULL;
}
timingOffset = toa / mSPSRx;
bits = demodulateBurst(*burst, mSPSRx, amp, toa);
return bits;
}
signalVector *Transceiver::chooseDiversityPath(radioVector *radio_burst, double &avg)
{
signalVector *burst;
int max_i = -1;
float pow, max = -1.0;
avg = 0.0;
/* Select the diversity channel with highest energy */
for (size_t i = 0; i < radio_burst->chans(); i++) {
energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
@@ -703,7 +647,6 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &i
if (max_i < 0) {
LOG(ALERT) << "Received empty burst";
delete radio_burst;
return NULL;
}
@@ -711,62 +654,16 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &i
burst = radio_burst->getVector(max_i);
avg = sqrt(avg / radio_burst->chans());
wTime = time;
RSSI = 20.0 * log10(rxFullScale / avg);
/* RSSI estimation are valid */
isRssiValid = true;
if (type == IDLE) {
/* Update noise levels */
state->mNoises.insert(avg);
state->mNoiseLev = state->mNoises.avg();
noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
delete radio_burst;
return NULL;
} else {
/* Do not update noise levels */
noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
}
/* Detect normal or RACH bursts */
if (type == TSC)
success = detectTSC(state, *burst, amp, toa, time);
else
success = detectRACH(state, *burst, amp, toa);
/* Alert an error and exit */
if (success <= 0) {
if (success == -SIGERR_CLIP) {
LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
} else if (success != SIGERR_NONE) {
LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
}
delete radio_burst;
return NULL;
}
timingOffset = toa / mSPSRx;
/* Demodulate and set output info */
if (equalize && (type != TSC))
equalize = false;
bits = demodulate(state, *burst, amp, toa, time.TN(), equalize);
delete radio_burst;
return bits;
return burst;
}
void Transceiver::reset()
void TransceiverState::updateNoiseEstimates(double avg)
{
for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
mTxPriorityQueues[i].clear();
/* Update noise levels */
mNoises.insert(avg);
mNoiseLev = mNoises.avg();
}
void Transceiver::driveControl(size_t chan)
{
int MAX_PACKET_LENGTH = 100;
@@ -841,9 +738,8 @@ void Transceiver::driveControl(size_t chan)
}
else if (strcmp(command,"NOISELEV")==0) {
if (mOn) {
float lev = mStates[chan].mNoiseLev;
sprintf(response,"RSP NOISELEV 0 %d",
(int) round(20.0 * log10(rxFullScale / lev)));
(int) round(dB2(rxFullScale / mStates[chan].mNoiseLev)));
}
else {
sprintf(response,"RSP NOISELEV 1 0");
@@ -980,20 +876,64 @@ void Transceiver::driveReceiveRadio()
void Transceiver::driveReceiveFIFO(size_t chan)
{
SoftVector *rxBurst = NULL;
radioVector *radio_burst = NULL;
signalVector *burst = NULL;
double burst_power; // sqr(amp)
double RSSI; // in dBFS
double dBm; // in dBm
double TOA; // in symbols
int TOAint; // in 1/256 symbols
double noise; // noise level in dBFS
GSM::Time burstTime;
bool isRssiValid; // are RSSI, noise and burstTime valid
CorrType burstType;
char burstString[3000];
int pktLen;
rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
/* Blocking FIFO read */
radio_burst = mReceiveFIFO[chan]->read();
if (!radio_burst)
return;
if (rxBurst) {
dBm = RSSI+rssiOffset;
TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
/* Set time and determine correlation type */
burstTime = radio_burst->getTime();
burstType = expectedCorrType(burstTime, chan);
/* Debug: dump bursts to disk */
/* bits 0-7 - chan 0 timeslots
* bits 8-15 - chan 1 timeslots */
if (mWriteBurstToDiskMask & ((1<<burstTime.TN()) << (8*chan)))
writeToFile(radio_burst, chan);
/* No processing if the timeslot is off. */
if (burstType == OFF) {
delete radio_burst;
return;
}
/* Choose a diversity channel to use */
/* Returned value is a pointer to the radio_burst internal structure */
burst = chooseDiversityPath(radio_burst, burst_power);
if (!burst) {
delete radio_burst;
return;
}
/* We use idle timeslots to calculate noise levels for informational purposes.
* Otherwise we ignore them. */
if (burstType == IDLE) {
mStates[chan].updateNoiseEstimates(burst_power);
return;
}
/* Update/calculate burst info */
noise = dB2(rxFullScale / mStates[chan].mNoiseLev);
RSSI = dB2(rxFullScale / burst_power);
dBm = RSSI+rssiOffset;
if (!mExternalDemod) {
/* Pre-process and demodulate radio vector */
SoftVector *rxBurst = demodSignalVector(burst, burstType, TOA);
if (!rxBurst)
return;
LOG(DEBUG) << std::fixed << std::right
<< " time: " << burstTime
@@ -1002,23 +942,67 @@ void Transceiver::driveReceiveFIFO(size_t chan)
<< " TOA: " << std::setw(5) << std::setprecision(2) << TOA
<< " bits: " << *rxBurst;
char burstString[gSlotLen+10];
burstString[0] = burstTime.TN();
for (int i = 0; i < 4; i++)
burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
burstString[5] = (int)dBm;
burstString[6] = (TOAint >> 8) & 0x0ff;
burstString[7] = TOAint & 0x0ff;
SoftVector::iterator burstItr = rxBurst->begin();
for (unsigned int i = 0; i < gSlotLen; i++) {
burstString[8+i] =(char) round((*burstItr++)*255.0);
}
burstString[gSlotLen+9] = '\0';
pktLen = formatDemodPacket(burstTime, dBm, TOA, rxBurst, burstString);
delete rxBurst;
mDataSockets[chan]->write(burstString,gSlotLen+10);
} else {
/* Send radio vector as is */
pktLen = formatRawPacket(burstTime, dBm, TOA, burstType, mTSC, burst, burstString);
}
mDataSockets[chan]->write(burstString, pktLen);
delete radio_burst;
}
int Transceiver::formatCommonPacketHeader(GSM::Time burstTime, double dBm, double TOA,
char *burstString)
{
int TOAint; // in 1/256 symbols
TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
burstString[0] = burstTime.TN();
for (int i = 0; i < 4; i++)
burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
burstString[5] = (int)dBm;
burstString[6] = (TOAint >> 8) & 0x0ff;
burstString[7] = TOAint & 0x0ff;
return 8;
}
int Transceiver::formatDemodPacket(GSM::Time burstTime, double dBm, double TOA,
SoftVector *rxBurst, char *burstString)
{
int headerSize = formatCommonPacketHeader(burstTime, dBm, TOA, burstString);
SoftVector::iterator burstItr = rxBurst->begin();
for (unsigned int i = 0; i < gSlotLen; i++) {
burstString[headerSize+i] =(char) round((*burstItr++)*255.0);
}
burstString[gSlotLen+headerSize+1] = '\0';
return gSlotLen+headerSize+2;
}
int Transceiver::formatRawPacket(GSM::Time burstTime, double dBm, double TOA,
CorrType burstType, unsigned tsc,
signalVector *rxBurst, char *burstString)
{
int headerSize = formatCommonPacketHeader(burstTime, dBm, TOA, burstString);
burstString[headerSize++] = burstType;
burstString[headerSize++] = tsc;
burstString[headerSize++] = 0; // alignment
burstString[headerSize++] = 0; // alignment
signalVector::iterator burstItr = rxBurst->begin();
float *signalItr = (float*)(&burstString[headerSize]);
for (unsigned int i = 0; i < gSlotLen; i++, burstItr++) {
signalItr[2*i] = (*burstItr).real();
signalItr[2*i+1] = (*burstItr).imag();
}
return headerSize + 2*gSlotLen*sizeof(float);
}
void Transceiver::driveTxFIFO()

View File

@@ -55,29 +55,15 @@ struct TransceiverState {
/* Initialize a multiframe slot in the filler table */
bool init(int filler, size_t sps, float scale, size_t rtsc);
void updateNoiseEstimates(double avg);
int chanType[8];
/* Last timestamp of each timeslot's channel estimate */
GSM::Time chanEstimateTime[8];
/* The filler table */
signalVector *fillerTable[102][8];
int fillerModulus[8];
bool mRetrans;
/* Most recent channel estimate of all timeslots */
signalVector *chanResponse[8];
/* Most recent DFE feedback filter of all timeslots */
signalVector *DFEForward[8];
signalVector *DFEFeedback[8];
/* Most recent SNR, timing, and channel amplitude estimates */
float SNRestimate[8];
float chanRespOffset[8];
complex chanRespAmplitude[8];
/* Received noise energy levels */
float mNoiseLev;
noiseVector mNoises;
@@ -101,7 +87,8 @@ public:
size_t wSPS, size_t chans,
GSM::Time wTransmitLatency,
RadioInterface *wRadioInterface,
double wRssiOffset);
double wRssiOffset,
bool wExternalDemod);
/** Destructor */
~Transceiver();
@@ -184,6 +171,8 @@ private:
double rssiOffset; ///< RSSI to dBm conversion offset
bool mExternalDemod; ///< Should we internal or external demod
/** modulate and add a burst to the transmit queue */
void addRadioVector(size_t chan, BitVector &bits,
int RSSI, GSM::Time &wTime);
@@ -195,9 +184,15 @@ private:
void pushRadioVector(GSM::Time &nowTime);
/** Pull and demodulate a burst from the receive FIFO */
SoftVector *pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
double &timingOffset, double &noise,
size_t chan = 0);
SoftVector *demodSignalVector(signalVector *burst,
CorrType type,
double &timingOffset);
/** choose the channel to use */
signalVector *chooseDiversityPath(radioVector *radio_burst, double &avg);
/** update noise estimate */
double updateNoiseEstimates(TransceiverState *state, double avg);
/** Set modulus for specific timeslot */
void setModulus(size_t timeslot, size_t chan);
@@ -209,19 +204,12 @@ private:
void writeClockInterface(void);
/** Detect RACH bursts */
int detectRACH(TransceiverState *state,
signalVector &burst,
int detectRACH(signalVector &burst,
complex &amp, float &toa);
/** Detect normal bursts */
int detectTSC(TransceiverState *state,
signalVector &burst,
complex &amp, float &toa, GSM::Time &time);
/** Demodulat burst and output soft bits */
SoftVector *demodulate(TransceiverState *state,
signalVector &burst, complex amp,
float toa, size_t tn, bool equalize);
int detectTSC(signalVector &burst,
complex &amp, float &toa);
int mSPSTx; ///< number of samples per Tx symbol
int mSPSRx; ///< number of samples per Rx symbol
@@ -251,6 +239,19 @@ protected:
/** drive demodulation of GSM bursts */
void driveReceiveFIFO(size_t chan);
/** format a common header for packets with sent over the network */
int formatCommonPacketHeader(GSM::Time burstTime, double dBm, double TOA,
char *burstString);
/** format a packet of soft-bits to be sent over the network */
int formatDemodPacket(GSM::Time burstTime, double dBm, double TOA,
SoftVector *rxBurst, char *burstString);
/** format a packet of raw samples to be sent over the network */
int formatRawPacket(GSM::Time burstTime, double dBm, double TOA,
CorrType burstType, unsigned tsc,
signalVector *rxBurst, char *burstString);
/** drive transmission of GSM bursts */
void driveTxFIFO();

View File

@@ -72,6 +72,7 @@ struct trx_config {
double offset;
double rssi_offset;
bool swap_channels;
bool external_demod;
};
ConfigurationTable gConfig;
@@ -189,6 +190,7 @@ bool trx_setup_config(struct trx_config *config)
ost << " Tuning offset........... " << config->offset << std::endl;
ost << " RSSI to dBm offset...... " << config->rssi_offset << std::endl;
ost << " Swap channels........... " << config->swap_channels << std::endl;
ost << " External demodulator.... " << config->external_demod << std::endl;
std::cout << ost << std::endl;
return true;
@@ -244,7 +246,7 @@ Transceiver *makeTransceiver(struct trx_config *config, RadioInterface *radio)
VectorFIFO *fifo;
trx = new Transceiver(config->port, config->addr.c_str(), config->sps,
config->chans, GSM::Time(3,0), radio, config->rssi_offset);
config->chans, GSM::Time(3,0), radio, config->rssi_offset, config->external_demod);
if (!trx->init(config->filler, config->rtsc)) {
LOG(ALERT) << "Failed to initialize transceiver";
delete trx;
@@ -298,8 +300,9 @@ static void print_help()
" -o Set baseband frequency offset (default=auto)\n"
" -r Random burst test mode with TSC\n"
" -R RSSI to dBm offset in dB (default=0)\n"
" -S Swap channels (UmTRX only)\n",
"EMERG, ALERT, CRT, ERR, WARNING, NOTICE, INFO, DEBUG");
" -S Swap channels (UmTRX only)\n"
" -e External demodulator - stream raw samples instead of soft bits (default=internal)\n",
"EMERG, ALERT, CRT, ERR, WARNING, NOTICE, INFO, DEBUG");
}
static void handle_options(int argc, char **argv, struct trx_config *config)
@@ -316,8 +319,9 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
config->offset = 0.0;
config->rssi_offset = 0.0;
config->swap_channels = false;
config->external_demod = false;
while ((option = getopt(argc, argv, "ha:l:i:p:c:dxfo:s:r:R:S")) != -1) {
while ((option = getopt(argc, argv, "ha:l:i:p:c:dxfo:s:r:R:Se")) != -1) {
switch (option) {
case 'h':
print_help();
@@ -363,6 +367,9 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
case 'S':
config->swap_channels = true;
break;
case 'e':
config->external_demod = true;
break;
default:
print_help();
exit(0);

View File

@@ -147,64 +147,8 @@ void sigProcLibDestroy()
GSMPulse1 = NULL;
}
// dB relative to 1.0.
// if > 1.0, then return 0 dB
float dB(float x) {
float arg = 1.0F;
float dB = 0.0F;
if (x >= 1.0F) return 0.0F;
if (x <= 0.0F) return -200.0F;
float prevArg = arg;
float prevdB = dB;
float stepSize = 16.0F;
float dBstepSize = 12.0F;
while (stepSize > 1.0F) {
do {
prevArg = arg;
prevdB = dB;
arg /= stepSize;
dB -= dBstepSize;
} while (arg > x);
arg = prevArg;
dB = prevdB;
stepSize *= 0.5F;
dBstepSize -= 3.0F;
}
return ((arg-x)*(dB-3.0F) + (x-arg*0.5F)*dB)/(arg - arg*0.5F);
}
// 10^(-dB/10), inverse of dB func.
float dBinv(float x) {
float arg = 1.0F;
float dB = 0.0F;
if (x >= 0.0F) return 1.0F;
if (x <= -200.0F) return 0.0F;
float prevArg = arg;
float prevdB = dB;
float stepSize = 16.0F;
float dBstepSize = 12.0F;
while (stepSize > 1.0F) {
do {
prevArg = arg;
prevdB = dB;
arg /= stepSize;
dB -= dBstepSize;
} while (dB > x);
arg = prevArg;
dB = prevdB;
stepSize *= 0.5F;
dBstepSize -= 3.0F;
}
return ((dB-x)*(arg*0.5F)+(x-(dB-3.0F))*(arg))/3.0F;
double dB2(double x) {
return 20.0 * log10(x);
}
float vectorNorm2(const signalVector &x)
@@ -1478,8 +1422,7 @@ int detectRACHBurst(signalVector &rxBurst,
* tail: Search 4 symbols + maximum expected delay
*/
int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
int sps, complex &amp, float &toa, unsigned max_toa,
bool chan_req, signalVector **chan, float *chan_offset)
int sps, complex &amp, float &toa, unsigned max_toa)
{
int rc, target, head, tail;
CorrelationSequence *sync;
@@ -1495,14 +1438,6 @@ int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
rc = detectGeneralBurst(rxBurst, thresh, sps, amp, toa,
target, head, tail, sync);
/* Equalization not currently supported */
if (rc > 0 && chan_req) {
*chan = new signalVector(6 * sps);
if (chan_offset)
*chan_offset = 0.0;
}
return rc;
}
@@ -1559,166 +1494,6 @@ SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
return bits;
}
// Assumes symbol-spaced sampling!!!
// Based upon paper by Al-Dhahir and Cioffi
bool designDFE(signalVector &channelResponse,
float SNRestimate,
int Nf,
signalVector **feedForwardFilter,
signalVector **feedbackFilter)
{
signalVector G0(Nf);
signalVector G1(Nf);
signalVector::iterator G0ptr = G0.begin();
signalVector::iterator G1ptr = G1.begin();
signalVector::iterator chanPtr = channelResponse.begin();
int nu = channelResponse.size()-1;
*G0ptr = 1.0/sqrtf(SNRestimate);
for(int j = 0; j <= nu; j++) {
*G1ptr = chanPtr->conj();
G1ptr++; chanPtr++;
}
signalVector *L[Nf];
signalVector::iterator Lptr;
float d = 1.0;
for(int i = 0; i < Nf; i++) {
d = G0.begin()->norm2() + G1.begin()->norm2();
L[i] = new signalVector(Nf+nu);
Lptr = L[i]->begin()+i;
G0ptr = G0.begin(); G1ptr = G1.begin();
while ((G0ptr < G0.end()) && (Lptr < L[i]->end())) {
*Lptr = (*G0ptr*(G0.begin()->conj()) + *G1ptr*(G1.begin()->conj()) )/d;
Lptr++;
G0ptr++;
G1ptr++;
}
complex k = (*G1.begin())/(*G0.begin());
if (i != Nf-1) {
signalVector G0new = G1;
scaleVector(G0new,k.conj());
addVector(G0new,G0);
signalVector G1new = G0;
scaleVector(G1new,k*(-1.0));
addVector(G1new,G1);
delayVector(&G1new, &G1new, -1.0);
scaleVector(G0new,1.0/sqrtf(1.0+k.norm2()));
scaleVector(G1new,1.0/sqrtf(1.0+k.norm2()));
G0 = G0new;
G1 = G1new;
}
}
*feedbackFilter = new signalVector(nu);
L[Nf-1]->segmentCopyTo(**feedbackFilter,Nf,nu);
scaleVector(**feedbackFilter,(complex) -1.0);
conjugateVector(**feedbackFilter);
signalVector v(Nf);
signalVector::iterator vStart = v.begin();
signalVector::iterator vPtr;
*(vStart+Nf-1) = (complex) 1.0;
for(int k = Nf-2; k >= 0; k--) {
Lptr = L[k]->begin()+k+1;
vPtr = vStart + k+1;
complex v_k = 0.0;
for (int j = k+1; j < Nf; j++) {
v_k -= (*vPtr)*(*Lptr);
vPtr++; Lptr++;
}
*(vStart + k) = v_k;
}
*feedForwardFilter = new signalVector(Nf);
signalVector::iterator w = (*feedForwardFilter)->end();
for (int i = 0; i < Nf; i++) {
delete L[i];
complex w_i = 0.0;
int endPt = ( nu < (Nf-1-i) ) ? nu : (Nf-1-i);
vPtr = vStart+i;
chanPtr = channelResponse.begin();
for (int k = 0; k < endPt+1; k++) {
w_i += (*vPtr)*(chanPtr->conj());
vPtr++; chanPtr++;
}
*--w = w_i/d;
}
return true;
}
// Assumes symbol-rate sampling!!!!
SoftVector *equalizeBurst(signalVector &rxBurst,
float TOA,
int sps,
signalVector &w, // feedforward filter
signalVector &b) // feedback filter
{
signalVector *postForwardFull;
if (!delayVector(&rxBurst, &rxBurst, -TOA))
return NULL;
postForwardFull = convolve(&rxBurst, &w, NULL,
CUSTOM, 0, rxBurst.size() + w.size() - 1);
if (!postForwardFull)
return NULL;
signalVector* postForward = new signalVector(rxBurst.size());
postForwardFull->segmentCopyTo(*postForward,w.size()-1,rxBurst.size());
delete postForwardFull;
signalVector::iterator dPtr = postForward->begin();
signalVector::iterator dBackPtr;
signalVector::iterator rotPtr = GMSKRotationN->begin();
signalVector::iterator revRotPtr = GMSKReverseRotationN->begin();
signalVector *DFEoutput = new signalVector(postForward->size());
signalVector::iterator DFEItr = DFEoutput->begin();
// NOTE: can insert the midamble and/or use midamble to estimate BER
for (; dPtr < postForward->end(); dPtr++) {
dBackPtr = dPtr-1;
signalVector::iterator bPtr = b.begin();
while ( (bPtr < b.end()) && (dBackPtr >= postForward->begin()) ) {
*dPtr = *dPtr + (*bPtr)*(*dBackPtr);
bPtr++;
dBackPtr--;
}
*dPtr = *dPtr * (*revRotPtr);
*DFEItr = *dPtr;
// make decision on symbol
*dPtr = (dPtr->real() > 0.0) ? 1.0 : -1.0;
//*DFEItr = *dPtr;
*dPtr = *dPtr * (*rotPtr);
DFEItr++;
rotPtr++;
revRotPtr++;
}
vectorSlicer(DFEoutput);
SoftVector *burstBits = new SoftVector(postForward->size());
SoftVector::iterator burstItr = burstBits->begin();
DFEItr = DFEoutput->begin();
for (; DFEItr < DFEoutput->end(); DFEItr++)
*burstItr++ = DFEItr->real();
delete postForward;
delete DFEoutput;
return burstBits;
}
bool sigProcLibSetup(int sps)
{
if ((sps != 1) && (sps != 4))

View File

@@ -36,8 +36,8 @@ enum signalError {
SIGERR_INTERNAL,
};
/** Convert a linear number to a dB value */
float dB(float x);
/** Convert a power value to a dB value */
double dB2(double x);
/** Convert a dB value into a linear value */
float dBinv(float x);
@@ -204,9 +204,6 @@ int detectRACHBurst(signalVector &rxBurst,
@param amplitude The estimated amplitude of received TSC burst.
@param TOA The estimate time-of-arrival of received TSC burst.
@param maxTOA The maximum expected time-of-arrival
@param requestChannel Set to true if channel estimation is desired.
@param channelResponse The estimated channel.
@param channelResponseOffset The time offset b/w the first sample of the channel response and the reported TOA.
@return positive if threshold value is reached, negative on error, zero otherwise
*/
int analyzeTrafficBurst(signalVector &rxBurst,
@@ -215,10 +212,7 @@ int analyzeTrafficBurst(signalVector &rxBurst,
int sps,
complex &amplitude,
float &TOA,
unsigned maxTOA,
bool requestChannel = false,
signalVector** channelResponse = NULL,
float *channelResponseOffset = NULL);
unsigned maxTOA);
/**
Decimate a vector.
@@ -240,34 +234,4 @@ signalVector *decimateVector(signalVector &wVector, size_t factor);
SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
complex channel, float TOA);
/**
Design the necessary filters for a decision-feedback equalizer.
@param channelResponse The multipath channel that we're mitigating.
@param SNRestimate The signal-to-noise estimate of the channel, a linear value
@param Nf The number of taps in the feedforward filter.
@param feedForwardFilter The designed feed forward filter.
@param feedbackFilter The designed feedback filter.
@return True if DFE can be designed.
*/
bool designDFE(signalVector &channelResponse,
float SNRestimate,
int Nf,
signalVector **feedForwardFilter,
signalVector **feedbackFilter);
/**
Equalize/demodulate a received burst via a decision-feedback equalizer.
@param rxBurst The received burst to be demodulated.
@param TOA The time-of-arrival of the received burst.
@param sps The number of samples per GSM symbol.
@param w The feed forward filter of the DFE.
@param b The feedback filter of the DFE.
@return The demodulated bit sequence.
*/
SoftVector *equalizeBurst(signalVector &rxBurst,
float TOA,
int sps,
signalVector &w,
signalVector &b);
#endif /* SIGPROCLIB_H */

View File

@@ -1,5 +1,5 @@
if !ARCH_ARM
AM_CFLAGS = -Wall -std=gnu99 -march=native -I../common
AM_CFLAGS = -Wall -std=gnu99 -I../common
noinst_LTLIBRARIES = libarch.la

19
debian/changelog vendored Normal file
View File

@@ -0,0 +1,19 @@
osmo-trx (0.1.9~1) trusty; urgency=medium
* minor debian changes
* correct atom cross-compilation
* corrected build-time and run-time dependencies
-- Kirill Zakharenko <earwin@gmail.com> Thu, 23 Jul 2015 00:01:07 +0000
osmo-trx (0.1.9) trusty; urgency=medium
* Ask Ivan, really
-- Kirill Zakharenko <earwin@gmail.com> Thu, 16 Jul 2015 12:13:46 +0000
osmo-trx (0.1.8) precise; urgency=low
* Initial release (Closes: #nnnn) <nnnn is the bug number of your ITP
-- Ivan Klyuchnikov <Ivan.Kluchnikov@fairwaves.ru> Sun, 9 Mar 2014 14:10:10 +0400

1
debian/compat vendored Normal file
View File

@@ -0,0 +1 @@
9

24
debian/control vendored Normal file
View File

@@ -0,0 +1,24 @@
Source: osmo-trx
Maintainer: Ivan Klyuchnikov <ivan.kluchnikov@fairwaves.ru>
Section: net
Priority: optional
Standards-Version: 3.9.3
Build-Depends: debhelper (>= 9), autotools-dev, libdbd-sqlite3, pkg-config, dh-autoreconf, libuhd-dev, libusb-1.0-0-dev, libboost-all-dev, hardening-wrapper
Homepage: http://openbsc.osmocom.org/trac/wiki/OsmoTRX
Vcs-Git: git://git.osmocom.org/osmo-trx
Vcs-Browser: http://cgit.osmocom.org/osmo-trx
Package: osmo-trx
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libdbd-sqlite3
Description: OsmoTRX is a software-defined radio transceiver that implements the Layer 1 physical layer of a BTS
Package: osmo-trx-dbg
Architecture: any
Section: debug
Priority: extra
Depends: osmo-trx (= ${binary:Version}), ${misc:Depends}
Description: Debug symbols for the osmo-trx
Make debugging possible

25
debian/copyright vendored Normal file
View File

@@ -0,0 +1,25 @@
The Debian packaging is:
Copyright (C) 2014 Max <max.suraev@fairwaves.ru>
It was downloaded from:
git://git.osmocom.org/osmo-trx
Upstream Authors:
Thomas Tsou <tom@tsou.cc>
David A. Burgess <dburgess@kestrelsp.com>
Harvind S. Samra <hssamra@kestrelsp.com>
Raffi Sevlian <raffisev@gmail.com>
Copyright:
Copyright (C) 2012-2013 Thomas Tsou <tom@tsou.cc>
Copyright (C) 2011 Range Networks, Inc.
Copyright (C) 2008-2011 Free Software Foundation, Inc.
License:
GNU Affero General Public License, Version 3

1
debian/osmo-trx.install vendored Normal file
View File

@@ -0,0 +1 @@
/usr/bin/osmo-trx

15
debian/rules vendored Executable file
View File

@@ -0,0 +1,15 @@
#!/usr/bin/make -f
DEB_BUILD_HARDENING=1
%:
dh $@ --with autoreconf
override_dh_auto_configure:
dh_auto_configure -- --without-sse CFLAGS="-DHAVE_SSE3 -march=atom -mtune=atom -O2" CXXFLAGS="-DHAVE_SSE3 -march=atom -mtune=atom -O2"
override_dh_shlibdeps:
dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info
override_dh_strip:
dh_strip --dbg-package=osmo-trx-dbg

1
debian/source/format vendored Normal file
View File

@@ -0,0 +1 @@
3.0 (native)