FreeCalypso > hg > fc-tourmaline
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; }