Hoernchen has submitted this change. ( 
https://gerrit.osmocom.org/c/osmo-trx/+/36046?usp=email )

Change subject: ms: add sigproclib demod
......................................................................

ms: add sigproclib demod

This is basically a fixed version of ttsous ancient branch that can be
used instead of the VA. Required config option part of a future
patchset.

Change-Id: I6558992bd69f18526be5ebe7d424ca00ceb67772
---
M GSM/GSMCommon.cpp
M GSM/GSMCommon.h
M Transceiver52M/Resampler.cpp
M Transceiver52M/ms/ms_rx_lower.cpp
M Transceiver52M/ms/ms_upper.cpp
M Transceiver52M/sigProcLib.cpp
M Transceiver52M/sigProcLib.h
7 files changed, 419 insertions(+), 11 deletions(-)

Approvals:
  Jenkins Builder: Verified
  pespin: Looks good to me, but someone else must approve
  laforge: Looks good to me, but someone else must approve
  Hoernchen: Looks good to me, approved




diff --git a/GSM/GSMCommon.cpp b/GSM/GSMCommon.cpp
index 5e9e4ae..a9e2bb1 100644
--- a/GSM/GSMCommon.cpp
+++ b/GSM/GSMCommon.cpp
@@ -55,12 +55,15 @@
 };

 const BitVector 
GSM::gDummyBurst("0001111101101110110000010100100111000001001000100000001111100011100010111000101110001010111010010100011001100111001111010011111000100101111101010000");
+const BitVector GSM::gDummyBurstTSC("01110001011100010111000101");

 /* 3GPP TS 05.02, section 5.2.7 "Access burst (AB)", synch. sequence bits */
 const BitVector 
GSM::gRACHSynchSequenceTS0("01001011011111111001100110101010001111000");  /* 
GSM, GMSK (default) */
 const BitVector 
GSM::gRACHSynchSequenceTS1("01010100111110001000011000101111001001101");  /* 
EGPRS, 8-PSK */
 const BitVector 
GSM::gRACHSynchSequenceTS2("11101111001001110101011000001101101110111");  /* 
EGPRS, GMSK */

+const BitVector 
GSM::gSCHSynchSequence("1011100101100010000001000000111100101101010001010111011000011011");
+
 //                               
|-head-||---------midamble----------------------||--------------data----------------||t|
 const BitVector 
GSM::gRACHBurst("0011101001001011011111111001100110101010001111000110111101111110000111001001010110011000");

diff --git a/GSM/GSMCommon.h b/GSM/GSMCommon.h
index 48723b4..aa059c2 100644
--- a/GSM/GSMCommon.h
+++ b/GSM/GSMCommon.h
@@ -52,11 +52,16 @@

 /** C0T0 filler burst, GSM 05.02, 5.2.6 */
 extern const BitVector gDummyBurst;
+extern const BitVector gDummyBurstTSC;

 /** Random access burst synch. sequence */
 extern const BitVector gRACHSynchSequenceTS0;
 extern const BitVector gRACHSynchSequenceTS1;
 extern const BitVector gRACHSynchSequenceTS2;
+
+/** Synchronization burst sync sequence */
+extern const BitVector gSCHSynchSequence;
+
 /** Random access burst synch. sequence, GSM 05.02 5.2.7 */
 extern const BitVector gRACHBurst;

diff --git a/Transceiver52M/Resampler.cpp b/Transceiver52M/Resampler.cpp
index 910c7ff..841c3a9 100644
--- a/Transceiver52M/Resampler.cpp
+++ b/Transceiver52M/Resampler.cpp
@@ -32,7 +32,7 @@
 #define M_PI                   3.14159265358979323846264338327f
 #endif

-#define MAX_OUTPUT_LEN         4096
+#define MAX_OUTPUT_LEN         4096*4

 using namespace std;

