aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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])