ms: restructure the va code to add rach support

This commit adds support for rach bursts to the viterbi equalizer, which
is currently only being used by the ms side, so the equalizer can be used
by the osmo-trx network side, too. The difference is that rach bursts are
shorter than any other burst type (due to unknown TA) and start with
diffrent tail bits.

This drops the multiversioning which was only working for x86 anyway because
it can't be combined with no_ubsan.

Change-Id: I4a5cedc8c9a3289c75ce7b914eac286e601ebed0
diff --git a/Transceiver52M/grgsm_vitac/constants.h b/Transceiver52M/grgsm_vitac/constants.h
index 07f2290..27bf6f4 100644
--- a/Transceiver52M/grgsm_vitac/constants.h
+++ b/Transceiver52M/grgsm_vitac/constants.h
@@ -38,6 +38,7 @@
 #define STEALING_BIT      1
 #define N_TRAIN_BITS      26
 #define N_SYNC_BITS       64
+#define N_ACCESS_BITS     41
 #define USEFUL_BITS       142  //(2*(DATA_BITS+STEALING_BIT) + N_TRAIN_BITS )
 #define FCCH_BITS         USEFUL_BITS
 #define BURST_SIZE        (USEFUL_BITS+2*TAIL_BITS)
@@ -73,6 +74,12 @@
   0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1
 };
 
+static const unsigned char ACCESS_BITS [] = {
+ 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0,
+ 0, 1, 1, 1, 1, 0, 0, 0
+};
+
 const unsigned FCCH_FRAMES[] = { 0, 10, 20, 30, 40 };
 const unsigned SCH_FRAMES[] = { 1, 11, 21, 31, 41 };
 
diff --git a/Transceiver52M/grgsm_vitac/grgsm_vitac.cpp b/Transceiver52M/grgsm_vitac/grgsm_vitac.cpp
index 836c555..5779d9d 100644
--- a/Transceiver52M/grgsm_vitac/grgsm_vitac.cpp
+++ b/Transceiver52M/grgsm_vitac/grgsm_vitac.cpp
@@ -39,13 +39,13 @@
 #include "viterbi_detector.h"
 #include "grgsm_vitac.h"
 
-//signalVector mChanResp;
+gr_complex d_acc_training_seq[N_ACCESS_BITS]; ///<encoded training sequence of a RACH burst
 gr_complex d_sch_training_seq[N_SYNC_BITS]; ///<encoded training sequence of a SCH burst
 gr_complex d_norm_training_seq[TRAIN_SEQ_NUM][N_TRAIN_BITS]; ///<encoded training sequences of a normal and dummy burst
 const int d_chan_imp_length = CHAN_IMP_RESP_LENGTH;
 