diff --git a/Transceiver52M/ms/ms_rx_lower.cpp 
b/Transceiver52M/ms/ms_rx_lower.cpp
index c2adda3..d894e96 100644
--- a/Transceiver52M/ms/ms_rx_lower.cpp
+++ b/Transceiver52M/ms/ms_rx_lower.cpp
@@ -19,6 +19,8 @@
  *
  */

+#include "sigProcLib.h"
+#include "signalVector.h"
 #include <atomic>
 #include <cassert>
 #include <complex>
@@ -155,12 +157,12 @@
        auto current_gsm_time = timekeeper.gsmtime();
        const auto buf_len = is_first_sch_acq ? SCH_LEN_SPS : ONE_TS_BURST_LEN;
        const auto which_in_buffer = is_first_sch_acq ? first_sch_buf : 
burst_copy_buffer;
+       memset((void *)&sch_acq_buffer[0], 0, sizeof(sch_acq_buffer));
+#if 1
        const auto which_out_buffer = is_first_sch_acq ? sch_acq_buffer : 
&sch_acq_buffer[40 * 2];
        const auto ss = reinterpret_cast<std::complex<float> 
*>(which_out_buffer);
        std::complex<float> channel_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
-
        int start;
-       memset((void *)&sch_acq_buffer[0], 0, sizeof(sch_acq_buffer));
        convert_and_scale(which_out_buffer, which_in_buffer, buf_len * 2, 1.f / 
float(rxFullScale));
        if (is_first_sch_acq) {
                float max_corr = 0;
@@ -173,9 +175,22 @@
        detect_burst_nb(&ss[start], &channel_imp_resp[0], 0, sch_demod_bits);

        auto sch_decode_success = decode_sch(sch_demod_bits, is_first_sch_acq);
+#if 0
+       auto burst = new signalVector(buf_len, 50);
+       const auto corr_type = is_first_sch_acq ? 
sch_detect_type::SCH_DETECT_BUFFER : sch_detect_type::SCH_DETECT_FULL;
+       struct estim_burst_params ebp;

+       // scale like uhd, +-2k -> +-32k
+       convert_and_scale(burst->begin(), which_in_buffer, buf_len * 2, 
SAMPLE_SCALE_FACTOR);
+
+       auto rv = detectSCHBurst(*burst, 4, 4, corr_type, &ebp);
+
+       int howmuchdelay = ebp.toa * 4;
+       std::cerr << "ooffs: " << howmuchdelay << " " << std::endl;
+       std::cerr << "voffs: " << start << " " << sch_decode_success << 
std::endl;
+#endif
        if (sch_decode_success) {
-               const auto ts_offset_symb = 0;
+               const auto ts_offset_symb = 4;
                if (is_first_sch_acq) {
                        // update ts to first sample in sch buffer, to allow 
delay calc for current ts
                        first_sch_ts_start = first_sch_buf_rcv_ts + start - 
(ts_offset_symb * 4) - 1;
@@ -190,6 +205,97 @@
                DBGLG2() << "L SCH : \x1B[31m decode fail \033[0m @ toa:" << 
start << " " << current_gsm_time.FN()
                         << ":" << current_gsm_time.TN() << std::endl;
        }
+#else
+       const auto ts_offset_symb = 4;
+       auto burst = new signalVector(buf_len, 50);
+       const auto corr_type = is_first_sch_acq ? 
sch_detect_type::SCH_DETECT_BUFFER : sch_detect_type::SCH_DETECT_FULL;
+       struct estim_burst_params ebp;
+
+       // scale like uhd, +-2k -> +-32k
+       convert_and_scale(burst->begin(), which_in_buffer, buf_len * 2, 
SAMPLE_SCALE_FACTOR);
+
+       auto rv = detectSCHBurst(*burst, 4, 4, corr_type, &ebp);
+
+       int howmuchdelay = ebp.toa * 4;
+
+       if (!rv) {
+               delete burst;
+               DBGLG() << "SCH : \x1B[31m detect fail \033[0m 
NOOOOOOOOOOOOOOOOOO toa:" << ebp.toa << " "
+                       << current_gsm_time.FN() << ":" << 
current_gsm_time.TN() << std::endl;
+               return false;
+       }
+
+       SoftVector *bits;
+       if (is_first_sch_acq) {
+               // can't be legit with a buf size spanning _at least_ one SCH 
but delay that implies partial sch burst
+               if (howmuchdelay < 0 || (buf_len - howmuchdelay) < 
ONE_TS_BURST_LEN) {
+                       delete burst;
+                       return false;
+               }
+
+               struct estim_burst_params ebp2;
+               // auto sch_chunk = new signalVector(ONE_TS_BURST_LEN, 50);
+               // auto sch_chunk_start = sch_chunk->begin();
+               // memcpy(sch_chunk_start, sch_buf_f.data() + howmuchdelay, 
sizeof(std::complex<float>) * ONE_TS_BURST_LEN);
+
+               auto delay = delayVector(burst, NULL, -howmuchdelay);
+
+               scaleVector(*delay, (complex)1.0 / ebp.amp);
+
+               auto rv2 = detectSCHBurst(*delay, 4, 4, 
sch_detect_type::SCH_DETECT_FULL, &ebp2);
+               DBGLG() << "FIRST SCH : " << (rv2 ? "yes " : "   ") << "Timing 
offset     " << ebp2.toa << " symbols"
+                       << std::endl;
+
+               bits = demodAnyBurst(*delay, SCH, 4, &ebp2);
+               delete delay;
+       } else {
+               bits = demodAnyBurst(*burst, SCH, 4, &ebp);
+       }
+
+       delete burst;
+
+       // clamp to +-1.5 because +-127 softbits scaled by 64 after -0.5 can be 
at most +-1.5
+       clamp_array(bits->begin(), 148, 1.5f);
+
+       float_to_sbit(&bits->begin()[0], (signed char *)&sch_demod_bits[0], 62, 
148);
+       // float_to_sbit(&bits->begin()[106], &data[39], 62, 39);
+
+       if (decode_sch((char *)sch_demod_bits, is_first_sch_acq)) {
+               auto current_gsm_time_updated = timekeeper.gsmtime();
+               if (is_first_sch_acq) {
+                       // update ts to first sample in sch buffer, to allow 
delay calc for current ts
+                       first_sch_ts_start = first_sch_buf_rcv_ts + 
howmuchdelay - (ts_offset_symb * 4);
+               } else {
+                       // continuous sch tracking, only update if off too much
+                       auto diff = [](float x, float y) { return x > y ? x - y 
: y - x; };
+
+                       auto d = diff(ebp.toa, ts_offset_symb);
+                       if (abs(d) > 0.3) {
+                               if (ebp.toa < ts_offset_symb)
+                                       ebp.toa = d;
+                               else
+                                       ebp.toa = -d;
+                               temp_ts_corr_offset += ebp.toa * 4;
+
+                               DBGLG() << "offs: " << ebp.toa << " " << 
temp_ts_corr_offset << std::endl;
+                       }
+               }
+
+               auto a = gsm_sch_check_fn(current_gsm_time_updated.FN() - 1);
+               auto b = gsm_sch_check_fn(current_gsm_time_updated.FN());
+               auto c = gsm_sch_check_fn(current_gsm_time_updated.FN() + 1);
+               DBGLG() << "L SCH : Timing offset     " << rv << " " << ebp.toa 
<< " " << a << b << c << "fn "
+                       << current_gsm_time_updated.FN() << ":" << 
current_gsm_time_updated.TN() << std::endl;
+
+               delete bits;
+               return true;
+       } else {
+               DBGLG2() << "L SCH : \x1B[31m decode fail \033[0m @ toa:" << 
ebp.toa << " " << current_gsm_time.FN()
+                        << ":" << current_gsm_time.TN() << std::endl;
+       }
+
+       delete bits;
+#endif
        return false;
 }

