view src/cs/layer1/cfile/l1_tch_tap.c @ 303:f76436d19a7a default tip

!GPRS config: fix long-standing AT+COPS chance hanging bug There has been a long-standing bug in FreeCalypso going back years: sometimes in the AT command bring-up sequence of an ACI-only MS, the AT+COPS command would produce only a power scan followed by cessation of protocol stack activity (only L1 ADC traces), instead of the expected network search sequence. This behaviour was seen in different FC firmware versions going back to Citrine, and seemed to follow some law of chance, not reliably repeatable. This bug has been tracked down and found to be specific to !GPRS configuration, stemming from our TCS2/TCS3 hybrid and reconstruction of !GPRS support that was bitrotten in TCS3.2/LoCosto version. ACI module psa_mms.c, needed only for !GPRS, was missing in the TCS3 version and had to be pulled from TCS2 - but as it turns out, there is a new field in the MMR_REG_REQ primitive that needs to be set correctly, and that psa_mms.c module is the place where this initialization needed to be added.
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 08 Jun 2023 08:23:37 +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;
}