changeset 300:edcb8364d45b

L1: resurrect TCH tap feature In this new incarnation of our TCH tap feature, we support DL sniffing in all 3 of FR1, HR1 and EFR, and the new implementation will capture every 20 ms frame where the old one silently skipped a frame (sent nothing) during FACCH stealing. The wire interface on RVTMUX changed slightly, and fc-shell tch record will need to be updated to support the new version. TCH UL play or substitution is supported for FR1 and EFR only; support for HR1 can be added later if needed.
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 13 Dec 2022 02:44:01 +0000
parents 91e61d00a6b5
children 4bb5772a05a3
files components/l1_ext src/cs/layer1/cfile/l1_cmplx.c src/cs/layer1/cfile/l1_init.c src/cs/layer1/cfile/l1_tch_tap.c src/cs/layer1/include/tch_tap_proto.h
diffstat 5 files changed, 217 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/components/l1_ext	Tue Mar 29 04:41:25 2022 +0000
+++ b/components/l1_ext	Tue Dec 13 02:44:01 2022 +0000
@@ -58,6 +58,7 @@
 cfile_plain $SRCDIR/cfile/l1_init.c
 cfile_plain $SRCDIR/cfile/l1_sync.c
 cfile_plain $SRCDIR/cfile/l1_cmplx.c
+cfile_plain $SRCDIR/cfile/l1_tch_tap.c
 
 cfile_plain $SRCDIR/tm_cfile/l1tm_async.c
 cfile_plain $SRCDIR/tm_cfile/l1tm_func.c
--- a/src/cs/layer1/cfile/l1_cmplx.c	Tue Mar 29 04:41:25 2022 +0000
+++ b/src/cs/layer1/cfile/l1_cmplx.c	Tue Dec 13 02:44:01 2022 +0000
@@ -233,6 +233,11 @@
   UWORD8 input_level_flag, UWORD8 input_level, UWORD16 radio_freq, UWORD8 if_threshold);
 #endif
 
+/* FreeCalypso added feature: TCH tap */
+extern BOOL tch_dl_sniff_mode, tch_ul_play_mode;
+extern void tch_send_downlink_bits(API *dsp_buffer, UWORD8 nwords,
+				   UWORD8 chan_mode, UWORD8 fn_mod_104);
+extern void tchf_substitute_uplink(API *dsp_buffer);
 
 //#pragma DUPLICATE_FOR_INTERNAL_RAM_END
 
@@ -5115,6 +5120,11 @@
           }
           #endif
         }
+        else if (tch_ul_play_mode &&
+                 (channel_mode == TCH_FS_MODE || channel_mode == TCH_EFR_MODE))
+        {
+          tchf_substitute_uplink(l1s_dsp_com.dsp_ndb_ptr->a_du_1);
+        }
       }
     }
 
@@ -8659,6 +8669,15 @@
              (channel_mode  == TCH_HS_MODE))
             play_trace();
         #endif
+        if (tch_dl_sniff_mode && channel_mode == TCH_HS_MODE)
+        {
+          if (subchannel == 0)
+            tch_send_downlink_bits(l1s_dsp_com.dsp_ndb_ptr->a_dd_0, 11,
+                                   channel_mode, fn_mod_104);
+          else if (subchannel == 1)
+            tch_send_downlink_bits(l1s_dsp_com.dsp_ndb_ptr->a_dd_1, 11,
+                                   channel_mode, fn_mod_104);
+        }
 
         // Check A_DD_0 information block only if no FACCH.
         if (subchannel==0)
@@ -9265,6 +9284,12 @@
               || channel_mode == TCH_EFR_MODE))
             play_trace();
         #endif
+        if (tch_dl_sniff_mode &&
+            (channel_mode == TCH_FS_MODE || channel_mode == TCH_EFR_MODE))
+        {
+            tch_send_downlink_bits(l1s_dsp_com.dsp_ndb_ptr->a_dd_0, 20,
+                                   channel_mode, fn_mod_104);
+        }
 
         // FACCH: Check A_FD information block.
         //-------------------------------------