diff --git a/Transceiver52M/ms/ms_upper.cpp b/Transceiver52M/ms/ms_upper.cpp
index c5664cd..2e8bc11 100644
--- a/Transceiver52M/ms/ms_upper.cpp
+++ b/Transceiver52M/ms/ms_upper.cpp
@@ -199,6 +199,7 @@
                return true;
        }

+#if 1
        convert_and_scale(ss, e.burst, ONE_TS_BURST_LEN * 2, 1.f / 
float(rxFullScale));

        pow = energyDetect(sv, 20 * 4 /*sps*/);
@@ -232,6 +233,42 @@
                //      detect_burst(ss, &chan_imp_resp2[0], dummy_burst_start, 
outbin);
 #endif
        }
+#else
+
+       // lower layer sch detection offset, easy to verify by just printing 
the detected value using both the va+sigproc code.
+       convert_and_scale(ss + 16, e.burst, ONE_TS_BURST_LEN * 2, 15);
+
+       pow = energyDetect(sv, 20 * 4 /*sps*/);
+       if (pow < -1) {
+               LOG(ALERT) << "Received empty burst";
+               return false;
+       }
+
+       avg = sqrt(pow);
+
+       /* Detect normal or RACH bursts */
+       CorrType type = CorrType::TSC;
+       struct estim_burst_params ebp;
+       auto rc = detectAnyBurst(sv, mTSC, 3, 4, type, 48, &ebp);
+       if (rc > 0) {
+               type = (CorrType)rc;
+       }
+
+       if (rc < 0) {
+               std::cerr << "UR : \x1B[31m rx fail \033[0m @ toa:" << ebp.toa 
<< " " << e.gsmts.FN() << ":"
+                         << e.gsmts.TN() << std::endl;
+               return false;
+       }
+       SoftVector *bits = demodAnyBurst(sv, type, 4, &ebp);
+
+       SoftVector::const_iterator burstItr = bits->begin();
+       // invert and fix to +-127 sbits
+       for (int ii = 0; ii < 148; ii++) {
+               demodded_softbits[ii] = *burstItr++ > 0.0f ? -127 : 127;
+       }
+       delete bits;
+
+#endif
        RSSI = (int)floor(20.0 * log10(rxFullScale / avg));
        // FIXME: properly handle offset, sch/nb alignment diff? handled by 
