diff src/g23m-gsm/mm/mm_tim.c @ 1:fa8dc04885d8

src/g23m-*: import from Magnetite
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 16 Oct 2020 06:25:50 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/g23m-gsm/mm/mm_tim.c	Fri Oct 16 06:25:50 2020 +0000
@@ -0,0 +1,838 @@
+/* 
++----------------------------------------------------------------------------- 
+|  Project :  GSM-PS (8410)
+|  Modul   :  MM_TIM
++----------------------------------------------------------------------------- 
+|  Copyright 2002 Texas Instruments Berlin, AG 
+|                 All rights reserved. 
+| 
+|                 This file is confidential and a trade secret of Texas 
+|                 Instruments Berlin, AG 
+|                 The receipt of or possession of this file does not convey 
+|                 any rights to reproduce or disclose its contents or to 
+|                 manufacture, use, or sell anything it may describe, in 
+|                 whole, or in part, without the specific written consent of 
+|                 Texas Instruments Berlin, AG. 
++----------------------------------------------------------------------------- 
+|  Purpose :  This Modul defines the timer handling functions
+|             for the component MM of the mobile station
++----------------------------------------------------------------------------- 
+*/ 
+
+#ifndef MM_TIM_C
+#define MM_TIM_C
+
+#define ENTITY_MM
+
+/*==== INCLUDES ===================================================*/
+#if defined (NEW_FRAME)
+
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include "typedefs.h"
+#include "pcm.h"
+#include "pconst.cdg"
+#include "mconst.cdg"
+#include "message.h"
+#include "ccdapi.h"
+#include "vsi.h"
+#include "custom.h"
+#include "gsm.h"
+#include "prim.h"
+#include "cnf_mm.h"
+#include "mon_mm.h"
+#include "pei.h"
+#include "tok.h"
+#include "mm.h"
+
+#else
+
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include "stddefs.h"
+#include "pcm.h"
+#include "pconst.cdg"
+#include "mconst.cdg"
+#include "message.h"
+#include "ccdapi.h"
+#include "custom.h"
+#include "gsm.h"
+#include "prim.h"
+#include "cnf_mm.h"
+#include "mon_mm.h"
+#include "vsi.h"
+#include "pei.h"
+#include "tok.h"
+#include "mm.h"
+
+#endif
+/*==== EXPORT =====================================================*/
+
+/*==== PRIVAT =====================================================*/
+
+/*==== VARIABLES ==================================================*/
+
+#if defined (OPTION_TIMER)
+LOCAL T_TIMER_CONFIG       config_table[NUM_OF_MM_TIMERS];
+#endif
+
+
+/*==== FUNCTIONS ==================================================*/
+#if defined (OPTION_TIMER)
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)         MODULE  : MM_TIM                   |
+| STATE   : code                  ROUTINE : tim_init_timer           |
++--------------------------------------------------------------------+
+
+  PURPOSE : Initialise Time-out FIFO and configuration data.
+
+*/
+
+
+GLOBAL BOOL tim_init_timer (void)
+{
+  USHORT i;
+
+  TRACE_FUNCTION ("tim_init_timer()");
+
+  for (i = 0; i < NUM_OF_MM_TIMERS; i++)
+  {
+    config_table[i].t_mode = TIMER_RESET;
+    config_table[i].t_val  = 0L;
+  }
+
+  return TRUE;
+}
+#endif /* #if defined (OPTION_TIMER) */
+
+#if defined (OPTION_TIMER)
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)         MODULE  : MM_TIM                   |
+| STATE   : code                  ROUTINE : tim_config_timer         |
++--------------------------------------------------------------------+
+
+  PURPOSE : Configure Timer
+
+*/
+
+GLOBAL void tim_config_timer (UBYTE t_num, UBYTE t_mod, ULONG t_val)
+{
+  TRACE_FUNCTION ("tim_config_timer()");
+
+  assert (t_num < NUM_OF_MM_TIMERS);
+
+  if (t_num < NUM_OF_MM_TIMERS)
+  {
+    config_table[t_num].t_mode = t_mod;
+    config_table[t_num].t_val  = t_val;
+  }
+  else
+  {
+    TRACE_ERROR ("tim_config_timer(): index out of range");
+  }
+}
+#endif /* #if defined (OPTION_TIMER) */
+
+#if defined (NEW_FRAME)
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)         MODULE  : MM_TIM                   |
+| STATE   : code                  ROUTINE : tim_exec_timeout         |
++--------------------------------------------------------------------+
+
+  PURPOSE : execute timeout
+
+*/
+
+GLOBAL void tim_exec_timeout (USHORT index)
+{
+  GET_INSTANCE_DATA;
+  /* typedef void (*T_VOID_FUNC)(); */ /* Already defined */
+
+  static const T_VOID_FUNC timer_jump_table[NUM_OF_MM_TIMERS] = 
+  {
+    tim_t_reg,    /* T_REGISTRATION */
+    tim_t3210,    /* T3210 */
+    tim_t3211,    /* T3211 */
+    tim_t3212,    /* T3212 */
+    tim_t3213,    /* T3213 */
+    tim_t3220,    /* T3220 */
+    tim_t3230,    /* T3230 */
+    tim_t3240,    /* T3240 */
+
+    tim_t_hplmn   /* T_HPLMN */
+#ifdef REL99
+    , tim_t3241    /* T3241 */
+#endif
+  };
+
+  if (index < NUM_OF_MM_TIMERS)
+  {
+    /* 
+     * Timeout is handled in SDL like the reception of a primitive, 
+     * so enable also this trace if primitive traces are enabled only
+     */
+/* Implements Measure#36 */
+#if defined(NCONFIG)
+    /* partab is not defined when NCONFIG is defined */
+    TRACE_EVENT_P1 ("tim_exec_timeout: index (%d)", index);
+#else /* not (NCONFIG) */
+#if defined (TRACE_PRIM) AND defined(OPTION_TIMER)
+    TRACE_EVENT_P1 ("tim_exec_timeout (%s)", partab[index].keyword);
+#endif
+#endif /* NCONFIG */
+
+    mm_data->t_running[index] = FALSE;
+    timer_jump_table[index]();  
+  }
+  else
+  {
+    TRACE_ERROR ("tim_exec_timeout(): index out of range");
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)         MODULE  : MM_TIM                   |
+| STATE   : code                  ROUTINE : tim_stop_timer           |
++--------------------------------------------------------------------+
+
+  PURPOSE : stop timer
+
+*/
+
+GLOBAL void tim_stop_timer (USHORT index)
+{
+  GET_INSTANCE_DATA;
+  assert (index < NUM_OF_MM_TIMERS);
+
+  if (index < NUM_OF_MM_TIMERS)
+  {
+/* Implements Measure#36 */
+#if defined(NCONFIG)
+    /* partab is not defined when NCONFIG is defined */
+  TRACE_EVENT_P1 ("tim_stop_timer: index (%d)", index);
+#else /* not (NCONFIG) */
+#if defined (TRACE_PRIM) AND defined(OPTION_TIMER)
+  TRACE_EVENT_P1 ("tim_stop_timer (%s)", partab[index].keyword);
+#endif
+#endif /* NCONFIG */
+  
+  mm_data->t_running[index] = FALSE;
+  TIMER_STOP (mm_handle, index);
+}
+  else
+  {
+    TRACE_ERROR ("tim_stop_timer(): index out of range");
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)         MODULE  : MM_TIM                   |
+| STATE   : code                  ROUTINE : tim_start_timer          |
++--------------------------------------------------------------------+
+
+  PURPOSE : start timer
+
+*/
+
+GLOBAL void tim_start_timer (USHORT index, T_TIME value)
+{
+  GET_INSTANCE_DATA;
+  assert (index < NUM_OF_MM_TIMERS);
+
+  if (index < NUM_OF_MM_TIMERS)
+  {
+/* Implements Measure#36 */
+#if defined(NCONFIG)
+    /* partab is not defined when NCONFIG is defined */
+  TRACE_EVENT_P1 ("tim_start_timer: index (%d)", index);
+#else /* not (NCONFIG) */
+#if defined (TRACE_PRIM) AND defined(OPTION_TIMER)
+  TRACE_EVENT_P1 ("tim_start_timer (%s)", partab[index].keyword);
+#endif
+#endif /* NCONFIG */
+#if defined (OPTION_TIMER)
+  switch (config_table[index].t_mode)
+  {
+    case TIMER_SET:
+      value = config_table[index].t_val;
+      break;
+
+    case TIMER_RESET:
+      value = value;
+      break;
+
+    case TIMER_SPEED_UP:
+      value = value / config_table[index].t_val;
+      if (value == 0)
+        value = 1;
+      TRACE_EVENT_P1 ("timer_speed_up (%d)", value);
+      break;
+
+    case TIMER_SLOW_DOWN:
+      value = value * config_table[index].t_val;
+      TRACE_EVENT_P1 ("timer_speed_down (%d)", value);
+      break;
+
+    default:
+      TRACE_FUNCTION ("ERROR: UNKNOWN MODE");
+      return;
+  }
+#endif
+
+  mm_data->t_running[index] = TRUE;
+
+  TIMER_START (mm_handle, index, value);
+}
+  else
+  {
+    TRACE_ERROR ("tim_start_timer(): index out of range");
+  }
+}
+
+#endif /* #if defined (NEW_FRAME) */
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_TIM                     |
+| STATE   : code                ROUTINE : tim_t3210                  |
++--------------------------------------------------------------------+
+
+  PURPOSE : Timeout of timer T3210
+
+*/
+
+GLOBAL void tim_t3210 (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("tim_t3210()");
+
+  switch (GET_STATE (STATE_MM))
+  {
+    case MM_LUP_INITIATED:
+    case MM_WAIT_FOR_RR_CONN_LUP:
+      TIMERSTOP (T3240);
+      mm_abort_connection (ABCS_NORM);
+      /* 
+       * The RR connection is aborted normally. RR guarantees that this will
+       * be answered by RR_RELEASE_IND.
+       * This has the advange that GMM gets the MMGMM_NREG_IND after the
+       * channel release of layer 2 if GPRS present without any disadvantage 
+       * for a GSM only protocol stack. No state change here.
+       */
+      break;
+
+    default: /* Ignore event */
+      break;
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_TIM                     |
+| STATE   : code                ROUTINE : tim_t3211                  |
++--------------------------------------------------------------------+
+
+  PURPOSE : Timeout of timer T3211
+
+*/
+
+// T3211 handling routine does the same as T3213 handling routine now ...
+
+GLOBAL void tim_t3211 (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("tim_t3211()");
+
+  switch (GET_STATE (STATE_MM))
+  {
+// If we leave these states and reenter a full service IDLE state,
+// mm_release_rr_connection() 
+// for MM_WAIT_FOR_OUTG_MM_CONN and MM_WAIT_FOR_RR_CONN_MM will 
+// handle the update.
+// mm_rr_activate_cnf() for MM_WAIT_FOR_RR_ACTIVE will also 
+// handle the an outstanding update if coming back to full 
+// service IDLE state.
+// mm_rr_abort_ind() will be called if the state was 
+// MM_PLMN_SEARCH_NORMAL_SERVICE, if there is an outstanding
+// updating procedure and the new service is full service, 
+// this will be checked there after state transition.
+// MM_IDLE_NO_CELL_AVAILABLE / RR_ACTIVATE_IND is handled also.
+// No need to store the timer anymore into the queue.
+
+/*
+    // case MM_WAIT_FOR_OUTG_MM_CONN:
+    // case MM_WAIT_FOR_RR_CONN_MM:
+    // case MM_WAIT_FOR_RR_ACTIVE:
+    case MM_PLMN_SEARCH_NORMAL_SERVICE:
+    // case MM_IDLE_NO_CELL_AVAILABLE:
+      mm_write_entry (TIMEOUT, T3211, 0);
+      break;
+*/
+
+    case MM_IDLE_ATTEMPT_TO_UPDATE:
+    case MM_IDLE_NORMAL_SERVICE:
+      mm_continue_running_update ();
+      break;
+
+    default: /* Ignore event */
+      break;
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_TIM                     |
+| STATE   : code                ROUTINE : tim_t3212                  |
++--------------------------------------------------------------------+
+
+  PURPOSE : Timeout of counter timer for timer T3212
+
+*/
+
+GLOBAL void tim_t3212 (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("tim_t3212()");
+
+  switch (GET_STATE (STATE_MM))
+  {
+    case MM_NULL:
+    case MM_IDLE_NO_IMSI:
+      break; /* Forget the event */
+
+    case MM_IDLE_NORMAL_SERVICE:
+      mm_data->t3212_timeout = TRUE;
+      mm_data->attempt_cnt = 0; /* Expiry of timer T3212 */
+      if (!mm_normal_upd_needed())
+      {
+        /* MM is updated on the cell, no Imm Ass Rej, no cell barred */
+        if (mm_lup_allowed_by_gmm())
+        {
+          mm_periodic_loc_upd ();
+        }
+        else
+        {
+          mm_mmgmm_lup_needed_ind (MMGMM_T3212);
+          /* No state change, remains in MM_IDLE_NORMAL_SERVICE */
+        }
+      }
+      break;
+
+    case MM_IDLE_ATTEMPT_TO_UPDATE:
+      if (mm_data->mm.mm_info.t3212 NEQ T3212_NO_PRD_UPDAT)
+      {
+        mm_data->t3212_timeout = TRUE;
+        mm_data->attempt_cnt = 0; /* Expiry of timer T3212 */
+        if (mm_lup_allowed_by_gmm())
+        {
+          mm_normal_loc_upd ();
+        }
+        else
+        {
+          mm_mmgmm_lup_needed_ind (MMGMM_T3212);
+          /* No state change, remains in MM_IDLE_ATTEMPT_TO_UPDATE */
+        }
+      }
+      break;
+
+    default: /* Store the event until it is possible to handle it */
+      mm_data->t3212_timeout = TRUE;
+      break;
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_TIM                     |
+| STATE   : code                ROUTINE : tim_t3213                  |
++--------------------------------------------------------------------+
+
+  PURPOSE : Timeout of timer T3213
+
+*/
+
+GLOBAL void tim_t3213 (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("tim_t3213()");
+
+  switch (GET_STATE (STATE_MM))
+  {
+/* 
+    case MM_WAIT_FOR_OUTG_MM_CONN:
+    case MM_WAIT_FOR_RR_CONN_MM:
+    case MM_WAIT_FOR_RR_ACTIVE:
+    case MM_PLMN_SEARCH_NORMAL_SERVICE:
+      mm_write_entry (TIMEOUT, T3213, 0);
+      break;
+*/
+
+    case MM_IDLE_ATTEMPT_TO_UPDATE:
+    case MM_IDLE_NORMAL_SERVICE:
+      /* 
+       * if something is received from RR or T3213 was already restarted 2 times --> delay of additional 8 seconds
+       * continue the LUP attempts
+       */
+      mm_data->t3213_restart++;
+      if (mm_data->t3213_restart > MAX_REST_T3213)
+        mm_continue_running_update ();
+      else
+        TIMERSTART (T3213, T_3213_VALUE);
+      break;
+
+    default: /* Ignore event */
+      break;
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_TIM                     |
+| STATE   : code                ROUTINE : tim_t3220                  |
++--------------------------------------------------------------------+
+
+  PURPOSE : Timeout of timer T3220
+
+*/
+
+GLOBAL void tim_t3220 (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("tim_t3220()");
+
+  switch (GET_STATE (STATE_MM))
+  {
+    case MM_IMSI_DETACH_INIT:
+    case MM_WAIT_FOR_RR_CONN_DETACH:
+      /* 
+       * The RR connection is aborted normally. RR guarantees that this will
+       * be answered by RR_RELEASE_IND. If MM receives the RR_RELEASE_IND,
+       * the IMSI DETACH procedure ends and appropriate actions are taken.
+       * This has the advange that GMM gets the MMGMM_NREG_CNF after the 
+       * channel release of layer 2 if GPRS present without any disadvantage 
+       * for a GSM only protocol stack. No state change here.
+       */
+      mm_abort_connection (ABCS_NORM);
+      break;
+
+    default: /* Ignore event */
+      break;
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_TIM                     |
+| STATE   : code                ROUTINE : tim_t3230                  |
++--------------------------------------------------------------------+
+
+  PURPOSE : Timeout of timer T3230
+
+*/
+
+GLOBAL void tim_t3230 (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("tim_t3230()");
+
+  /* 
+   * If T3230 expires (i.e. no response is given but a RR connection is 
+   * available) the MM connection establishment is aborted and the requesting
+   * CM sublayer is informed. If no other MM connection exists then the mobile
+   * station shall proceed as described in section 4.5.3.1 for release of the 
+   * RR connection. Otherwise the mobile station shall return to the MM 
+   * sublayer state where the request of an MM connection was received,
+   * i.e. to MM sublayer state MM connection active. Other ongoing
+   * MM connections (if any) shall not be affected.
+   * [GSM 04.08 subclause 4.5.1.2 b)]
+   * 
+   * If all MM connections are released by their CM entities, the
+   * mobile station shall set timer T3240 and enter the state
+   * WAIT FOR NETWORK COMMAND, expecting the release of the RR connection.
+   *  [Excerpt from GSM 04.08 subclause 4.5.3.1]
+   */
+  
+  switch (GET_STATE (STATE_MM))
+  {
+    case MM_WAIT_FOR_REESTABLISH:
+    case MM_WAIT_FOR_OUTG_MM_CONN:
+      mm_mmxx_rel_ind (MMCS_TIMER_RECOVERY, CM_ACTIVE);
+      mm_mmxx_rel_ind (MMCS_TIMER_RECOVERY, CM_PENDING);
+      mm_data->wait_for_accept = FALSE;
+      TIMERSTART (T3240, T_3240_VALUE);
+      SET_STATE (STATE_MM, MM_WAIT_FOR_NW_CMD);
+      break;
+
+    case MM_CONN_ACTIVE: /* wait_for_accept expected to be TRUE */
+      mm_mmxx_rel_ind (MMCS_TIMER_RECOVERY, CM_PENDING);
+      mm_data->wait_for_accept = FALSE;
+      if ((mm_count_connections (CM_ACTIVE) EQ 0) AND
+          (mm_count_connections (CM_STORE)  EQ 0))
+      {
+        TIMERSTART (T3240, T_3240_VALUE);
+        SET_STATE (STATE_MM, MM_WAIT_FOR_NW_CMD);
+      }
+      USE_STORED_ENTRIES();
+      break;
+
+    default: /* Ignore event */
+      break;
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_TIM                     |
+| STATE   : code                ROUTINE : tim_t3240                  |
++--------------------------------------------------------------------+
+
+  PURPOSE : Timeout of timer T3240
+
+*/
+
+GLOBAL void tim_t3240 (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("tim_t3240()");
+
+  switch (GET_STATE (STATE_MM))
+  {
+    case MM_PROCESS_PROMPT:
+    case MM_WAIT_FOR_NW_CMD:
+      mm_abort_connection (ABCS_NORM);
+      mm_mmxx_rel_ind (MMCS_TIMER_RECOVERY, CM_ACTIVE);
+      mm_mmxx_rel_ind (MMCS_TIMER_RECOVERY, CM_PENDING);
+      
+      /* 
+       * The RR connection is aborted normally. RR guarantees that this will
+       * be answered by RR_RELEASE_IND.
+       * This has the advange that GMM gets the MMGMM_CM_RELEASE_IND after the
+       * channel release of layer 2 if GPRS present without any disadvantage 
+       * for a GSM only protocol stack. No state change here.
+       */
+      break;
+
+    case MM_LUP_REJECTED:
+      mm_abort_connection (ABCS_NORM);
+      /* 
+       * The RR connection is aborted normally. RR guarantees that this will
+       * be answered by RR_RELEASE_IND.
+       * This has the advange that GMM gets the MMGMM_NREG_IND after the
+       * channel release of layer 2 if GPRS present without any disadvantage 
+       * for a GSM only protocol stack. No state change here.
+       */
+      break;
+
+    default: /* Ignore event */
+      break;
+  }
+}
+
+#ifdef REL99
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_TIM                     |
+| STATE   : code                ROUTINE : tim_t3241                  |
++--------------------------------------------------------------------+
+
+  PURPOSE : Timeout of timer T3241
+
+*/
+
+GLOBAL void tim_t3241 (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("tim_t3241()");
+
+  switch (GET_STATE (STATE_MM))
+  {
+    case MM_RR_CONN_RELEASE_NOT_ALLOWED:
+      mm_abort_connection (ABCS_NORM);
+      /*
+       * The RR connection is aborted normally. RR guarantees that this will
+       * be answered by RR_RELEASE_IND.
+       * This has the advange that GMM gets the MMGMM_CM_RELEASE_IND after the
+       * channel release of layer 2 if GPRS present without any disadvantage
+       * for a GSM only protocol stack. No state change here.
+       */
+      break;
+    default: /* Ignore event */
+      break;
+  }
+}
+#endif
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_TIM                             |
+| STATE   : code                ROUTINE : tim_t_hplmn                        |
++----------------------------------------------------------------------------+
+
+  PURPOSE : Timeout of timer T_HPLMN. 
+            This timer allows control of the PPLMN rescan and
+            national roaming procedure to recover the HPLMN.
+*/
+
+GLOBAL void tim_t_hplmn (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("tim_t_hplmn()");
+
+  /*
+   * Launch the scan procedure if it still makes sense to do it according to
+   * MM state.
+   */
+  if (mm_full_service_pplmn_scan())
+  {
+    mm_data->plmn_scan_mm = TRUE;
+    mm_data->first_attach_mem = FALSE;	
+    mm_func_mmgmm_net_req();
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_TIM                     |
+| STATE   : code                ROUTINE : tim_t_reg                  |
++--------------------------------------------------------------------+
+
+  PURPOSE : Timeout of timer T_REG. 
+            This timer is not foreseen by the recommendations. 
+            It is MM's health monitor timer, checking 
+            the conditions whether an update has been missed.
+
+*/
+
+GLOBAL void tim_t_reg (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("tim_t_reg()");
+
+  switch (GET_STATE (STATE_MM))
+  {
+    case MM_NULL:
+      break; /* No timer activity in this state */
+  
+    case MM_IDLE_NORMAL_SERVICE: /* 19.1 */
+      /* Restart the registration timer */
+      TIMERSTART (T_REGISTRATION, T_REG_VALUE);      
+    
+      /* 
+       * As it is not expected that the timer catches in state 
+       * MM_IDLE_NORMAL_SERVICE in FTA, there is no test 
+       * here for a test SIM. The goal is to have an MM
+       * where the timer never catches in MM_IDLE_NORMAL_SERVICE.
+       */
+      
+      /* Check whether T3211, T3213 are running retriggering update anyway */
+      if ((TIMERACTIVE (T3211) OR TIMERACTIVE (T3213)) AND 
+          (mm_data->loc_upd_type.lut NEQ NOT_RUNNING))
+        return;
+
+      /* Check whether MM is temporary barred and cannot update now */
+      if ((mm_data->idle_entry EQ RRCS_ACCESS_BARRED) OR
+          (mm_data->idle_entry EQ RRCS_RND_ACC_DELAY))
+        return; 
+        
+      /* 
+       * Check whether we are in an ATTACH update procedure, but there is no
+       * T3211, T3213 timer running and MM is not temporary barred.
+       */
+      if (mm_attach_upd_needed() OR mm_normal_upd_needed())
+      {
+        TRACE_ERROR ("Recover ATTACH/NORMAL");
+        
+        mm_mmgmm_lup_needed_ind (MMGMM_REG_TIMER);
+
+        if (mm_normal_upd_needed ())
+        {
+          mm_data->attempt_cnt = 0; /* New location area */
+          mm_normal_loc_upd ();
+        }
+        else
+        {
+          mm_attach_loc_upd ();
+        }
+        return;
+      }
+ 
+      /* 
+       * Check whether T3212 should run, but is not running.
+       * If so, something irregular has happened and 
+       * we have to start the update immediately.
+       */
+      if (mm_data->mm.mm_info.t3212 NEQ T3212_NO_PRD_UPDAT AND 
+          (!TIMERACTIVE (T3212) OR mm_data->t3212_timeout))
+      {
+        /* 
+         * The networks says we have periodic updating, 
+         * but unexpectedly T3212 is not running or T3212 timed out.
+         */
+        TRACE_ERROR ("Recover PERIODIC");
+        
+        if (mm_lup_allowed_by_gmm())
+        {
+          mm_periodic_loc_upd ();
+        }
+        else
+        {
+          // Don't add recovery code now for GPRS, maybe more has to be done.
+          // mm_mmgmm_lup_needed_ind (MMGMM_REG_TIMER);
+        }
+        return;
+      }
+      break;
+
+    case MM_IDLE_ATTEMPT_TO_UPDATE: /* 19.2 */
+      /* Restart the registration timer */
+      TIMERSTART (T_REGISTRATION, T_REG_VALUE);      
+
+      /* Timer only handled in this state if a normal SIM is present */
+      if (mm_data->reg.op.sim_ins EQ SIM_NO_INSRT OR 
+          mm_data->reg.op.ts EQ TS_AVAIL)
+        return;
+
+      /* Check whether T3211, T3213 are running retriggering update anyway */
+      if ((TIMERACTIVE (T3211) OR TIMERACTIVE (T3213)) AND 
+          (mm_data->loc_upd_type.lut NEQ NOT_RUNNING))
+        return;
+
+      if (TIMERACTIVE (T3212))
+        return;
+
+
+      /* Check whether MM is temporary barred and cannot update now */
+      if ((mm_data->idle_entry EQ RRCS_ACCESS_BARRED) OR
+          (mm_data->idle_entry EQ RRCS_RND_ACC_DELAY))
+        return; 
+        
+      if (mm_gsm_alone ())
+      {
+        mm_normal_loc_upd ();
+      }
+      else
+      {
+        mm_mmgmm_lup_needed_ind (MMGMM_REG_TIMER);
+        /* No state change, remains in MM_IDLE_ATTEMPT_TO_UPDATE */
+      }
+      break;
+
+    default:
+      /* Restart the registration timer */
+      TIMERSTART (T_REGISTRATION, T_REG_VALUE);      
+      break;
+  }
+}
+
+#endif