-void initvita() {
-
+void initvita()
+{
 	/**
 	 * Prepare SCH sequence bits
 	 *
@@ -53,59 +53,72 @@
 	 * Burst and two guard periods
 	 * (one guard period is an arbitrary overlap)
 	 */
-	gmsk_mapper(SYNC_BITS, N_SYNC_BITS,
-		d_sch_training_seq, gr_complex(0.0, -1.0));
+	gmsk_mapper(SYNC_BITS, N_SYNC_BITS, d_sch_training_seq, gr_complex(0.0, -1.0));
 	for (auto &i : d_sch_training_seq)
 		i = conj(i);
 
+	/* ab */
+	gmsk_mapper(ACCESS_BITS, N_ACCESS_BITS, d_acc_training_seq, gr_complex(0.0, -1.0));
+	for (auto &i : d_acc_training_seq)
+		i = conj(i);
+
 	/* Prepare bits of training sequences */
 	for (int i = 0; i < TRAIN_SEQ_NUM; i++) {
 		/**
 		 * If first bit of the sequence is 0
 		 * => first symbol is 1, else -1
 		 */
-		gr_complex startpoint = train_seq[i][0] == 0 ?
-			gr_complex(1.0, 0.0) : gr_complex(-1.0, 0.0);
-		gmsk_mapper(train_seq[i], N_TRAIN_BITS,
-			d_norm_training_seq[i], startpoint);
+		gr_complex startpoint = train_seq[i][0] == 0 ? gr_complex(1.0, 0.0) : gr_complex(-1.0, 0.0);
+		gmsk_mapper(train_seq[i], N_TRAIN_BITS, d_norm_training_seq[i], startpoint);
 		for (auto &i : d_norm_training_seq[i])
 			i = conj(i);
 	}
-
 }
 
-MULTI_VER_TARGET_ATTR NO_UBSAN
-void detect_burst(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary)
+template <unsigned int burst_size>
+NO_UBSAN static void detect_burst_generic(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start,
+					  char *output_binary, int ss)
 {
 	std::vector<gr_complex> rhh_temp(CHAN_IMP_RESP_LENGTH * d_OSR);
 	unsigned int stop_states[2] = { 4, 12 };
-	gr_complex filtered_burst[BURST_SIZE];
+	gr_complex filtered_burst[burst_size];
 	gr_complex rhh[CHAN_IMP_RESP_LENGTH];
-	float output[BURST_SIZE];
-	int start_state = 3;
-
-	// if(burst_start < 0 ||burst_start > 10)
-	// 	fprintf(stderr, "bo %d\n", burst_start);
-
-	// burst_start = burst_start >= 0 ? burst_start : 0;
+	float output[burst_size];
+	int start_state = ss;
 
 	autocorrelation(chan_imp_resp, &rhh_temp[0], d_chan_imp_length * d_OSR);
 	for (int ii = 0; ii < d_chan_imp_length; ii++)
 		rhh[ii] = conj(rhh_temp[ii * d_OSR]);
 
-	mafi(&input[burst_start], BURST_SIZE, chan_imp_resp,
-		d_chan_imp_length * d_OSR, filtered_burst);
+	mafi(&input[burst_start], burst_size, chan_imp_resp, d_chan_imp_length * d_OSR, filtered_burst);
 
-	viterbi_detector(filtered_burst, BURST_SIZE, rhh,
-		start_state, stop_states, 2, output);
+	viterbi_detector(filtered_burst, burst_size, rhh, start_state, stop_states, 2, output);
 
-	for (int i = 0; i < BURST_SIZE; i++)
-		output_binary[i] = output[i] * -127; // pre flip bits!
+	for (unsigned int i = 0; i < burst_size; i++)
+		output_binary[i] = (char)(output[i] * -127); // pre flip bits!
 }
 
-void
-gmsk_mapper(const unsigned char* input,
-	int nitems, gr_complex* gmsk_output, gr_complex start_point)
+NO_UBSAN void detect_burst_nb(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary,
+			      int ss)
+{
+	return detect_burst_generic<BURST_SIZE>(input, chan_imp_resp, burst_start, output_binary, ss);
+}
+NO_UBSAN void detect_burst_ab(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary,
+			      int ss)
+{
+	return detect_burst_generic<8 + 41 + 36 + 3>(input, chan_imp_resp, burst_start, output_binary, ss);
+}
+
+NO_UBSAN void detect_burst_nb(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary)
+{
+	return detect_burst_nb(input, chan_imp_resp, burst_start, output_binary, 3);
+}
+NO_UBSAN void detect_burst_ab(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary)
+{
+	return detect_burst_ab(input, chan_imp_resp, burst_start, output_binary, 3);
+}
+
+void gmsk_mapper(const unsigned char *input, int nitems, gr_complex *gmsk_output, gr_complex start_point)
 {
 	gr_complex j = gr_complex(0.0, 1.0);
 	gmsk_output[0] = start_point;
@@ -122,16 +135,13 @@
 		encoded_symbol = current_symbol * previous_symbol;
 
 		/* And do GMSK mapping */
-		gmsk_output[i] = j * gr_complex(encoded_symbol, 0.0)
-			* gmsk_output[i - 1];
+		gmsk_output[i] = j * gr_complex(encoded_symbol, 0.0) * gmsk_output[i - 1];
 
 		previous_symbol = current_symbol;
 	}
 }
 