lower anyway...
        timingOffset = (int)round(0);
diff --git a/Transceiver52M/sigProcLib.cpp b/Transceiver52M/sigProcLib.cpp
index df87f94..5fac365 100644
--- a/Transceiver52M/sigProcLib.cpp
+++ b/Transceiver52M/sigProcLib.cpp
@@ -129,6 +129,8 @@
 static CorrelationSequence *gMidambles[] = 
{NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
 static CorrelationSequence *gEdgeMidambles[] = 
{NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
 static CorrelationSequence *gRACHSequences[] = {NULL,NULL,NULL};
+static CorrelationSequence *gSCHSequence = NULL;
+static CorrelationSequence *gDummySequence = NULL;
 static PulseSequence *GSMPulse1 = NULL;
 static PulseSequence *GSMPulse4 = NULL;

@@ -151,6 +153,12 @@
     gRACHSequences[i] = NULL;
   }

+  delete gSCHSequence;
+  gSCHSequence = NULL;
+
+  delete gDummySequence;
+  gDummySequence = NULL;
+
   delete GMSKRotation1;
   delete GMSKReverseRotation1;
   delete GMSKRotation4;
@@ -315,6 +323,7 @@
     append = true;
     break;
   case CUSTOM:
+  // FIXME: x->getstart?
     if (start < h->size() - 1) {
       head = h->size() - start;
       append = true;
@@ -1289,6 +1298,77 @@
   return status;
 }

+static bool generateDummyMidamble(int sps)
+{
+  bool status = true;
+  float toa;
+  complex *data = NULL;
+  signalVector *autocorr = NULL, *midamble = NULL;
+  signalVector *midMidamble = NULL, *_midMidamble = NULL;
+
+  delete gDummySequence;
+
+  /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped 
*/
+  midMidamble = modulateBurst(gDummyBurstTSC.segment(5,16), 0, sps, true);
+  if (!midMidamble)
+    return false;
+
+  /* Simulated receive sequence is pulse shaped */
+  midamble = modulateBurst(gDummyBurstTSC, 0, sps, false);
+  if (!midamble) {
+    status = false;
+    goto release;
+  }
+
+  // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
+  //       the ideal TSC has an + 180 degree phase shift,
+  //       due to the pi/2 frequency shift, that
+  //       needs to be accounted for.
+  //       26-midamble is 61 symbols into burst, has +90 degree phase shift.
+  scaleVector(*midMidamble, complex(-1.0, 0.0));
+  scaleVector(*midamble, complex(0.0, 1.0));
+
+  conjugateVector(*midMidamble);
+
+  /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
+  data = (complex *) convolve_h_alloc(midMidamble->size());
+  _midMidamble = new signalVector(data, 0, midMidamble->size(), 
convolve_h_alloc, free);
+  _midMidamble->setAligned(true);
+  midMidamble->copyTo(*_midMidamble);
+
+  autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
+  if (!autocorr) {
+    status = false;
+    goto release;
+  }
+
+  gDummySequence = new CorrelationSequence;
+  gDummySequence->sequence = _midMidamble;
+  gDummySequence->gain = peakDetect(*autocorr, &toa, NULL);
+
+  /* For 1 sps only
+   *     (Half of correlation length - 1) + midpoint of pulse shape + remainder
+   *     13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
+   */
+  if (sps == 1)
+    gDummySequence->toa = toa - 13.5;
+  else
+    gDummySequence->toa = 0;
+
+release:
+  delete autocorr;
+  delete midamble;
+  delete midMidamble;
+
+  if (!status) {
+    delete _midMidamble;
+    free(data);
+    gDummySequence = NULL;
+  }
+
+  return status;
+}
+
 static CorrelationSequence *generateEdgeMidamble(int tsc)
 {
   complex *data = NULL;
@@ -1384,6 +1464,69 @@
   return status;
 }

+bool generateSCHSequence(int sps)
+{
+  bool status = true;
+  float toa;
+  complex *data = NULL;
+  signalVector *autocorr = NULL;
+  signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
+
+  delete gSCHSequence;
+
+  seq0 = modulateBurst(gSCHSynchSequence, 0, sps, false);
+  if (!seq0)
+    return false;
+
+  seq1 = modulateBurst(gSCHSynchSequence, 0, sps, true);
+  if (!seq1) {
+    status = false;
+    goto release;
+  }
+
+  conjugateVector(*seq1);
+
+  /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
+  data = (complex *) convolve_h_alloc(seq1->size());
+  _seq1 = new signalVector(data, 0, seq1->size(), convolve_h_alloc, free);
+  _seq1->setAligned(true);
+  seq1->copyTo(*_seq1);
+
+  autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
+  if (!autocorr) {
+    status = false;
+    goto release;
+  }
+
+  gSCHSequence = new CorrelationSequence;
+  gSCHSequence->sequence = _seq1;
+  gSCHSequence->buffer = data;
+  gSCHSequence->gain = peakDetect(*autocorr, &toa, NULL);
+
+  /* For 1 sps only
+   *     (Half of correlation length - 1) + midpoint of pulse shaping filer
+   *     20.5 = (64 / 2 - 1) + 1.5
+   */
+  if (sps == 1)
+    gSCHSequence->toa = toa - 32.5;
+  else
+    gSCHSequence->toa = 0.0;
+
+release:
+  delete autocorr;
+  delete seq0;
+  delete seq1;
+
+  if (!status) {
+    delete _seq1;
+    free(data);
+    gSCHSequence = NULL;
+  }
+
+  return status;
+}
+
+
 /*
  * Peak-to-average computation +/- range from peak in symbols
  */
@@ -1441,14 +1584,15 @@
   return energy/windowLength;
 }

