FreeCalypso > hg > fc-tourmaline
diff src/cs/layer1/cfile/l1_tch_tap.c @ 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 | |
children |
line wrap: on
line diff
--- /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; +}