--- a/src/cs/layer1/cfile/l1_init.c	Tue Mar 29 04:41:25 2022 +0000
+++ b/src/cs/layer1/cfile/l1_init.c	Tue Dec 13 02:44:01 2022 +0000
@@ -1889,6 +1889,8 @@
     Cust_navc_ctrl_status(1);//start - NAVC
  #endif//end of (OP_L1_STANDALONE == 1 || L1_NAVC == 1 )
 
+  /* FreeCalypso addition */
+  tch_tap_init();
 }
 
 /*-------------------------------------------------------*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cs/layer1/cfile/l1_tch_tap.c	Tue Dec 13 02:44:01 2022 +0000
@@ -0,0 +1,178 @@
+/*
+ * This module is a FreeCalypso addition; it contains code implementing
+ * our TCH tap functional additions: TCH downlink capture and TCH uplink
+ * play.
+ */
+
+#include "l1_macro.h"
+#include "l1_confg.h"
+#include "l1_types.h"
+#include "sys_types.h"
+#include <string.h>
+#include "l1_const.h"
+
+#if TESTMODE
+  #include "l1tm_defty.h"
+#endif
+#if (AUDIO_TASK == 1)
+  #include "l1audio_const.h"
+  #include "l1audio_cust.h"
+  #include "l1audio_defty.h"
+#endif
+#if (L1_GTT == 1)
+  #include "l1gtt_const.h"
+  #include "l1gtt_defty.h"
+#endif
+#if (L1_MIDI == 1)
+  #include "l1midi_defty.h"
+#endif
+#include "l1_defty.h"
+
+#include "l1_varex.h"
+#include "l1_trace.h"
+#include "tch_tap_proto.h"
+
+T_RVT_USER_ID tch_tap_rvt_id;
+BOOL tch_dl_sniff_mode, tch_ul_play_mode;
+
+void tch_send_downlink_bits(API *dsp_buffer, UWORD8 nwords, UWORD8 chan_mode,
+			    UWORD8 fn_mod_104)
+{
+	UWORD16 size;
+	T_RVT_BUFFER buf;
+	T_RVT_RET rc;
+	UINT8 *dp;
+	UWORD16 apiword;
+	int i;
+
+	size = nwords * 2 + 3;
+	rc = rvt_mem_alloc(tch_tap_rvt_id, size, &buf);
+	if (rc != RVT_OK)
+		return;
+	dp = buf;
+	*dp++ = TCH_DLBITS_NEW_IND;
+	*dp++ = chan_mode;
+	*dp++ = fn_mod_104;
+	for (i = 0; i < nwords; i++) {
+		apiword = dsp_buffer[i];
+		*dp++ = apiword >> 8;
+		*dp++ = apiword;
+	}
+	rvt_send_trace_no_cpy(buf, tch_tap_rvt_id, size, RVT_BINARY_FORMAT);
+}
+
+static void send_tch_ulbits_conf(void)
+{
+	T_RVT_BUFFER buf;
+	T_RVT_RET rc;
+
+	rc = rvt_mem_alloc(tch_tap_rvt_id, 1, &buf);
+	if (rc == RVT_OK) {
+		buf[0] = TCH_ULBITS_CONF;
+		rvt_send_trace_no_cpy(buf, tch_tap_rvt_id, 1,
+					RVT_BINARY_FORMAT);
+	}
+}
+
+#define	UPLINK_QUEUE_SIZE	5
+#define	WORDS_PER_ENTRY		17
+
+static UWORD16 uplink_data[UPLINK_QUEUE_SIZE][WORDS_PER_ENTRY];
+static volatile int ul_read_ptr, ul_write_ptr;
+
+void tchf_substitute_uplink(API *dsp_buffer)
+{
+	int read_ptr;
+	int i;
+
+	read_ptr = ul_read_ptr;
+	if (read_ptr == ul_write_ptr) {
+		/* no uplink substitution */
+		l1s_dsp_com.dsp_ndb_ptr->d_tch_mode &= ~B_PLAY_UL;
+		tch_ul_play_mode = FALSE;
+		return;
+	}
+	for (i = 0; i < WORDS_PER_ENTRY; i++)
+		dsp_buffer[i+3] = uplink_data[read_ptr][i];
+	// Fill data block Header...
+	dsp_buffer[0] = (1 << B_BLUD);		// 1st word: Set B_BLU bit.
+	dsp_buffer[1] = 0;			// 2nd word: cleared.
+	dsp_buffer[2] = 0;			// 3rd word: cleared.
+	l1s_dsp_com.dsp_ndb_ptr->d_tch_mode |= B_PLAY_UL;
+	/* advance the read pointer and send TCH_ULBITS_CONF */
+	read_ptr++;
+	if (read_ptr >= UPLINK_QUEUE_SIZE)
+		read_ptr = 0;
+	ul_read_ptr = read_ptr;
+	send_tch_ulbits_conf();
+}
+
+static void handle_tch_ulbits_req(T_RVT_BUFFER pkt)
+{
+	int write_ptr, write_next, i;
+	UINT8 *sp;
+
+	write_ptr = ul_write_ptr;
+	write_next = write_ptr + 1;
+	if (write_next >= UPLINK_QUEUE_SIZE)
+		write_next = 0;
+	if (write_next == ul_read_ptr)	/* queue full */
+		return;
+	sp = pkt + 1;
+	for (i = 0; i < WORDS_PER_ENTRY; i++) {
+		uplink_data[write_ptr][i] = (sp[0] << 8) | sp[1];
+		sp += 2;
+	}
+	ul_write_ptr = write_next;
+	tch_ul_play_mode = TRUE;
+}
+
+static void handle_tch_config_req(T_RVT_BUFFER pkt)
+{
+	UWORD8 config;
+	T_RVT_BUFFER buf;
+	T_RVT_RET rc;
+
+	config = pkt[1] & 0x01;
+	tch_dl_sniff_mode = config;
+
+	/* send TCH_CONFIG_CONF response */
+	rc = rvt_mem_alloc(tch_tap_rvt_id, 2, &buf);
+	if (rc == RVT_OK) {
+		buf[0] = TCH_CONFIG_CONF;
+		buf[1] = config;
+		rvt_send_trace_no_cpy(buf, tch_tap_rvt_id, 2,
+					RVT_BINARY_FORMAT);
+	}
+}
+
+/*
+ * The following function is the callback registered with RVT; it gets
+ * called in RVT HISR context.
+ */
+static void tch_rvt_input_callback(T_RVT_BUFFER pkt, UINT16 pktlen)
+{
+	if (pktlen < 1)
+		return;
+	switch (pkt[0]) {
+	case TCH_CONFIG_REQ:
+		if (pktlen != 2)
+			return;
+		handle_tch_config_req(pkt);
+		break;
+	case TCH_ULBITS_REQ:
+		if (pktlen < 34)
+			return;
+		handle_tch_ulbits_req(pkt);
+		break;
+	}
+}
+
+void tch_tap_init(void)
+{
+	rvt_register_id("TCH", &tch_tap_rvt_id, tch_rvt_input_callback);
+	tch_dl_sniff_mode = FALSE;
+	tch_ul_play_mode = FALSE;
+	ul_read_ptr = 0;
+	ul_write_ptr = 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cs/layer1/include/tch_tap_proto.h	Tue Dec 13 02:44:01 2022 +0000
@@ -0,0 +1,11 @@
+/*
+ * This header file is a FreeCalypso addition; it contains definitions
+ * for our RVTMUX-based protocol for TCH tapping.
+ */
+
+#define	TCH_CONFIG_REQ		0x11
+#define	TCH_CONFIG_CONF		0x12
+#define	TCH_ULBITS_REQ		0x13
+#define	TCH_ULBITS_CONF		0x14
+#define	TCH_DLBITS_OLD_IND	0x15	/* FR&EFR only, no distinction, no fn */
+#define	TCH_DLBITS_NEW_IND	0x16	/* with channel mode and fn added */