FreeCalypso > hg > fc-tourmaline
view src/cs/riviera/rvf/rvf_time.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 | 4e78acac3d88 |
children |
line wrap: on
line source
/****************************************************************************/ /* */ /* Name rvf_time.c */ /* */ /* Function this file contains rvf time related functions */ /* */ /* Version 0.1 */ /* */ /* Date Modification */ /* ------------------------------------ */ /* 3/12/99 Create */ /* 10/27/1999 remove all non-nucleus sections (#ifdef) */ /* 30/11/99 compliant to RV coding guidelines */ /* 31/01/2003 Timer Redesign/Impl.RV2 Gary TOTNEY */ /* */ /* Author David Lamy-Charrier (dlamy@tif.ti.com) */ /* */ /* (C) Copyright 1999 by Texas Instruments Incorporated, All Rights Reserved*/ /****************************************************************************/ #include "nucleus.h" #include "rvm/rvm_use_id_list.h" #include "rvm/rvm_i.h" // only for MBs [coupling issue] #include "rvm/rvm_api.h"// MSG [coupling issue] #include "rvf/rvf_i.h" #include "rvf/rvf_api.h" #include <string.h> /* ** Define the time control array */ static NU_TIMER rvf_Timer[MAX_RVF_TASKS][RVF_NUM_TASK_TIMERS]; //extern T_RVF_MB_ID rvm_timer_mem_bank; #define _RALLOC_TIMER_BLK(tb) rvf_get_buf(rvm_timer_mem_bank, sizeof(NU_TIMER), tb) #define _RALLOC_TMS_MSG(id, tb) rvf_get_msg_buf(rvm_tm_notify_mem_bank, sizeof(T_RVF_TMS_MSG), id, tb) /* PRIVATE FUNC FWD DECLs */ T_RV_TM_ID _invoke_tm(T_RVF_G_ADDR_ID gid, UINT32 t, UINT8 cont, void* action, UINT8 lg); /******************************************************************************* ** ** Function _rvf_timer_expire ** ** Description This internal function is called by Nucleus OS, when a task ** timer expires. It sets the corresponding event. ** ** Returns void ** *******************************************************************************/ void _rvf_timer_expire(UNSIGNED timer_id) { rvf_disable(14); /* send the corresponding timer event */ rvf_send_event((UINT8)(timer_id / RVF_NUM_TASK_TIMERS),(UINT16)(EVENT_MASK(((timer_id % RVF_NUM_TASK_TIMERS)+4)) ) ); rvf_enable(); } void _rvf_tm_notify(UNSIGNED timer_id) { T_RVF_TM_UBLK tmr; T_RVF_TM_ATTRIB_UBLK attr; UINT32 tmid=0, cont=0, d; OPTION opt; T_RVF_TMS_MSG* p_msg=NULL; if(timer_id) tmr.id=timer_id; if(NU_Timer_Information(tmr.ptr,attr.str, &opt, (UNSIGNED*)&d, (UNSIGNED*)&tmid, (UNSIGNED*)&d, (UNSIGNED*) &cont) == NU_INVALID_TIMER) { // use to get p_attrib rvf_send_trace ("FATAL: RVF TIMER ATTIRBUTE ERROR!", 49, NULL_PARAM, RV_TRACE_LEVEL_WARNING, 0); } /* printf("%ld %ld %d:", attr.attrib.host_addr_id, attr.attrib.action, attr.attrib.legacyFlag); */ if(!pRtAddrIdTable[attr.attrib.host_addr_id]) return; // Don't waste time in HISR /* MUST BE REPLACED WITH CACHED MSG'ing */ // Will utilise active caching in near future, limiting HISR duration if((_RALLOC_TMS_MSG(RVM_TMS_MSG, (T_RVF_MSG**)&p_msg))==RVF_RED){ rvf_send_trace ("FATAL: RVF TIMER HISR: Insufficient resources!", 49, NULL_PARAM, RV_TRACE_LEVEL_WARNING, 0); return; // (RV_MEMORY_ERR); } p_msg->hdr.msg_id=RVM_TMS_MSG; p_msg->tm_id=tmr.id; p_msg->cont=cont; p_msg->action=attr.attrib.action; rvf_disable(14); rvf_send_priority_msg(attr.attrib.host_addr_id, p_msg); // NOTE: must have id and recognised in FSM core rvf_enable(); } /********************************************************************************/ /* */ /* Function Name: rvf_create_timer */ /* */ /* Purpose: This function is reponsible for stopping timers. */ /* */ /* Revision History: */ /* */ /********************************************************************************/ T_RVF_TIMER_ID rvf_create_timer(T_RVF_G_ADDR_ID g_addrId, UINT32 tmDuration, BOOLEAN isContinuous, void* p_action) { return _invoke_tm(g_addrId, tmDuration, isContinuous, p_action, 0); } // this exists as part of an on-going initiative to deprecate rvf: start/stop timers T_RV_TM_ID _invoke_tm(T_RVF_G_ADDR_ID gid, UINT32 t, UINT8 cont, void* action, UINT8 lg) { T_RVF_TM_UBLK tmr; T_RVF_TM_ATTRIB_UBLK tm_attrib; UINT32 re_sched=0; OPTION opt=NU_DISABLE_TIMER; STATUS status; if(t) opt=NU_ENABLE_TIMER; if(cont) re_sched=t; // TO DO... ret. 0 if alloc fails if(_RALLOC_TIMER_BLK((T_RVF_BUFFER**)&tmr.ptr)) return 0; tm_attrib.attrib.host_addr_id =gid; tm_attrib.attrib.action =action; tm_attrib.attrib.legacyFlag =lg; status=NU_Create_Timer( tmr.ptr, // TIMER CONTROL BLOCK tm_attrib.str, // timer name (overloaded) _rvf_tm_notify, // expiration routine to call tmr.id, // unique id which enables to find a specific task and a specific timer t, // duration re_sched, // continuous = 1 opt); if(status!=NU_SUCCESS) tmr.id=0; return (UINT32)tmr.id; } /*T_RVF_RET rvf_get_remaining_time(T_RV_TM_ID tid, UINT32* t) { T_RVF_TM_UBLK tmr; tmr.id=tid; if(NU_Get_Remaining_Time(tmr.ptr, (UNSIGNED*)&t)==NU_INVALID_TIMER) return RV_INVALID_PARAMETER; return RVF_OK; }*/ /******************************************************************************* ** ** Function rvf_del_timer ** ** Description This function is called by an application to delete a timer ** entry from a timer list. ** ** Returns void ** *******************************************************************************/ void rvf_del_timer(T_RV_TM_ID tm_id) { T_RVF_TM_UBLK tmr; if(tm_id) tmr.id=tm_id; NU_Control_Timer(tmr.ptr, NU_DISABLE_TIMER); NU_Delete_Timer(tmr.ptr); rvf_free_buf(tmr.ptr); } void rvf_reset_timer(T_RV_TM_ID tm_id, UINT32 new_duration, BOOLEAN isContinuous) { T_RVF_TM_UBLK tmr; UINT32 re_sched=0; if(isContinuous)re_sched=new_duration; if(tm_id) tmr.id=tm_id; NU_Control_Timer(tmr.ptr, NU_DISABLE_TIMER); if(new_duration) { NU_Reset_Timer( tmr.ptr, _rvf_tm_notify, new_duration, re_sched, NU_ENABLE_TIMER); } } /******************************************************************************* ** ** Function _rvf_timers_init ** ** Description This internal function is called once at startup to initialize ** all the timer structures. ** ** Returns void ** *******************************************************************************/ void _rvf_timers_init(void) { UINT8 task_num, timer_num; for (task_num = 0; task_num< MAX_RVF_TASKS; task_num++) { for (timer_num = 0; timer_num < RVF_NUM_TASK_TIMERS; timer_num++) { NU_Create_Timer( &(rvf_Timer[task_num][timer_num]),/* TIMER CONTROL BLOCK*/ "", /* timer name */ _rvf_timer_expire, /* expiration routine to call*/ (task_num * RVF_NUM_TASK_TIMERS) +timer_num, /* unique id which enables to find a specific task and a specific timer*/ 1, 0, NU_DISABLE_TIMER); } } } /******************************************************************************* ** ** Function rvf_get_time_stamp ** ** Description This function formats the time into a user area ** ** Returns the address of the user area containing the formatted time ** *******************************************************************************/ char *rvf_get_time_stamp(char *tbuf) { UINT32 ms_time; UINT32 s_time; UINT32 m_time; UINT32 h_time; char *p_out = tbuf; ms_time = rvf_get_tick_count(); s_time = ms_time/100; /* 100 Ticks per second */ m_time = s_time/60; h_time = m_time/60; ms_time -= s_time*100; s_time -= m_time*60; m_time -= h_time*60; *p_out++ = (char)((h_time / 10) + '0'); *p_out++ = (char)((h_time % 10) + '0'); *p_out++ = ':'; *p_out++ = (char)((m_time / 10) + '0'); *p_out++ = (char)((m_time % 10) + '0'); *p_out++ = ':'; *p_out++ = (char)((s_time / 10) + '0'); *p_out++ = (char)((s_time % 10) + '0'); *p_out++ = ':'; *p_out++ = (char)((ms_time / 10) + '0'); *p_out++ = (char)((ms_time % 10) + '0'); *p_out++ = ':'; *p_out = 0; return tbuf; } /******************************************************************************* ** ** Function rvf_get_tick_count ** ** Description This function returns the current Nucleus system ticks ** ** Returns ticks ** *******************************************************************************/ UINT32 rvf_get_tick_count(void) { return NU_Retrieve_Clock(); } /******************************************************************************* ** ** Function rvf_start_timer ** ** Description An application can call this function to start one of ** it's four general purpose timers. Any of the four timers ** can be 1-shot or continuous. If a timer is already running, ** it will be reset to the new paramaters. ** ** Returns void ** *******************************************************************************/ void rvf_start_timer (UINT8 tnum, UINT32 ticks, BOOLEAN is_continuous) { T_RVF_G_ADDR_ID task_id = rvf_get_taskid(); if(tnum==RVF_TIMER_3 || tnum==RVF_TIMER_2) { // reserved for rvf timer service rvf_send_trace ("WARNING: Timers 2 & 3 are deprecated!", 37, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_LOW, 0); // return; } if (!ticks) // check if ticks == 0, set it to 1 { ticks = 1; } // disable Nucleus timer NU_Control_Timer( &(rvf_Timer[task_id][tnum]), NU_DISABLE_TIMER ); // reset the timer with the new settings NU_Reset_Timer( &(rvf_Timer[task_id][tnum]), _rvf_timer_expire, ticks, is_continuous? ticks:0, // if timer is continuous, reload it NU_ENABLE_TIMER); } /******************************************************************************* ** ** Function rvf_stop_timer ** ** Description An application can call this function to stop one of ** it's four general purpose timers. There is no harm in ** stopping a timer that is already stopped. ** ** Returns void ** *******************************************************************************/ void rvf_stop_timer (UINT8 tnum) { T_RVF_G_ADDR_ID task_id = rvf_get_taskid(); /* disable Nucleus timer */ NU_Control_Timer( &(rvf_Timer[task_id][tnum]), NU_DISABLE_TIMER ); } /******************************************************************************* ** ** Function rvf_init_timer_list ** ** Description This function is called by applications when they ** want to initialize a timer list. ** ** Returns void ** *******************************************************************************/ void rvf_init_timer_list (T_RVF_TIMER_LIST_Q *p_timer_listq) { p_timer_listq->p_first = NULL; p_timer_listq->p_last = NULL; p_timer_listq->last_ticks = 0; } /******************************************************************************* ** ** Function rvf_init_timer_list_entry ** ** Description This function is called by the applications when they ** want to initialize a timer list entry. This must be ** done prior to first use of the entry. ** ** Returns void ** *******************************************************************************/ void rvf_init_timer_list_entry (T_RVF_TIMER_LIST_ENT *p_tle) { p_tle->p_next = NULL; p_tle->p_prev = NULL; p_tle->ticks = 0xFFFFFFFFL; } /******************************************************************************* ** ** Function rvf_update_timer_list ** ** Description This function is called by the applications when they ** want to update a timer list. This should be at every ** timer list unit tick, e.g. once per sec, once per minute etc. ** ** Returns the number of timers that have expired ** *******************************************************************************/ UINT16 rvf_revise_timer_list (T_RVF_G_ADDR_ID gid){ if(!pRtAddrIdTable[gid] ); // !pRtAddrIdTable[gid]->p_tm_q || // pRtAddrIdTable[gid]->p_tm_q->timerCnt==0 || // pRtAddrIdTable[gid]->polling_tm!=0 ) return 0; /* rvf abort */ // return rvf_update_timer_list(pRtAddrIdTable[gid]->p_tm_q); /* tms notify */ return 0; } UINT16 rvf_update_timer_list (T_RVF_TIMER_LIST_Q *p_timer_listq) { T_RVF_TIMER_LIST_ENT *p_tle; UINT16 num_time_out = 0; p_tle = p_timer_listq->p_first; /* First, get the guys who have previously timed out */ while ((p_tle) && (p_tle->ticks == 0)) { num_time_out++; p_tle = p_tle->p_next; } /* Now, get the guys who have just timed out */ if ((p_tle) && (p_tle->ticks)) { if (--p_tle->ticks == 0) { while (p_tle != NULL && p_tle->ticks == 0) { num_time_out++; p_tle = p_tle->p_next; } } } if (p_timer_listq->last_ticks) p_timer_listq->last_ticks--; return (num_time_out); } /******************************************************************************* ** ** Function rvf_add_to_timer_list ** ** Description This function is called by an application to add a timer ** entry to a timer list. ** ** Returns void ** *******************************************************************************/ void rvf_add_to_timer_list (T_RVF_TIMER_LIST_Q *p_timer_listq, T_RVF_TIMER_LIST_ENT *p_tle) { UINT32 nr_ticks_total; T_RVF_TIMER_LIST_ENT *p_temp; if (p_tle->ticks >= p_timer_listq->last_ticks) { if (p_timer_listq->p_first == NULL) p_timer_listq->p_first = p_tle; else { if (p_timer_listq->p_last != NULL) p_timer_listq->p_last->p_next = p_tle; p_tle->p_prev = p_timer_listq->p_last; } p_tle->p_next = NULL; p_timer_listq->p_last = p_tle; nr_ticks_total = p_tle->ticks; p_tle->ticks = p_tle->ticks - p_timer_listq->last_ticks; p_timer_listq->last_ticks = nr_ticks_total; } else { p_temp = p_timer_listq->p_first; while (p_tle->ticks > p_temp->ticks) { p_tle->ticks = p_tle->ticks - p_temp->ticks; p_temp = p_temp->p_next; } if (p_temp == p_timer_listq->p_first) { p_tle->p_next = p_timer_listq->p_first; p_timer_listq->p_first->p_prev = p_tle; p_timer_listq->p_first = p_tle; } else { p_temp->p_prev->p_next = p_tle; p_tle->p_prev = p_temp->p_prev; p_temp->p_prev = p_tle; p_tle->p_next = p_temp; } p_temp->ticks = p_temp->ticks - p_tle->ticks; } } /******************************************************************************* ** ** Function rvf_remove_from_timer_list ** ** Description This function is called by an application to remove a timer ** entry from a timer list. ** ** Returns void ** *******************************************************************************/ void rvf_remove_from_timer_list (T_RVF_TIMER_LIST_Q *p_timer_listq, T_RVF_TIMER_LIST_ENT *p_tle) { if (p_tle == NULL || p_tle->ticks == 0xFFFFFFFFL || p_timer_listq->p_first == NULL) { return; } /* Add the ticks remaining in this timer to the next guy in the list. */ if (p_tle->p_next != NULL) { p_tle->p_next->ticks += p_tle->ticks; } else { p_timer_listq->last_ticks -= p_tle->ticks; } /* Unlink timer from the list. */ if (p_timer_listq->p_first == p_tle) { p_timer_listq->p_first = p_tle->p_next; if (p_timer_listq->p_first != NULL) p_timer_listq->p_first->p_prev = NULL; if (p_timer_listq->p_last == p_tle) p_timer_listq->p_last = NULL; } else { if (p_timer_listq->p_last == p_tle) { p_timer_listq->p_last = p_tle->p_prev; if (p_timer_listq->p_last != NULL) p_timer_listq->p_last->p_next = NULL; } else { if (p_tle->p_next != NULL && p_tle->p_next->p_prev == p_tle) p_tle->p_next->p_prev = p_tle->p_prev; else { /* Error case - chain messed up ?? */ return; } if (p_tle->p_prev != NULL && p_tle->p_prev->p_next == p_tle) p_tle->p_prev->p_next = p_tle->p_next; else { /* Error case - chain messed up ?? */ return; } } } p_tle->p_next = p_tle->p_prev = NULL; p_tle->ticks = 0xFFFFFFFFL; } /******************************************************************************* ** ** Function rvf_get_expired_entry ** ** Description This function returns a pointer to the first expired entry in ** the timer list queue. ** If no entry in the queue has expired, it returns NULL. ** ** Returns T_RVF_TIMER_LIST_ENT * : pointer to the expired entry if any. ** *******************************************************************************/ T_RVF_TIMER_LIST_ENT * rvf_get_expired_entry (T_RVF_TIMER_LIST_Q *p_timer_listq) { T_RVF_TIMER_LIST_ENT * p_tle; /* test if the first entry in the queue has expired */ if ( (p_timer_listq->p_first != NULL) && (p_timer_listq->p_first->ticks == 0) ) { p_tle = p_timer_listq->p_first; if(p_tle->t_init) { p_tle->ticks=p_tle->t_init; } else { /* unlink entry from the list */ p_timer_listq->p_first = p_tle->p_next; if (p_timer_listq->p_first != NULL) p_timer_listq->p_first->p_prev = NULL; if (p_timer_listq->p_last == p_tle) p_timer_listq->p_last = NULL; p_tle->p_next = NULL; p_tle->p_prev = NULL; p_tle->ticks = 0xFFFFFFFFL; //return p_tle; } return p_tle; } else { return NULL; } }