aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Tsou <tom@tsou.cc>2014-04-16 22:24:00 -0400
committerThomas Tsou <tom@tsou.cc>2014-10-06 10:35:29 -0700
commitc7f36c282a917a4718f9b116ba59d2daffa16eb2 (patch)
tree6c74ec97723488a62fb801cdcd55f6e44104f574
parentf31e4bb089453c18d42f998d8aa45b9c7947ff8a (diff)
Transceiver52M: Decode SCH and adjust GSM clock
When in MS acquisition mode, attempt to decode SCH and establish the BTS frame timing. Lock the transceiver GSM clock to the BTS by adjusting the clock value by the measured burst-SCH offset. Add tracking state, TRX_MODE_MS_TRACKING, which continues to detect and decode the SCH with timing tracking, but only on SCH poitions within the 51 multiframe. Signed-off-by: Thomas Tsou <tom@tsou.cc>
-rw-r--r--Transceiver52M/Makefile.am7
-rw-r--r--Transceiver52M/Transceiver.cpp89
-rw-r--r--Transceiver52M/Transceiver.h3
-rw-r--r--Transceiver52M/UHDDevice.cpp2
-rw-r--r--Transceiver52M/radioClock.cpp29
-rw-r--r--Transceiver52M/radioClock.h1
-rw-r--r--Transceiver52M/radioInterface.cpp5
-rw-r--r--Transceiver52M/radioInterface.h3
-rw-r--r--Transceiver52M/sch.c156
-rw-r--r--Transceiver52M/sch.h24
-rw-r--r--configure.ac3
11 files changed, 313 insertions, 9 deletions
diff --git a/Transceiver52M/Makefile.am b/Transceiver52M/Makefile.am
index d0a20f4..2255382 100644
--- a/Transceiver52M/Makefile.am
+++ b/Transceiver52M/Makefile.am
@@ -56,7 +56,8 @@ COMMON_SOURCES = \
radioClock.cpp \
sigProcLib.cpp \
signalVector.cpp \
- Transceiver.cpp
+ Transceiver.cpp \
+ sch.c
libtransceiver_la_SOURCES = \
$(COMMON_SOURCES) \
@@ -87,7 +88,9 @@ osmo_trx_LDADD = \
libtransceiver.la \
$(ARCH_LA) \
$(GSM_LA) \
- $(COMMON_LA) $(SQLITE_LA)
+ $(COMMON_LA) \
+ $(SQLITE_LA) \
+ $(LIBOSMOCORE_LIBS)
if USRP1
libtransceiver_la_SOURCES += USRPDevice.cpp
diff --git a/Transceiver52M/Transceiver.cpp b/Transceiver52M/Transceiver.cpp
index c6042eb..c3446f8 100644
--- a/Transceiver52M/Transceiver.cpp
+++ b/Transceiver52M/Transceiver.cpp
@@ -25,6 +25,10 @@
#include "Transceiver.h"
#include <Logger.h>
+extern "C" {
+#include "sch.h"
+}
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -405,6 +409,50 @@ bool Transceiver::detectSCH(TransceiverState *state,
return false;
}
+#define SCH_BIT_SCALE 64
+
+/* Decode SCH burst */
+bool Transceiver::decodeSCH(SoftVector *burst, GSM::Time *time)
+{
+ int fn;
+ struct sch_info sch;
+ ubit_t info[GSM_SCH_INFO_LEN];
+ sbit_t data[GSM_SCH_CODED_LEN];
+
+ if (burst->size() < 156) {
+ std::cout << "Invalid SCH burst length" << std::endl;
+ return false;
+ }
+
+ float_to_sbit(&(*burst)[3], &data[0], SCH_BIT_SCALE, 39);
+ float_to_sbit(&(*burst)[106], &data[39], SCH_BIT_SCALE, 39);
+
+ if (!gsm_sch_decode(info, data)) {
+ gsm_sch_parse(info, &sch);
+
+ std::cout << "SCH : Decoded values" << std::endl;
+ std::cout << " BSIC: " << sch.bsic << std::endl;
+ std::cout << " T1 : " << sch.t1 << std::endl;
+ std::cout << " T2 : " << sch.t2 << std::endl;
+ std::cout << " T3p : " << sch.t3p << std::endl;
+ std::cout << " FN : " << gsm_sch_to_fn(&sch) << std::endl;
+
+ fn = gsm_sch_to_fn(&sch);
+ if (fn < 0) {
+ std::cout << "SCH : Failed to convert FN " << std::endl;
+ return false;
+ }
+
+ time->FN(fn);
+ time->TN(0);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+
/*
* Detect normal burst training sequence midamble. Update equalization
* state information and channel estimate if necessary. Equalization
@@ -491,19 +539,26 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
SoftVector *bits = NULL;
TransceiverState *state = &mStates[chan];
+ GSM::Time sch_time, burst_time, diff_time;
+
/* Blocking FIFO read */
radioVector *radio_burst = mReceiveFIFO[chan]->read();
if (!radio_burst)
return NULL;
/* Set time and determine correlation type */
- GSM::Time time = radio_burst->getTime();
- CorrType type = expectedCorrType(time, chan);
+ burst_time = radio_burst->getTime();
+ CorrType type = expectedCorrType(burst_time, chan);
switch (state->mode) {
case TRX_MODE_MS_ACQUIRE:
type = SCH;
break;
+ case TRX_MODE_MS_TRACK:
+ if (!gsm_sch_check_fn(burst_time.FN()))
+ goto release;
+ type = SCH;
+ break;
case TRX_MODE_BTS:
if ((type == TSC) || (type == RACH))
break;
@@ -534,7 +589,7 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
/* Detect normal or RACH bursts */
if (type == TSC)
- success = detectTSC(state, *burst, amp, toa, time);
+ success = detectTSC(state, *burst, amp, toa, burst_time);
else if (type == RACH)
success = detectRACH(state, *burst, amp, toa);
else if (type == SCH)
@@ -551,10 +606,32 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
if (equalize && (type != TSC))
equalize = false;
- if (avg - state->mNoiseLev > 0.0)
- bits = demodulate(state, *burst, amp, toa, time.TN(), equalize);
+ /* Ignore noise threshold on MS mode for now */
+ if ((type == SCH) || (avg - state->mNoiseLev > 0.0))
+ bits = demodulate(state, *burst, amp, toa,
+ burst_time.TN(), equalize);
+
+ /* MS: Decode SCH and adjust GSM clock */
+ if ((state->mode == TRX_MODE_MS_ACQUIRE) ||
+ (state->mode == TRX_MODE_MS_TRACK)) {
+
+ if (decodeSCH(bits, &sch_time)) {
+ if (state->mode == TRX_MODE_MS_ACQUIRE) {
+ diff_time = GSM::Time(sch_time.FN() - burst_time.FN(),
+ -burst_time.TN());
+ mRadioInterface->adjustClock(diff_time);
+ state->mode = TRX_MODE_MS_TRACK;
+
+ std::cout << "SCH : Locking GSM clock " << std::endl;
+ } else {
+ std::cout << "SCH : Read SCH at FN " << burst_time.FN()
+ << " FN51 " << burst_time.FN() % 51 << std::endl;
+ }
+ }
+ goto release;
+ }
- wTime = time;
+ wTime = burst_time;
RSSI = (int) floor(20.0 * log10(rxFullScale / avg));
timingOffset = (int) round(toa * 256.0 / mSPSRx);
diff --git a/Transceiver52M/Transceiver.h b/Transceiver52M/Transceiver.h
index c167519..170af77 100644
--- a/Transceiver52M/Transceiver.h
+++ b/Transceiver52M/Transceiver.h
@@ -155,6 +155,8 @@ private:
signalVector &burst,
complex &amp, float &toa);
+ bool decodeSCH(SoftVector *burst, GSM::Time *time);
+
/** Detect normal bursts */
bool detectTSC(TransceiverState *state,
signalVector &burst,
@@ -238,6 +240,7 @@ public:
TRX_MODE_OFF,
TRX_MODE_BTS,
TRX_MODE_MS_ACQUIRE,
+ TRX_MODE_MS_TRACK,
};
protected:
diff --git a/Transceiver52M/UHDDevice.cpp b/Transceiver52M/UHDDevice.cpp
index bdeb1b5..e943e73 100644
--- a/Transceiver52M/UHDDevice.cpp
+++ b/Transceiver52M/UHDDevice.cpp
@@ -886,7 +886,7 @@ int uhd_device::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
if (rc < 0) {
LOG(ERR) << rx_buffers[0]->str_code(rc);
LOG(ERR) << rx_buffers[0]->str_status();
- return 0;
+ return len;
}
// Create vector buffer
diff --git a/Transceiver52M/radioClock.cpp b/Transceiver52M/radioClock.cpp
index 710018a..d9d5229 100644
--- a/Transceiver52M/radioClock.cpp
+++ b/Transceiver52M/radioClock.cpp
@@ -29,6 +29,35 @@ void RadioClock::set(const GSM::Time& wTime)
mLock.unlock();
}
+void RadioClock::adjust(GSM::Time& wOffset)
+{
+ int tn_diff, fn_diff = 0;
+
+ mLock.lock();
+
+ /* Modulo TN adustment */
+ tn_diff = mClock.TN() + wOffset.TN();
+ if (tn_diff < 0) {
+ tn_diff += 8;
+ fn_diff--;
+ } else if (tn_diff >= 8) {
+ tn_diff -= 8;
+ fn_diff++;
+ }
+
+ /* Modulo FN adjustment */
+ fn_diff += mClock.FN() + wOffset.FN();
+ if (fn_diff < 0)
+ fn_diff += GSM::gHyperframe;
+ else if ((unsigned) fn_diff >= GSM::gHyperframe)
+ fn_diff = fn_diff - GSM::gHyperframe;
+
+ mClock = GSM::Time(fn_diff, tn_diff);
+ updateSignal.signal();
+
+ mLock.unlock();
+}
+
void RadioClock::incTN()
{
mLock.lock();
diff --git a/Transceiver52M/radioClock.h b/Transceiver52M/radioClock.h
index 9c35c44..4ce8416 100644
--- a/Transceiver52M/radioClock.h
+++ b/Transceiver52M/radioClock.h
@@ -27,6 +27,7 @@
class RadioClock {
public:
void set(const GSM::Time& wTime);
+ void adjust(GSM::Time &wOffset);
void incTN();
GSM::Time get();
void wait();
diff --git a/Transceiver52M/radioInterface.cpp b/Transceiver52M/radioInterface.cpp
index d55761a..317d2b4 100644
--- a/Transceiver52M/radioInterface.cpp
+++ b/Transceiver52M/radioInterface.cpp
@@ -157,6 +157,11 @@ int RadioInterface::unRadioifyVector(float *floatVector,
return newVector.size();
}
+void RadioInterface::adjustClock(GSM::Time &offset)
+{
+ mClock.adjust(offset);
+}
+
bool RadioInterface::tuneTx(double freq, size_t chan)
{
return mRadio->setTxFreq(freq, chan);
diff --git a/Transceiver52M/radioInterface.h b/Transceiver52M/radioInterface.h
index 36bc6ea..7798e5c 100644
--- a/Transceiver52M/radioInterface.h
+++ b/Transceiver52M/radioInterface.h
@@ -102,6 +102,9 @@ public:
/** return the basestation clock */
RadioClock* getClock(void) { return &mClock;};
+ /** apply an offset to the main clock */
+ void adjustClock(GSM::Time &offset);
+
/** set transmit frequency */
bool tuneTx(double freq, size_t chan = 0);
diff --git a/Transceiver52M/sch.c b/Transceiver52M/sch.c
new file mode 100644
index 0000000..3cc2232
--- /dev/null
+++ b/Transceiver52M/sch.c
@@ -0,0 +1,156 @@
+#include <complex.h>
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/core/conv.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/crcgen.h>
+
+#include "sch.h"
+
+/* GSM 04.08, 9.1.30 Synchronization channel information */
+struct sch_packed_info {
+ ubit_t t1_hi[2];
+ ubit_t bsic[6];
+ ubit_t t1_md[8];
+ ubit_t t3p_hi[2];
+ ubit_t t2[5];
+ ubit_t t1_lo[1];
+ ubit_t t3p_lo[1];
+} __attribute__((packed));
+
+struct sch_burst {
+ sbit_t tail0[3];
+ sbit_t data0[39];
+ sbit_t etsc[64];
+ sbit_t data1[39];
+ sbit_t tail1[3];
+ sbit_t guard[8];
+} __attribute__((packed));
+
+static const uint8_t sch_next_output[][2] = {
+ { 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
+ { 3, 0 }, { 2, 1 }, { 3, 0 }, { 2, 1 },
+ { 3, 0 }, { 2, 1 }, { 3, 0 }, { 2, 1 },
+ { 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
+};
+
+static const uint8_t sch_next_state[][2] = {
+ { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
+ { 8, 9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
+ { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
+ { 8, 9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
+};
+
+static const struct osmo_conv_code gsm_conv_sch = {
+ .N = 2,
+ .K = 5,
+ .len = GSM_SCH_UNCODED_LEN,
+ .next_output = sch_next_output,
+ .next_state = sch_next_state,
+};
+
+const struct osmo_crc16gen_code gsm0503_sch_crc10 = {
+ .bits = 10,
+ .poly = 0x175,
+ .init = 0x000,
+ .remainder = 0x3ff,
+};
+
+#define GSM_MAX_BURST_LEN 157
+#define GSM_SYM_RATE (1625e3 / 6)
+
+int float_to_sbit(const float *in, sbit_t *out, float scale, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ out[i] = (in[i] - 0.5f) * scale;
+ }
+
+ return 0;
+}
+
+/* Check if FN contains a SCH burst */
+int gsm_sch_check_fn(int fn)
+{
+ int fn51 = fn % 51;
+
+ switch (fn51) {
+ case 1:
+ case 11:
+ case 21:
+ case 31:
+ case 41:
+ return 1;
+ }
+
+ return 0;
+}
+
+/* SCH (T1, T2, T3p) to full FN value */
+int gsm_sch_to_fn(struct sch_info *sch)
+{
+ int t1 = sch->t1;
+ int t2 = sch->t2;
+ int t3p = sch->t3p;
+
+ if ((t1 < 0) || (t2 < 0) || (t3p < 0))
+ return -1;
+ int tt;
+ int t3 = t3p * 10 + 1;
+
+ if (t3 < t2)
+ tt = (t3 + 26) - t2;
+ else
+ tt = (t3 - t2) % 26;
+
+ return t1 * 51 * 26 + tt * 51 + t3;
+}
+
+/* Parse encoded SCH message */
+int gsm_sch_parse(const uint8_t *info, struct sch_info *desc)
+{
+ struct sch_packed_info *p = (struct sch_packed_info *) info;
+
+ desc->bsic = (p->bsic[0] << 0) | (p->bsic[1] << 1) |
+ (p->bsic[2] << 2) | (p->bsic[3] << 3) |
+ (p->bsic[4] << 4);
+
+ desc->t1 = (p->t1_lo[0] << 0) | (p->t1_md[0] << 1) |
+ (p->t1_md[1] << 2) | (p->t1_md[2] << 3) |
+ (p->t1_md[3] << 4) | (p->t1_md[4] << 5) |
+ (p->t1_md[5] << 6) | (p->t1_md[6] << 7) |
+ (p->t1_md[7] << 8) | (p->t1_hi[0] << 9) |
+ (p->t1_hi[1] << 10);
+
+ desc->t2 = (p->t2[0] << 0) | (p->t2[1] << 1) |
+ (p->t2[2] << 2) | (p->t2[3] << 3) |
+ (p->t2[4] << 4);
+
+ desc->t3p = (p->t3p_lo[0] << 0) | (p->t3p_hi[0] << 1) |
+ (p->t3p_hi[1] << 2);
+
+ return 0;
+}
+
+/* From osmo-bts */
+int gsm_sch_decode(uint8_t *info, sbit_t *data)
+{
+ int rc;
+ ubit_t uncoded[GSM_SCH_UNCODED_LEN];
+
+ osmo_conv_decode(&gsm_conv_sch, data, uncoded);
+
+ rc = osmo_crc16gen_check_bits(&gsm0503_sch_crc10,
+ uncoded, GSM_SCH_INFO_LEN,
+ uncoded + GSM_SCH_INFO_LEN);
+ if (rc)
+ return -1;
+
+ memcpy(info, uncoded, GSM_SCH_INFO_LEN * sizeof(ubit_t));
+
+ return 0;
+}
diff --git a/Transceiver52M/sch.h b/Transceiver52M/sch.h
new file mode 100644
index 0000000..1e31968
--- /dev/null
+++ b/Transceiver52M/sch.h
@@ -0,0 +1,24 @@
+#ifndef _SCH_H_
+#define _SCH_H_
+
+#include <osmocom/core/bits.h>
+
+struct sch_info {
+ int bsic;
+ int t1;
+ int t2;
+ int t3p;
+};
+
+#define GSM_SCH_INFO_LEN 25
+#define GSM_SCH_UNCODED_LEN 35
+#define GSM_SCH_CODED_LEN 78
+
+int gsm_sch_decode(uint8_t *sb_info, sbit_t *burst);
+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);
+
+int float_to_sbit(const float *in, sbit_t *out, float scale, int len);
+
+#endif /* _SCH_H_ */
diff --git a/configure.ac b/configure.ac
index ae4ea3b..263486e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -58,6 +58,9 @@ AC_TYPE_SIZE_T
AC_HEADER_TIME
AC_C_BIGENDIAN
+dnl checks for libraries
+PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.3.9)
+
AC_ARG_WITH(usrp1, [
AS_HELP_STRING([--with-usrp1],
[enable USRP1 gnuradio based transceiver])