-gr_complex
-correlate_sequence(const gr_complex* sequence,
-	int length, const gr_complex* input)
+gr_complex correlate_sequence(const gr_complex *sequence, int length, const gr_complex *input)
 {
 	gr_complex result(0.0, 0.0);
 
@@ -142,9 +152,7 @@
 }
 
 /* Computes autocorrelation for positive arguments */
-inline void
-autocorrelation(const gr_complex* input,
-	gr_complex* out, int nitems)
+inline void autocorrelation(const gr_complex *input, gr_complex *out, int nitems)
 {
 	for (int k = nitems - 1; k >= 0; k--) {
 		out[k] = gr_complex(0, 0);
@@ -153,9 +161,7 @@
 	}
 }
 
-inline void
-mafi(const gr_complex* input, int nitems,
-	gr_complex* filter, int filter_length, gr_complex* output)
+inline void mafi(const gr_complex *input, int nitems, gr_complex *filter, int filter_length, gr_complex *output)
 {
 	for (int n = 0; n < nitems; n++) {
 		int a = n * d_OSR;
@@ -170,66 +176,45 @@
 	}
 }
 
-int get_chan_imp_resp(const gr_complex *input, gr_complex *chan_imp_resp, int search_center, int search_start_pos,
-		      int search_stop_pos, gr_complex *tseq, int tseqlen, float *corr_max)
+int get_chan_imp_resp(const gr_complex *input, gr_complex *chan_imp_resp, int search_start_pos, int search_stop_pos,
+		      gr_complex *tseq, int tseqlen, float *corr_max)
 {
-	std::vector<gr_complex> correlation_buffer;
+	const int num_search_windows = search_stop_pos - search_start_pos;
+	const int power_search_window_len = d_chan_imp_length * d_OSR;
 	std::vector<float> window_energy_buffer;
 	std::vector<float> power_buffer;
+	std::vector<gr_complex> correlation_buffer;
 
-	for (int ii = search_start_pos; ii < search_stop_pos; ii++) {
-		gr_complex correlation = correlate_sequence(tseq, tseqlen, &input[ii]);
+	power_buffer.reserve(num_search_windows);
+	correlation_buffer.reserve(num_search_windows);
+	window_energy_buffer.reserve(num_search_windows);
+
+	for (int ii = 0; ii < num_search_windows; ii++) {
+		gr_complex correlation = correlate_sequence(tseq, tseqlen, &input[search_start_pos + ii]);
 		correlation_buffer.push_back(correlation);
 		power_buffer.push_back(std::pow(abs(correlation), 2));
 	}
 
-	int strongest_corr_nr = max_element(power_buffer.begin(), power_buffer.end()) - power_buffer.begin();
-
 	/* Compute window energies */
-	auto window_energy_start_offset = strongest_corr_nr - 6 * d_OSR;
-	window_energy_start_offset = window_energy_start_offset < 0 ? 0 : window_energy_start_offset; //can end up out of range..
-	auto window_energy_end_offset = strongest_corr_nr + 6 * d_OSR + d_chan_imp_length * d_OSR;
-	auto iter = power_buffer.begin() + window_energy_start_offset;
-	auto iter_end = power_buffer.begin() + window_energy_end_offset;
-	while (iter != iter_end) {
-		std::vector<float>::iterator iter_ii = iter;
-		bool loop_end = false;
-		float energy = 0;
+	float windowSum = 0;
 
-		int len = d_chan_imp_length * d_OSR;
-		for (int ii = 0; ii < len; ii++, iter_ii++) {
-			if (iter_ii == power_buffer.end()) {
-				loop_end = true;
-				break;
-			}
+	// first window
+	for (int i = 0; i < power_search_window_len; i++) {
+		windowSum += power_buffer[i];
+	}
+	window_energy_buffer.push_back(windowSum);
 
-			energy += (*iter_ii);
-		}
-
-		if (loop_end)
-			break;
-
-		window_energy_buffer.push_back(energy);
-		iter++;
+	// slide windows
+	for (int i = power_search_window_len; i < num_search_windows; i++) {
+		windowSum += power_buffer[i] - power_buffer[i - power_search_window_len];
+		window_energy_buffer.push_back(windowSum);
 	}
 
-	/* Calculate the strongest window number */
-	int strongest_window_nr = window_energy_start_offset +
-				  max_element(window_energy_buffer.begin(), window_energy_buffer.end()) -
+	int strongest_window_nr = std::max_element(window_energy_buffer.begin(), window_energy_buffer.end()) -
 				  window_energy_buffer.begin();
 
-	// auto window_search_start = window_energy_buffer.begin() + strongest_corr_nr - 5* d_OSR;
-	// auto window_search_end = window_energy_buffer.begin() + strongest_corr_nr + 10* d_OSR;
-	// window_search_end = window_search_end >= window_energy_buffer.end() ? window_energy_buffer.end() : window_search_end;
-
-	// /* Calculate the strongest window number */
-	// int strongest_window_nr = max_element(window_search_start, window_search_end /* - d_chan_imp_length * d_OSR*/) - window_energy_buffer.begin();
-
-	// if (strongest_window_nr < 0)
-	// 	strongest_window_nr = 0;
-
 	float max_correlation = 0;
-	for (int ii = 0; ii < d_chan_imp_length * d_OSR; ii++) {
+	for (int ii = 0; ii < power_search_window_len; ii++) {
 		gr_complex correlation = correlation_buffer[strongest_window_nr + ii];
 		if (abs(correlation) > max_correlation)
 			max_correlation = abs(correlation);
@@ -242,7 +227,27 @@
 	 * Compute first sample position, which corresponds
 	 * to the first sample of the impulse response
 	 */
-	return search_start_pos + strongest_window_nr - search_center * d_OSR;
+	return search_start_pos + strongest_window_nr;
+}
+
+/*
+8 ext tail bits
+41 sync seq
+36 encrypted bits
+3 tail bits
+68.25 extended tail bits (!)
+
+center at 8+5 (actually known tb -> known isi, start at 8?) FIXME
+*/
+int get_access_imp_resp(const gr_complex *input, gr_complex *chan_imp_resp, float *corr_max, int max_delay)
+{
+	const int search_center = 8 + 5;
+	const int search_start_pos = (search_center - 5) * d_OSR + 1;
+	const int search_stop_pos = (search_center + 5 + d_chan_imp_length + max_delay) * d_OSR;
+	const auto tseq = &d_acc_training_seq[TRAIN_BEGINNING];
+	const auto tseqlen = N_ACCESS_BITS - (2 * TRAIN_BEGINNING);
+	return get_chan_imp_resp(input, chan_imp_resp, search_start_pos, search_stop_pos, tseq, tseqlen, corr_max) -
+	       search_center * d_OSR;
 }
 
 /*
@@ -260,8 +265,8 @@
 	const int search_stop_pos = (search_center + 5 + d_chan_imp_length) * d_OSR;
 	const auto tseq = &d_norm_training_seq[bcc][TRAIN_BEGINNING];
 	const auto tseqlen = N_TRAIN_BITS - (2 * TRAIN_BEGINNING);
-	return get_chan_imp_resp(input, chan_imp_resp, search_center, search_start_pos, search_stop_pos, tseq, tseqlen,
-				 corr_max);
+	return get_chan_imp_resp(input, chan_imp_resp, search_start_pos, search_stop_pos, tseq, tseqlen, corr_max) -
+	       search_center * d_OSR;
 }
 
 /*
@@ -281,8 +286,9 @@
 
 	// strongest_window_nr + chan_imp_resp_center + SYNC_POS *d_OSR - 48 * d_OSR - 2 * d_OSR + 2 ;
 	float corr_max;
-	return get_chan_imp_resp(input, chan_imp_resp, search_center, search_start_pos, search_stop_pos, tseq, tseqlen,
-				 &corr_max);
+	return get_chan_imp_resp(input, chan_imp_resp, search_start_pos, search_stop_pos, tseq, tseqlen, &corr_max) -
+	       search_center * d_OSR;
+	;
 }
 
 int get_sch_buffer_chan_imp_resp(const gr_complex *input, gr_complex *chan_imp_resp, unsigned int len, float *corr_max)
@@ -291,9 +297,9 @@
 	const int search_center = SYNC_POS + TRAIN_BEGINNING;
 	const int search_start_pos = 0;
 	// FIXME: proper end offset
-	const int search_stop_pos = len - (N_SYNC_BITS*8);
+	const int search_stop_pos = len - (N_SYNC_BITS * 8);
 	auto tseq = &d_sch_training_seq[TRAIN_BEGINNING];
 
-	return get_chan_imp_resp(input, chan_imp_resp, search_center, search_start_pos, search_stop_pos, tseq, tseqlen,
-				 corr_max);
+	return get_chan_imp_resp(input, chan_imp_resp, search_start_pos, search_stop_pos, tseq, tseqlen, corr_max) -
+	       search_center * d_OSR;
 }
\ No newline at end of file
diff --git a/Transceiver52M/grgsm_vitac/grgsm_vitac.h b/Transceiver52M/grgsm_vitac/grgsm_vitac.h
index 2c89d8c..d00c3ad 100644
--- a/Transceiver52M/grgsm_vitac/grgsm_vitac.h
+++ b/Transceiver52M/grgsm_vitac/grgsm_vitac.h
@@ -58,8 +58,11 @@
 int process_vita_burst(gr_complex *input, int tsc, unsigned char *output_binary);
 int process_vita_sc_burst(gr_complex *input, int tsc, unsigned char *output_binary, int *offset);
 
-MULTI_VER_TARGET_ATTR_CLANGONLY
-void detect_burst(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary);
+void detect_burst_nb(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary, int ss);
+void detect_burst_ab(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary, int ss);
+void detect_burst_nb(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary);
+void detect_burst_ab(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary);
+
 void gmsk_mapper(const unsigned char *input, int nitems, gr_complex *gmsk_output, gr_complex start_point);
 gr_complex correlate_sequence(const gr_complex *sequence, int length, const gr_complex *input);
 inline void autocorrelation(const gr_complex *input, gr_complex *out, int nitems);
@@ -67,6 +70,7 @@
 int get_sch_chan_imp_resp(const gr_complex *input, gr_complex *chan_imp_resp);
 int get_norm_chan_imp_resp(const gr_complex *input, gr_complex *chan_imp_resp, float *corr_max, int bcc);
 int get_sch_buffer_chan_imp_resp(const gr_complex *input, gr_complex *chan_imp_resp, unsigned int len, float *corr_max);
+int get_access_imp_resp(const gr_complex *input, gr_complex *chan_imp_resp, float *corr_max, int max_delay);
 
 enum class btype { NB, SCH };
 struct fdata {
diff --git a/Transceiver52M/ms/ms_rx_lower.cpp b/Transceiver52M/ms/ms_rx_lower.cpp
index 5a07df5..c2adda3 100644
--- a/Transceiver52M/ms/ms_rx_lower.cpp
+++ b/Transceiver52M/ms/ms_rx_lower.cpp
@@ -170,7 +170,7 @@
 		start = start < 39 ? start : 39;
 		start = start > -39 ? start : -39;
 	}
-	detect_burst(&ss[start], &channel_imp_resp[0], 0, sch_demod_bits);
+	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);
 
diff --git a/Transceiver52M/ms/ms_upper.cpp b/Transceiver52M/ms/ms_upper.cpp
index 0a2c333..3c34efe 100644
--- a/Transceiver52M/ms/ms_upper.cpp
+++ b/Transceiver52M/ms/ms_upper.cpp
@@ -196,7 +196,7 @@
 		// fprintf(stderr, "%s %d\n", (is_nb ? "N":"D"), burst_time.FN());
 		// if (is_nb)
 #endif
-		detect_burst(ss, &chan_imp_resp[0], normal_burst_start, demodded_softbits);
+		detect_burst_nb(ss, &chan_imp_resp[0], normal_burst_start, demodded_softbits);
 #ifdef DBGXX
 		// else
 		// 	detect_burst(ss, &chan_imp_resp2[0], dummy_burst_start, outbin);