-static signalVector *downsampleBurst(const signalVector &burst)
+static signalVector *downsampleBurst(const signalVector &burst, int in_len = 
DOWNSAMPLE_IN_LEN,
+                                    int out_len = DOWNSAMPLE_OUT_LEN)
 {
-  signalVector in(DOWNSAMPLE_IN_LEN, dnsampler->len());
-  signalVector *out = new signalVector(DOWNSAMPLE_OUT_LEN);
-  burst.copyToSegment(in, 0, DOWNSAMPLE_IN_LEN);
+  signalVector in(in_len, dnsampler->len());
+  // gSCHSequence->sequence->size(), ensure next conv has no realloc
+  signalVector *out = new signalVector(out_len, 64);
+  burst.copyToSegment(in, 0, in_len);

-  if (dnsampler->rotate((float *) in.begin(), DOWNSAMPLE_IN_LEN,
-                        (float *) out->begin(), DOWNSAMPLE_OUT_LEN) < 0) {
+  if (dnsampler->rotate((float *)in.begin(), in_len, (float *)out->begin(), 
out_len) < 0) {
     delete out;
     out = NULL;
   }
@@ -1469,6 +1613,12 @@
   /* Integer position where the sequence starts */
   const int ps = start + 1 - N + (int)roundf(toa);

+  if(ps < 0) // might be -22 for toa 40 with N=64, if off by a lot during sch 
ms sync
+    return 0;
+
+  if (ps + N > (int)burst->size())
+         return 0;
+
   /* Estimate Signal power */
   S = 0.0f;
   for (int i=0, j=ps; i<(int)N; i++,j++)
@@ -1652,6 +1802,80 @@
   return rc;
 }

+int detectSCHBurst(signalVector &burst,
+                   float thresh,
+                   int sps,
+        sch_detect_type state, struct estim_burst_params *ebp)
+{
+  int rc, start, target, head, tail, len;
+  complex _amp;
+  CorrelationSequence *sync;
+
+  if ((sps != 1) && (sps != 4))
+    return -1;
+
+  target = 3 + 39 + 64;
+
+  switch (state) {
+  case sch_detect_type::SCH_DETECT_NARROW:
+    head = 4;
+    tail = 4;
+    break;
+  case sch_detect_type::SCH_DETECT_BUFFER:
+         target = 1;
+         head = 0;
+         tail = (12 * 8 * 625) / 4; // 12 frames, downsampled /4 to 1 sps
+         break;
+  case sch_detect_type::SCH_DETECT_FULL:
+  default:
+    head = target - 1;
+    tail = 39 + 3 + 9;
+    break;
+  }
+
+  start = (target - head) * 1 - 1;
+  len = (head + tail) * 1;
+  sync = gSCHSequence;
+  signalVector corr(len);
+
+  signalVector *dec = downsampleBurst(burst, len * 4, len);
+  rc = detectBurst(*dec, corr, sync, thresh, 1, start, len, ebp);
+  delete dec;
+
+  if (rc < 0) {
+    return -1;
+  } else if (!rc) {
+      ebp->amp = 0.0f;
+      ebp->toa = 0.0f;
+    return 0;
+  }
+
+  if (state == sch_detect_type::SCH_DETECT_BUFFER)
+         ebp->toa = ebp->toa - (3 + 39 + 64);
+  else {
+         /* Subtract forward search bits from delay */
+         ebp->toa = ebp->toa - head;
+  }
+
+  return rc;
+}
+
+static int detectDummyBurst(const signalVector &burst, float threshold,
+                               int sps, unsigned max_toa, struct 
estim_burst_params *ebp)
+{
+  int rc, target, head, tail;
+  CorrelationSequence *sync;
+
+  target = 3 + 58 + 16 + 5;
+  head = 10;
+  tail = 6 + max_toa;
+  sync = gDummySequence;
+
+  ebp->tsc = 0;
+  rc = detectGeneralBurst(burst, threshold, sps, target, head, tail, sync, 
ebp);
+  return rc;
+}
+
 /*
  * Normal burst detection
  *
@@ -1670,7 +1894,7 @@
     return -SIGERR_UNSUPPORTED;

   target = 3 + 58 + 16 + 5;
-  head = 6;
+  head = 10;
   tail = 6 + max_toa;
   sync = gMidambles[tsc];

@@ -1719,6 +1943,9 @@
   case RACH:
     rc = detectRACHBurst(burst, threshold, sps, max_toa, type == EXT_RACH, 
ebp);
     break;
+  case IDLE:
+    rc = detectDummyBurst(burst, threshold, sps, max_toa, ebp);
+    break;
   default:
     LOG(ERR) << "Invalid correlation type";
   }
@@ -1921,6 +2148,9 @@
   generateRACHSequence(&gRACHSequences[1], gRACHSynchSequenceTS1, 1);
   generateRACHSequence(&gRACHSequences[2], gRACHSynchSequenceTS2, 1);

+  generateSCHSequence(1);
+  generateDummyMidamble(1);
+
   for (int tsc = 0; tsc < 8; tsc++) {
     generateMidamble(1, tsc);
     gEdgeMidambles[tsc] = generateEdgeMidamble(tsc);
diff --git a/Transceiver52M/sigProcLib.h b/Transceiver52M/sigProcLib.h
index 0c3c7c6..39c8ddd 100644
--- a/Transceiver52M/sigProcLib.h
+++ b/Transceiver52M/sigProcLib.h
@@ -31,6 +31,7 @@
   TSC,         ///< timeslot should contain a normal burst
   EXT_RACH,    ///< timeslot should contain an extended access burst
   RACH,        ///< timeslot should contain an access burst
+  SCH,
   EDGE,        ///< timeslot should contain an EDGE burst
   IDLE         ///< timeslot is an idle (or dummy) burst
 };
@@ -93,6 +94,8 @@
 void scaleVector(signalVector &x,
                  complex scale);

+signalVector *delayVector(const signalVector *in, signalVector *out, float 
delay);
+
 /**
         Rough energy estimator.
         @param rxBurst A GSM burst.
@@ -133,6 +136,17 @@
                    unsigned max_toa,
                    struct estim_burst_params *ebp);

+enum class sch_detect_type {
+       SCH_DETECT_FULL,
+       SCH_DETECT_NARROW,
+       SCH_DETECT_BUFFER,
+};
+
+int detectSCHBurst(signalVector &rxBurst,
+                    float detectThreshold,
+                    int sps,
+                    sch_detect_type state, struct estim_burst_params *ebp);
+
 /** Demodulate burst basde on type and output soft bits */
 SoftVector *demodAnyBurst(const signalVector &burst, CorrType type,
                           int sps, struct estim_burst_params *ebp);

--
To view, visit https://gerrit.osmocom.org/c/osmo-trx/+/36046?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-trx
Gerrit-Branch: master
Gerrit-Change-Id: I6558992bd69f18526be5ebe7d424ca00ceb67772
Gerrit-Change-Number: 36046
Gerrit-PatchSet: 2
Gerrit-Owner: Hoernchen <[email protected]>
Gerrit-Reviewer: Hoernchen <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-Reviewer: pespin <[email protected]>
Gerrit-MessageType: merged

Reply via email to