view src/cs/layer1/cfile/l1_tch_tap.c @ 301:4bb5772a05a3

AT%SPVER: new command for setting custom speech version lists The speech version list in the Bearer Capability IE tells the network which speech codecs are supported by the MS, and in which order of preference. The standard behaviour is to list all codecs that are supported by the hw+fw platform, and the standard preference order is newer over older, FR over HR. But sometimes it is desirable (for network testing) to artificially restrict which codecs the test MS will declare as supported, and/or to list them in some peculiar non-standard order of preference. Add a new private AT command, AT%SPVER, allowing the user to set and clear custom speech version lists for the Bearer Capability IE composer in CC.
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 21 May 2023 21:43:10 +0000
parents edcb8364d45b
children
line wrap: on
line source

/*
 * 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;
}