aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Transceiver52M/Transceiver.cpp40
-rw-r--r--Transceiver52M/Transceiver.h7
-rw-r--r--Transceiver52M/UHDDevice.cpp50
-rw-r--r--Transceiver52M/radioDevice.h3
-rw-r--r--Transceiver52M/radioInterface.cpp4
-rw-r--r--Transceiver52M/radioInterface.h3
-rw-r--r--Transceiver52M/radioVector.cpp28
-rw-r--r--Transceiver52M/radioVector.h7
-rw-r--r--Transceiver52M/sch.c63
-rw-r--r--Transceiver52M/sch.h2
10 files changed, 182 insertions, 25 deletions
diff --git a/Transceiver52M/Transceiver.cpp b/Transceiver52M/Transceiver.cpp
index c3446f8..60be8d2 100644
--- a/Transceiver52M/Transceiver.cpp
+++ b/Transceiver52M/Transceiver.cpp
@@ -45,10 +45,11 @@ using namespace GSM;
/* Number of running values use in noise average */
#define NOISE_CNT 20
+#define FREQ_CNT 20
TransceiverState::TransceiverState()
- : mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT),
- mode(Transceiver::TRX_MODE_OFF)
+ : mRetrans(false), mNoiseLev(0.0),
+ mNoises(NOISE_CNT), mFreqOffsets(FREQ_CNT), mode(Transceiver::TRX_MODE_OFF)
{
for (int i = 0; i < 8; i++) {
chanType[i] = Transceiver::NONE;
@@ -56,6 +57,7 @@ TransceiverState::TransceiverState()
chanResponse[i] = NULL;
DFEForward[i] = NULL;
DFEFeedback[i] = NULL;
+ prevFrame[i] = NULL;
for (int n = 0; n < 102; n++)
fillerTable[n][i] = NULL;
@@ -452,6 +454,34 @@ bool Transceiver::decodeSCH(SoftVector *burst, GSM::Time *time)
return true;
}
+#define FCCH_OFFSET_LIMIT 2e3
+#define FCCH_ADJUST_LIMIT 20.0
+
+/* Apply FCCH frequency correction */
+bool Transceiver::correctFCCH(TransceiverState *state, signalVector *burst)
+{
+ double offset, avg;
+
+ if (!burst)
+ return false;
+
+ offset = gsm_fcch_offset((float *) burst->begin(), burst->size());
+ if (offset > FCCH_OFFSET_LIMIT)
+ return false;
+
+ state->mFreqOffsets.insert(offset);
+ avg = state->mFreqOffsets.avg();
+
+ if (state->mFreqOffsets.full())
+ std::cout << "FCCH: Frequency offset " << avg << " Hz" << std::endl;
+
+ if (state->mFreqOffsets.full() && (fabs(avg) > FCCH_ADJUST_LIMIT)) {
+ mRadioInterface->tuneRxOffset(-avg);
+ state->mFreqOffsets.reset();
+ }
+
+ return true;
+}
/*
* Detect normal burst training sequence midamble. Update equalization
@@ -614,6 +644,7 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
/* MS: Decode SCH and adjust GSM clock */
if ((state->mode == TRX_MODE_MS_ACQUIRE) ||
(state->mode == TRX_MODE_MS_TRACK)) {
+ correctFCCH(state, state->prevFrame[burst_time.TN()]->getVector());
if (decodeSCH(bits, &sch_time)) {
if (state->mode == TRX_MODE_MS_ACQUIRE) {
@@ -635,11 +666,14 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
RSSI = (int) floor(20.0 * log10(rxFullScale / avg));
timingOffset = (int) round(toa * 256.0 / mSPSRx);
- delete radio_burst;
+ delete state->prevFrame[burst_time.TN()];
+ state->prevFrame[burst_time.TN()] = radio_burst;
return bits;
release:
+ delete state->prevFrame[burst_time.TN()];
+ state->prevFrame[burst_time.TN()] = radio_burst;
delete bits;
return NULL;
}
diff --git a/Transceiver52M/Transceiver.h b/Transceiver52M/Transceiver.h
index 170af77..8f3e47b 100644
--- a/Transceiver52M/Transceiver.h
+++ b/Transceiver52M/Transceiver.h
@@ -80,7 +80,11 @@ struct TransceiverState {
/* Received noise energy levels */
float mNoiseLev;
- noiseVector mNoises;
+ avgVector mNoises;
+ avgVector mFreqOffsets;
+
+ /* Store pointers to previous frame */
+ radioVector *prevFrame[8];
/* Transceiver mode */
int mode;
@@ -156,6 +160,7 @@ private:
complex &amp, float &toa);
bool decodeSCH(SoftVector *burst, GSM::Time *time);
+ bool correctFCCH(TransceiverState *state, signalVector *burst);
/** Detect normal bursts */
bool detectTSC(TransceiverState *state,
diff --git a/Transceiver52M/UHDDevice.cpp b/Transceiver52M/UHDDevice.cpp
index e943e73..3b9012a 100644
--- a/Transceiver52M/UHDDevice.cpp
+++ b/Transceiver52M/UHDDevice.cpp
@@ -58,6 +58,11 @@ struct uhd_dev_offset {
const std::string desc;
};
+struct tune_result {
+ uhd::tune_result_t uhd;
+ double freq;
+};
+
/*
* Tx / Rx sample offset values. In a perfect world, there is no group delay
* though analog components, and behaviour through digital filters exactly
@@ -282,6 +287,7 @@ public:
bool setTxFreq(double wFreq, size_t chan);
bool setRxFreq(double wFreq, size_t chan);
+ bool setRxOffset(double wOffset, size_t chan);
inline TIMESTAMP initialWriteTimestamp() { return ts_initial * sps; }
inline TIMESTAMP initialReadTimestamp() { return ts_initial; }
@@ -332,7 +338,7 @@ private:
double offset;
std::vector<double> tx_gains, rx_gains;
- std::vector<double> tx_freqs, rx_freqs;
+ std::vector<tune_result> tx_freqs, rx_freqs;
size_t tx_spp, rx_spp;
bool started;
@@ -1004,7 +1010,7 @@ bool uhd_device::updateAlignment(TIMESTAMP timestamp)
uhd::tune_request_t uhd_device::select_freq(double freq, size_t chan, bool tx)
{
double rf_spread, rf_freq;
- std::vector<double> freqs;
+ std::vector<tune_result> freqs;
uhd::tune_request_t treq(freq);
if ((chans == 1) || ((chans == 2) && dev_type == UMTRX)) {
@@ -1023,17 +1029,17 @@ uhd::tune_request_t uhd_device::select_freq(double freq, size_t chan, bool tx)
freqs = rx_freqs;
/* Tune directly if other channel isn't tuned */
- if (freqs[!chan] < 10.0)
+ if (freqs[!chan].freq < 10.0)
return treq;
/* Find center frequency between channels */
- rf_spread = fabs(freqs[!chan] - freq);
+ rf_spread = fabs(freqs[!chan].freq - freq);
if (rf_spread > B2XX_CLK_RT) {
LOG(ALERT) << rf_spread << "Hz tuning spread not supported\n";
return treq;
}
- rf_freq = (freqs[!chan] + freq) / 2.0f;
+ rf_freq = (freqs[!chan].freq + freq) / 2.0f;
treq.rf_freq_policy = uhd::tune_request_t::POLICY_MANUAL;
treq.target_freq = freq;
@@ -1050,10 +1056,12 @@ bool uhd_device::set_freq(double freq, size_t chan, bool tx)
if (tx) {
tres = usrp_dev->set_tx_freq(treq, chan);
- tx_freqs[chan] = usrp_dev->get_tx_freq(chan);
+ tx_freqs[chan].uhd = tres;
+ tx_freqs[chan].freq = usrp_dev->get_tx_freq(chan);
} else {
tres = usrp_dev->set_rx_freq(treq, chan);
- rx_freqs[chan] = usrp_dev->get_rx_freq(chan);
+ rx_freqs[chan].uhd = tres;
+ rx_freqs[chan].freq = usrp_dev->get_rx_freq(chan);
}
LOG(INFO) << "\n" << tres.to_pp_string() << std::endl;
@@ -1066,13 +1074,15 @@ bool uhd_device::set_freq(double freq, size_t chan, bool tx)
*/
if (treq.rf_freq_policy == uhd::tune_request_t::POLICY_MANUAL) {
if (tx) {
- treq = select_freq(tx_freqs[!chan], !chan, true);
+ treq = select_freq(tx_freqs[!chan].freq, !chan, true);
tres = usrp_dev->set_tx_freq(treq, !chan);
- tx_freqs[!chan] = usrp_dev->get_tx_freq(!chan);
+ tx_freqs[!chan].uhd = tres;
+ tx_freqs[!chan].freq = usrp_dev->get_tx_freq(!chan);
} else {
- treq = select_freq(rx_freqs[!chan], !chan, false);
+ treq = select_freq(rx_freqs[!chan].freq, !chan, false);
tres = usrp_dev->set_rx_freq(treq, !chan);
- rx_freqs[!chan] = usrp_dev->get_rx_freq(!chan);
+ rx_freqs[!chan].uhd = tres;
+ rx_freqs[!chan].freq = usrp_dev->get_rx_freq(!chan);
}
LOG(INFO) << "\n" << tres.to_pp_string() << std::endl;
@@ -1091,6 +1101,20 @@ bool uhd_device::setTxFreq(double wFreq, size_t chan)
return set_freq(wFreq, chan, true);
}
+bool uhd_device::setRxOffset(double wOffset, size_t chan)
+{
+ uhd::tune_result_t tres;
+ uhd::tune_request_t treq(rx_freqs[chan].freq - wOffset);
+
+ treq.rf_freq_policy = uhd::tune_request_t::POLICY_MANUAL;
+ treq.rf_freq = rx_freqs[chan].uhd.actual_rf_freq;
+
+ tres = usrp_dev->set_rx_freq(treq, chan);
+ rx_freqs[chan].freq = usrp_dev->get_rx_freq(chan);
+
+ return true;
+}
+
bool uhd_device::setRxFreq(double wFreq, size_t chan)
{
if (chan >= rx_freqs.size()) {
@@ -1108,7 +1132,7 @@ double uhd_device::getTxFreq(size_t chan)
return 0.0;
}
- return tx_freqs[chan];
+ return tx_freqs[chan].freq;
}
double uhd_device::getRxFreq(size_t chan)
@@ -1118,7 +1142,7 @@ double uhd_device::getRxFreq(size_t chan)
return 0.0;
}
- return rx_freqs[chan];
+ return rx_freqs[chan].freq;
}
bool uhd_device::recv_async_msg()
diff --git a/Transceiver52M/radioDevice.h b/Transceiver52M/radioDevice.h
index 6273bcc..c77869e 100644
--- a/Transceiver52M/radioDevice.h
+++ b/Transceiver52M/radioDevice.h
@@ -91,6 +91,9 @@ class RadioDevice {
/** Set the receiver frequency */
virtual bool setRxFreq(double wFreq, size_t chan = 0) = 0;
+ /** Adjust the receiver offset */
+ virtual bool setRxOffset(double wOffset, size_t chan = 0) = 0;
+
/** Returns the starting write Timestamp*/
virtual TIMESTAMP initialWriteTimestamp(void)=0;
diff --git a/Transceiver52M/radioInterface.cpp b/Transceiver52M/radioInterface.cpp
index 317d2b4..75266dd 100644
--- a/Transceiver52M/radioInterface.cpp
+++ b/Transceiver52M/radioInterface.cpp
@@ -172,6 +172,10 @@ bool RadioInterface::tuneRx(double freq, size_t chan)
return mRadio->setRxFreq(freq, chan);
}
+bool RadioInterface::tuneRxOffset(double offset, size_t chan)
+{
+ return mRadio->setRxOffset(offset, chan);
+}
void RadioInterface::start()
{
diff --git a/Transceiver52M/radioInterface.h b/Transceiver52M/radioInterface.h
index 7798e5c..ebf8f38 100644
--- a/Transceiver52M/radioInterface.h
+++ b/Transceiver52M/radioInterface.h
@@ -111,6 +111,9 @@ public:
/** set receive frequency */
virtual bool tuneRx(double freq, size_t chan = 0);
+ /** set frequency correction */
+ virtual bool tuneRxOffset(double offset, size_t chan = 0);
+
/** set receive gain */
double setRxGain(double dB, size_t chan = 0);
diff --git a/Transceiver52M/radioVector.cpp b/Transceiver52M/radioVector.cpp
index 2e3af9d..ea354b4 100644
--- a/Transceiver52M/radioVector.cpp
+++ b/Transceiver52M/radioVector.cpp
@@ -74,25 +74,31 @@ bool radioVector::setVector(signalVector *vector, size_t chan)
return true;
}
-noiseVector::noiseVector(size_t size)
- : std::vector<float>(size), itr(0)
+avgVector::avgVector(size_t max)
+ : std::vector<float>(0), itr(0)
{
+ this->max = max;
}
-float noiseVector::avg() const
+float avgVector::avg() const
{
float val = 0.0;
+ if (!size())
+ return 0.0f;
+
for (size_t i = 0; i < size(); i++)
val += (*this)[i];
return val / (float) size();
}
-bool noiseVector::insert(float val)
+bool avgVector::insert(float val)
{
- if (!size())
- return false;
+ if (size() < max) {
+ push_back(val);
+ return true;
+ }
if (itr >= this->size())
itr = 0;
@@ -102,6 +108,16 @@ bool noiseVector::insert(float val)
return true;
}
+bool avgVector::full() const
+{
+ return size() >= max;
+}
+
+void avgVector::reset()
+{
+ resize(0);
+}
+
GSM::Time VectorQueue::nextTime() const
{
GSM::Time retVal;
diff --git a/Transceiver52M/radioVector.h b/Transceiver52M/radioVector.h
index 0566123..7e236b6 100644
--- a/Transceiver52M/radioVector.h
+++ b/Transceiver52M/radioVector.h
@@ -46,14 +46,17 @@ private:
GSM::Time mTime;
};
-class noiseVector : std::vector<float> {
+class avgVector : std::vector<float> {
public:
- noiseVector(size_t size = 0);
+ avgVector(size_t size = 0);
bool insert(float val);
+ bool full() const;
float avg() const;
+ void reset();
private:
size_t itr;
+ size_t max;
};
class VectorFIFO : public InterthreadQueue<radioVector> { };
diff --git a/Transceiver52M/sch.c b/Transceiver52M/sch.c
index 3cc2232..67db259 100644
--- a/Transceiver52M/sch.c
+++ b/Transceiver52M/sch.c
@@ -62,6 +62,9 @@ const struct osmo_crc16gen_code gsm0503_sch_crc10 = {
#define GSM_MAX_BURST_LEN 157
#define GSM_SYM_RATE (1625e3 / 6)
+/* Pre-generated FCCH measurement tone */
+static complex float fcch_ref[GSM_MAX_BURST_LEN];
+
int float_to_sbit(const float *in, sbit_t *out, float scale, int len)
{
int i;
@@ -154,3 +157,63 @@ int gsm_sch_decode(uint8_t *info, sbit_t *data)
return 0;
}
+
+#define FCCH_TAIL_BITS_LEN 3
+#define FCCH_DATA_LEN 142
+
+/* Compute FCCH frequency offset */
+double gsm_fcch_offset(float *burst, int len)
+{
+ int i, start, end;
+ float a, b, c, d, ang, avg = 0.0f;
+ double freq;
+
+ if (len > GSM_MAX_BURST_LEN)
+ len = GSM_MAX_BURST_LEN;
+
+ for (i = 0; i < len; i++) {
+ a = burst[2 * i + 0];
+ b = burst[2 * i + 1];
+ c = crealf(fcch_ref[i]);
+ d = cimagf(fcch_ref[i]);
+
+ burst[2 * i + 0] = a * c - b * d;
+ burst[2 * i + 1] = a * d + b * c;
+ }
+
+ start = FCCH_TAIL_BITS_LEN;
+ end = start + FCCH_DATA_LEN;
+
+ for (i = start; i < end; i++) {
+ a = cargf(burst[2 * (i - 1) + 0] +
+ burst[2 * (i - 1) + 1] * I);
+ b = cargf(burst[2 * i + 0] +
+ burst[2 * i + 1] * I);
+
+ ang = b - a;
+
+ if (ang > M_PI)
+ ang -= 2 * M_PI;
+ else if (ang < -M_PI)
+ ang += 2 * M_PI;
+
+ avg += ang;
+ }
+
+ avg /= (float) (end - start);
+ freq = avg / (2 * M_PI) * GSM_SYM_RATE;
+
+ return freq;
+}
+
+/* Generate FCCH measurement tone */
+static __attribute__((constructor)) void init()
+{
+ int i;
+ double freq = 0.25;
+
+ for (i = 0; i < GSM_MAX_BURST_LEN; i++) {
+ fcch_ref[i] = sin(2 * M_PI * freq * (double) i) +
+ cos(2 * M_PI * freq * (double) i) * I;
+ }
+}
diff --git a/Transceiver52M/sch.h b/Transceiver52M/sch.h
index 1e31968..ec2d0e0 100644
--- a/Transceiver52M/sch.h
+++ b/Transceiver52M/sch.h
@@ -19,6 +19,8 @@ int gsm_sch_parse(const uint8_t *sb_info, struct sch_info *desc);
int gsm_sch_to_fn(struct sch_info *sch);
int gsm_sch_check_fn(int fn);
+double gsm_fcch_offset(float *burst, int len);
+
int float_to_sbit(const float *in, sbit_t *out, float scale, int len);
#endif /* _SCH_H_ */