# HG changeset patch # User Mychaela Falconia # Date 1670899441 0 # Node ID edcb8364d45b33afdda77ad58df00ebf2ed6c591 # Parent 91e61d00a6b5bb6c9a9ddf3daaa604ce92ffd044 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. diff -r 91e61d00a6b5 -r edcb8364d45b components/l1_ext --- 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 diff -r 91e61d00a6b5 -r edcb8364d45b src/cs/layer1/cfile/l1_cmplx.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. //------------------------------------- diff -r 91e61d00a6b5 -r edcb8364d45b src/cs/layer1/cfile/l1_init.c --- 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(); } /*-------------------------------------------------------*/ diff -r 91e61d00a6b5 -r edcb8364d45b src/cs/layer1/cfile/l1_tch_tap.c --- /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 +#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; +} diff -r 91e61d00a6b5 -r edcb8364d45b src/cs/layer1/include/tch_tap_proto.h --- /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 */