view src/g23m-aci/aci_dti_mng/dti_conn_mng.c @ 632:d968a3216ba0

new tangomdm build target TCS211/Magnetite built for target leonardo runs just fine on the Tango-based Caramel board, but a more proper tangomdm build target is preferable in order to better market these Tango modems to prospective commercial customers. The only differences are in GPIO and MCSI config: * MCSI is enabled in the tangomdm build config. * GPIO 1 is loudspeaker amplifier control on Leonardo, but on Tango platforms it can be used for anything. On Caramel boards this GPIO should be configured as an output driving high. * GPIO 2 needs to be configured as Calypso input on Leonardo, but on Tango platforms it can be used for anything. On Caramel boards this GPIO should be configured as an output, either high or low is OK.
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 04 Jan 2020 19:27:41 +0000
parents 53929b40109c
children
line wrap: on
line source

/*
+-----------------------------------------------------------------------------
|  Project :  ...
|  Modul   :  dti_conn_mng.c
+-----------------------------------------------------------------------------
|  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 :  Implementation of DTI Connection Manager
+-----------------------------------------------------------------------------
*/


#ifndef DTI_CONN_MNG_C
#define DTI_CONN_MNG_C
#endif


/*===== INCLUDES ===================================================*/

#include "aci_all.h"

#include "pconst.cdg"
#include "mconst.cdg"
#include "cnf_aci.h"
#include "mon_aci.h"
#include "pei.h"
#include "aci_cmh.h"
#include "ati_cmd.h"
#include "aci_io.h"

#include "aci_cmh.h"
#include "aci_lst.h"
#include "aci_mem.h"

#include "dti.h"
#include "dti_conn_mng.h"
#include "dti_cntrl_mng.h"



LOCAL ULONG        used_dti_channels = 0;
LOCAL T_ACI_LIST  *dti_channel_list = NULL; /* list_begin */

LOCAL T_DTI_CONN_PARAMS glob_params;


/********************** LOCAL FUNCTIONS *****************************/


LOCAL UBYTE dti_conn_get_new_dti_id (void)
{
  ULONG tst_id;
  UBYTE i;

  TRACE_FUNCTION("dti_conn_get_new_dti_id()");

  /* create a new DTI ID */
  for (i = 0; i <= MAX_DTI_CONN_CHANNELS; i++)
  {
    tst_id = (0x01 << i) & used_dti_channels;
    if (!tst_id)
    {
      break;
    }
  }
  if (tst_id)
  {
    TRACE_EVENT("No DTI ID available");
    return (DTI_DTI_ID_NOTPRESENT);
  }
  used_dti_channels |= (0x01 << i);

  TRACE_EVENT_P1("DTI ID %d created", i);

  return (i);
}


LOCAL void dti_conn_remove_dti_id (UBYTE dti_id)
{
  ULONG tst_id;
  
  TRACE_FUNCTION("dti_conn_remove_id()");
  
  if (dti_id >= MAX_DTI_CONN_CHANNELS)
    return;

  tst_id = 0x01 << (dti_id);
  used_dti_channels &= ~tst_id;

  TRACE_EVENT_P1("DTI ID %d removed", dti_id);

}


LOCAL BOOL dti_conn_error_cb(UBYTE dti_id, T_DTI_CONN_STATE result_type)
{
  /* theorically should not be called... Yet helpfull for testing */
  TRACE_FUNCTION("dti_conn_error_cb()");

  TRACE_EVENT("ERROR: DTI connection callback has not been initialized !");

  return FALSE;
}


LOCAL void dti_conn_reset_conn_parms( T_DTI_CONN_CHANNEL *dti_channel )
{

  UBYTE i,j;

  TRACE_FUNCTION("dti_conn_reset_conn_parms()");

  dti_channel->erase_channel = FALSE;
  dti_channel->num_of_conns  = 0;
  dti_channel->conn_cb       = dti_conn_error_cb;
  dti_channel->state         = DTI_CONN_STATE_DISCONNECTED;

  for (i=0; i<MAX_DTI_CONN_TUPLES; i++)
  {
    dti_channel->tuple_list[i].state = DTI_CONN_STATE_DISCONNECTED;
    for (j=0; j<NUM_OF_PEERS; j++)
    {
      dti_channel->tuple_list[i].peers[j].state  = DTI_CONN_STATE_DISCONNECTED;
      dti_channel->tuple_list[i].peers[j].ent_id = DTI_ENTITY_INVALID;
    }
  }
}


LOCAL BOOL DTItest_dti_id( UBYTE dti_id, void *elem)
{
  T_DTI_CONN_CHANNEL *dti_channel = (T_DTI_CONN_CHANNEL *)elem;

  if (dti_channel EQ NULL)
    return FALSE;
  if (dti_channel -> dti_id EQ dti_id )
    return TRUE;
  else
    return FALSE;
}

LOCAL T_DTI_CONN_TUPLE *dti_conn_find_dti_tuple( T_DTI_CONN_CHANNEL *dti_channel, UBYTE tuple_no)
{
   return &(dti_channel->tuple_list[tuple_no]);
}


LOCAL T_DTI_CONN_CHANNEL *dti_conn_find_dti_conn( UBYTE dti_id )
{
  T_DTI_CONN_CHANNEL *dti_channel;

  TRACE_FUNCTION("dti_conn_find_dti_conn()");
  
  /*find channel in list */
  dti_channel = find_element (dti_channel_list, dti_id, DTItest_dti_id);

  return dti_channel;
}


LOCAL BOOL dti_conn_connect( T_DTI_CONN_CHANNEL* dti_channel, 
                              T_DTI_ENTITY_ID*   entity_list, 
                              UBYTE              num_entities, 
                              T_DTI_CONN_MODE    mode )
{
  ULONG link_id;
  UBYTE tuple_no;
  UBYTE i;

  TRACE_FUNCTION("dti_conn_connect()");

  dti_channel->state = DTI_CONN_STATE_CONNECTING;

  if (dti_channel->conn_cb)
  {
    (void )dti_channel->conn_cb(dti_channel->dti_id, DTI_CONN_STATE_CONNECTING);
  }
  else
  {
    TRACE_EVENT("conn_cb is NULL");
  }


  if (mode EQ APPEND)
  {
    tuple_no = dti_channel->num_of_conns;
  }
  else /* SPLIT */
  {
    tuple_no = 0;
    dti_channel->num_of_conns = 0;
  }

  for (i=0; i<num_entities-1; i++)
  {
    dti_channel->tuple_list[tuple_no].peers[0].ent_id = entity_list[i];
    dti_channel->tuple_list[tuple_no].peers[1].ent_id = entity_list[i+1];

    if ( (dti_channel->tuple_list[tuple_no].state NEQ DTI_CONN_STATE_DISCONNECTING) AND
         (dti_channel->tuple_list[tuple_no].state NEQ DTI_CONN_STATE_CONNECTING) )
    {
      dti_channel->tuple_list[tuple_no].state = DTI_CONN_STATE_CONNECTING;
      dti_channel->tuple_list[tuple_no].tuple_no = tuple_no;
      dti_channel->state = DTI_CONN_STATE_CONNECTING;

      link_id = dti_conn_compose_link_id(0, 0, dti_channel->dti_id, tuple_no);

      dti_channel->tuple_list[tuple_no].peers[0].state = DTI_CONN_STATE_CONNECTING;
      dti_channel->tuple_list[tuple_no].peers[1].state = DTI_CONN_STATE_CONNECTING;

      /* connect a tuple */
     (void) glob_params.mng_ent_cb(link_id, entity_list[i], entity_list[i+1], DTI_CONNECT);
      (void)glob_params.mng_ent_cb(link_id, entity_list[i+1], entity_list[i], DTI_CONNECT);
    }

    tuple_no++;
  }

  dti_channel->num_of_conns = tuple_no;

  return TRUE;
}


LOCAL BOOL dti_conn_disconnect( T_DTI_CONN_CHANNEL* dti_channel )
{
  ULONG link_id;
  UBYTE i;

  TRACE_FUNCTION("dti_conn_disconnect()");

  dti_channel->state = DTI_CONN_STATE_DISCONNECTING;

  if (dti_channel->conn_cb)
  {
    (void)dti_channel->conn_cb(dti_channel->dti_id, DTI_CONN_STATE_DISCONNECTING);
  }
  else
  {
    TRACE_EVENT("conn_cb is NULL");
  }

  for (i=0; i < dti_channel->num_of_conns; i++)
  {

    /* set tuple state only if it is not already DISCONNECTED */
    if (dti_channel->tuple_list[i].state NEQ DTI_CONN_STATE_DISCONNECTED)
    {
      dti_channel->tuple_list[i].state = DTI_CONN_STATE_DISCONNECTING;
    }

    link_id = dti_conn_compose_link_id(0, 0, dti_channel->dti_id, i);

    /* disconnect only a connected entity */
    if (dti_channel->tuple_list[i].peers[0].state EQ DTI_CONN_STATE_CONNECTED  OR
		dti_channel->tuple_list[i].peers[0].state EQ DTI_CONN_STATE_CONNECTING    )
    {
      dti_channel->tuple_list[i].peers[0].state = DTI_CONN_STATE_DISCONNECTING;
      (void)glob_params.mng_ent_cb(link_id, dti_channel->tuple_list[i].peers[0].ent_id, 
                           dti_channel->tuple_list[i].peers[1].ent_id, DTI_DISCONNECT);
    }

    /* disconnect only a connected entity */
    if (dti_channel->tuple_list[i].peers[1].state EQ DTI_CONN_STATE_CONNECTED  OR
		dti_channel->tuple_list[i].peers[1].state EQ DTI_CONN_STATE_CONNECTING    )
    {
      dti_channel->tuple_list[i].peers[1].state = DTI_CONN_STATE_DISCONNECTING;
      (void)glob_params.mng_ent_cb(link_id, dti_channel->tuple_list[i].peers[1].ent_id, 
                            dti_channel->tuple_list[i].peers[0].ent_id, DTI_DISCONNECT);
    }
  }

  return TRUE;
}







/********************** GLOBAL FUNCTIONS *****************************/


GLOBAL T_DTI_CONN_LINK_ID dti_conn_compose_link_id(UBYTE dummy, UBYTE assoc, UBYTE dti_id, UBYTE tuple_no)
{
  T_DTI_CONN_LINK_ID link_id = 0;

  link_id += dummy;
  link_id <<= 8;
  link_id += assoc;
  link_id <<= 8;
  link_id += dti_id;
  link_id <<= 8;
  link_id += tuple_no;

  return link_id;
}


/*
+--------------------------------------------------------------------+
| PROJECT :                             MODULE  : DTI_CONN           |
| STATE   : code                        ROUTINE : dti_conn_init      |
+--------------------------------------------------------------------+

  PURPOSE : initialise the DTI Connection Manager

*/
GLOBAL void dti_conn_init( T_DTI_CONN_MNG_ENT_CB* mng_ent_cb )
{
  TRACE_FUNCTION("dti_conn_init()");

  dti_channel_list = new_list ();
 
  glob_params.conn_cb      = NULL;
  glob_params.mng_ent_cb   = mng_ent_cb;
  glob_params.num_entities = 0;

}


/*
+--------------------------------------------------------------------+
| PROJECT :                             MODULE  : DTI_CONN           |
| STATE   : code                        ROUTINE : dti_conn_new       |
+--------------------------------------------------------------------+

  PURPOSE : register new DTI channel

*/
GLOBAL UBYTE dti_conn_new(UBYTE dti_id )
{
  T_DTI_CONN_CHANNEL *dti_channel;

  TRACE_FUNCTION("dti_conn_new()");


  if (dti_id EQ DTI_DTI_ID_NOTPRESENT)
  {
    dti_id = dti_conn_get_new_dti_id ();
  }

  if (dti_id EQ DTI_DTI_ID_NOTPRESENT)
  {
    return (DTI_DTI_ID_NOTPRESENT);
  }

  /* search for an existing entry with correspondant dti_id */
  dti_channel = dti_conn_find_dti_conn (dti_id);

  if( dti_channel )
  {
    return (DTI_DTI_ID_NOTPRESENT); /* couldn't create a new entry */
  }

  ACI_MALLOC(dti_channel, sizeof(T_DTI_CONN_CHANNEL));

  dti_conn_reset_conn_parms (dti_channel);
  dti_channel->dti_id = dti_id;
  insert_list(dti_channel_list, dti_channel);

  return (dti_channel->dti_id);
}


/*
+---------------------------------------------------------------------+
| PROJECT :                            MODULE  : DTI_CONN             |
| STATE   : code                       ROUTINE : dti_conn_erase_entry |
+---------------------------------------------------------------------+

  PURPOSE :  erase entry from DTI channel list 

*/
GLOBAL void dti_conn_erase_entry(UBYTE dti_id)
{
  T_DTI_CONN_CHANNEL *dti_channel;

  TRACE_FUNCTION("dti_conn_erase_entry");

  /* find element to be erased */
  dti_channel = remove_element (dti_channel_list, dti_id, DTItest_dti_id);

  if( dti_channel NEQ NULL ) /* entry not erased yet */
    ACI_MFREE (dti_channel);

  dti_conn_remove_dti_id(dti_id);
}


/*
+-----------------------------------------------------------------------+
| PROJECT :               MODULE  : DTI_CONN                            |
| STATE   : code          ROUTINE : dti_conn_is_dti_channel_connected   |
+-----------------------------------------------------------------------+ 

  PURPOSE : returns TRUE if end-to-end DTI connection is connected and 
            the given entity is in this connection

*/
GLOBAL BOOL dti_conn_is_dti_channel_connected( T_DTI_ENTITY_ID ent_id, UBYTE dti_id )
{
  UBYTE count = 0;
  UBYTE i;
  UBYTE entity_found = FALSE;
  T_DTI_CONN_CHANNEL *dti_channel = dti_conn_find_dti_conn( dti_id );

  TRACE_FUNCTION("dti_conn_is_dti_channel_connected()");

  if (dti_channel EQ NULL)
  {
    TRACE_EVENT_P1("dti_channel for dti_id %d not found", dti_id);
    return FALSE;
  }

  for (i=0; i<dti_channel->num_of_conns; i++)
  {
    if ((dti_channel->tuple_list[i].peers[0].ent_id EQ ent_id) OR
        (dti_channel->tuple_list[i].peers[1].ent_id EQ ent_id))
    {
      entity_found = TRUE;
      break;
    }
  }

  if (entity_found EQ FALSE)
    return FALSE;

  if (dti_channel->state EQ DTI_CONN_STATE_CONNECTED)
  {
    return TRUE;
  }
  else
  {
    for (i=0; i<dti_channel->num_of_conns; i++)
    {
      if (dti_channel->tuple_list[i].state EQ DTI_CONN_STATE_CONNECTED)
      {
        count++;
      }
    }

    if (count EQ dti_channel->num_of_conns)
    {
      return TRUE;
    }
  }

  return FALSE;
}


/*
+--------------------------------------------------------------------------+
| PROJECT :               MODULE  : DTI_CONN                               |
| STATE   : code          ROUTINE : dti_conn_is_dti_channel_disconnected   |
+--------------------------------------------------------------------------+ 

  PURPOSE : returns TRUE if end-to-end DTI connection is disconnected

*/
GLOBAL BOOL dti_conn_is_dti_channel_disconnected( UBYTE dti_id )
{
  UBYTE count = 0;
  UBYTE i;
  T_DTI_CONN_CHANNEL *dti_channel = dti_conn_find_dti_conn( dti_id );

  TRACE_FUNCTION("dti_conn_is_dti_channel_disconnected()");


  if (dti_channel EQ NULL)
  {
    return TRUE;
  }

  if (dti_channel->state EQ DTI_CONN_STATE_DISCONNECTED)
  {
    return TRUE;
  }
  else
  {
    for (i=0; i<dti_channel->num_of_conns; i++)
    {
      if (dti_channel->tuple_list[i].state EQ DTI_CONN_STATE_DISCONNECTED)
      {
        count++;
      }
    }

    if (count EQ dti_channel->num_of_conns)
    {
      return TRUE;
    }
  }

  return FALSE;
}


/*
+---------------------------------------------------------------------+
| PROJECT :                             MODULE  : DTI_CONN            |
| STATE   : code                        ROUTINE : dti_conn_est_dpath  |
+---------------------------------------------------------------------+

  PURPOSE : establishes data path.

*/
GLOBAL BOOL dti_conn_est_dpath( UBYTE               dti_id,
                                T_DTI_ENTITY_ID*    entity_list,
                                UBYTE               num_entities,
                                T_DTI_CONN_MODE     mode,
                                T_DTI_CONN_CB*      cb)
{
  T_DTI_CONN_CHANNEL *dti_channel;

  TRACE_FUNCTION("dti_conn_est_dpath()");


  /*find channel in list */
  dti_channel = dti_conn_find_dti_conn (dti_id);

  if (dti_channel EQ NULL)
  {
    TRACE_EVENT_P1("[ERR] dti_conn_est_dpath: dti_channel dti_id=%x not found",
                   dti_id);
    /* DTI ID not found */
    return FALSE;
  }
  
  if ( entity_list[0] EQ DTI_ENTITY_INVALID OR entity_list[1] EQ DTI_ENTITY_INVALID)
  {
    /* improper entity list */
    TRACE_EVENT("[ERR] improper entity list ");
    return FALSE;
  }

  /* if 'SPLIT' then the whole DTI channel must be disconnected before a 
   * new connection is established 
   */
  if ((mode EQ SPLIT) AND (dti_channel->state NEQ DTI_CONN_STATE_DISCONNECTED))
  {
    dti_conn_disconnect (dti_channel);
    
    /* save new entity list to entity list buffer */
    memcpy(glob_params.entity_list_buf, entity_list, sizeof(T_DTI_ENTITY_ID)*num_entities);
    glob_params.num_entities = num_entities;
    glob_params.conn_cb = cb;
  }
  else
  {
    dti_channel->conn_cb = cb;
    dti_conn_connect (dti_channel, entity_list, num_entities, mode);
  }

  return TRUE;
}


/*
+---------------------------------------------------------------------+
| PROJECT :                           MODULE  : DTI_CONN              |
| STATE   : code                      ROUTINE : dti_conn_close_dpath  |
+---------------------------------------------------------------------+

  PURPOSE : closes a DTI connection

*/
GLOBAL BOOL dti_conn_close_dpath( UBYTE dti_id )
{
  T_DTI_CONN_CHANNEL *dti_channel;

  TRACE_FUNCTION("dti_conn_close_dpath()");


  dti_channel = dti_conn_find_dti_conn( dti_id );
  if (dti_channel EQ NULL)
  {
    TRACE_EVENT_P1("[ERR] dti_conn_close_dpath: dti_channel dti_id=%x not found",
                   dti_id);
    return FALSE;
  }

  if (dti_channel->state NEQ DTI_CONN_STATE_DISCONNECTED)
  {
    dti_channel->state = DTI_CONN_STATE_DISCONNECTING;
        
    dti_conn_disconnect (dti_channel);
  }
  else
  {
    TRACE_EVENT("[ERR] dti_conn_close_dpath: try to close dpath which was DISCONNECTED");
    return FALSE;
  }

  return TRUE;
}


/*
+-----------------------------------------------------------------------+
| PROJECT :                        MODULE  : DTI_CONN                   |
| STATE   : code                   ROUTINE : dti_conn_entity_connected  |
+-----------------------------------------------------------------------+

  PURPOSE : response after a DTI connect request. This function is called 
            to inform the DTI Connection Manager that a connection is 
            established.

*/
GLOBAL void dti_conn_entity_connected( T_DTI_CONN_LINK_ID link_id, 
                                       T_DTI_ENTITY_ID    ent_id, 
                                       T_DTI_CONN_RESULT  result )
{
  T_DTI_CONN_CHANNEL    *dti_channel;
  T_DTI_CONN_TUPLE      *tuple;
  UBYTE                 i;
  UBYTE                 dti_id = EXTRACT_DTI_ID(link_id);
  BOOL                  both_entities_connected = FALSE;
  UBYTE                 count = 0;

  TRACE_FUNCTION("dti_conn_entity_connected()");


  dti_channel = dti_conn_find_dti_conn( dti_id );
  if (dti_channel EQ NULL)
  {
    TRACE_EVENT_P1("[ERR] dti_conn_entity_connected: dti_channel link_id=%x not found",
                   link_id);
    return;
  }

  if (result EQ DTI_ERROR)
  {
    /* mark entity as disconnected */
    dti_conn_entity_disconnected( link_id, ent_id );

    /* close the whole DTI channel */
    dti_conn_close_dpath( dti_id );
    return;
  }

  if (dti_channel->state EQ DTI_CONN_STATE_CONNECTED)
  {
    TRACE_EVENT_P1("dti channel with dti_id=%x already connected", dti_id);
    return;
  }

  tuple = dti_conn_find_dti_tuple( dti_channel, EXTRACT_TUPLE_NO(link_id ) );

  for (i=0; i<NUM_OF_PEERS; i++)
  {
    if (tuple->peers[i].state EQ DTI_CONN_STATE_CONNECTED)
    {
      count++;
    }

    if (tuple->peers[i].ent_id EQ ent_id)
    {
      if (tuple->peers[i].state EQ DTI_CONN_STATE_CONNECTING)
      {
        tuple->peers[i].state = DTI_CONN_STATE_CONNECTED;
        count++;
      }
    }
    if (count EQ NUM_OF_PEERS)
    {
      both_entities_connected = TRUE;
    }
  }

  /* if both entities are CONNECTED */
  if (both_entities_connected)
  {
    tuple->state = DTI_CONN_STATE_CONNECTED;

    /* if all other tuples CONNECTED */
    if (dti_conn_is_dti_channel_connected(ent_id, dti_id))
    {
      dti_channel->state = DTI_CONN_STATE_CONNECTED;

      TRACE_EVENT_P1("DTI ID %d connected", dti_id);
      
      /* call connect_cb here */
      if (dti_channel->conn_cb)
      {
        (void)dti_channel->conn_cb(dti_id, DTI_CONN_STATE_CONNECTED);
      }
      else
      {
        TRACE_EVENT("conn_cb is NULL");
      }
    }
  }
}


/*
+-----------------------------------------------------------------------+
| PROJECT :                     MODULE  : DTI_CONN                      |
| STATE   : code                ROUTINE : dti_conn_entity_disconnected  |
+-----------------------------------------------------------------------+

  PURPOSE : response after a DTI connect request. This function is called 
            to inform the DTI Connection Manager that a connection is 
            closed.

*/
GLOBAL void dti_conn_entity_disconnected( T_DTI_CONN_LINK_ID link_id, T_DTI_ENTITY_ID ent_id )
{
  T_DTI_CONN_CHANNEL    *dti_channel;
  T_DTI_CONN_TUPLE      *tuple;
  UBYTE                 i;
  UBYTE                 dti_id = EXTRACT_DTI_ID(link_id);
  UBYTE                 count = 0;

  TRACE_FUNCTION("dti_conn_entity_disconnected()");


  dti_channel = dti_conn_find_dti_conn( dti_id );
  if (dti_channel EQ NULL)
  {
    TRACE_EVENT_P1("[ERR] dti_conn_entity_disconnected: dti_channel link_id=%x not found",
                   link_id);
    return;
  }

  if (dti_channel->state EQ DTI_CONN_STATE_DISCONNECTED)
  {
    TRACE_EVENT_P1("dti channel with dti_id=%x already diconnected", dti_id);
    return;
  }


  tuple = dti_conn_find_dti_tuple( dti_channel, EXTRACT_TUPLE_NO(link_id) );

  for (i=0; i<NUM_OF_PEERS; i++)
  {
    if (tuple->peers[i].state EQ DTI_CONN_STATE_DISCONNECTED)
    {
      count++;
    }

    /* find disconnected entity */
    if (tuple->peers[i].ent_id EQ ent_id)
    {
      tuple->peers[i].state  = DTI_CONN_STATE_DISCONNECTED;
      tuple->peers[i].ent_id = DTI_ENTITY_INVALID;
      count++;

      tuple->state = DTI_CONN_STATE_DISCONNECTING;

      if (dti_channel->state EQ DTI_CONN_STATE_CONNECTED)
      {
        /* set DTI channel state */
        dti_channel->state = DTI_CONN_STATE_DISCONNECTING;
      }
    }
  }

  /* if both entities are DISCONNECTED */
  if (count EQ NUM_OF_PEERS)
  {
    /* set tuple state */
    tuple->state = DTI_CONN_STATE_DISCONNECTED;

    /* if all other tuples DISCONNECTED */
    if (dti_conn_is_dti_channel_disconnected(dti_id))
    {
      dti_channel->state = DTI_CONN_STATE_DISCONNECTED;

      TRACE_EVENT_P1("DTI ID %d disconnected", dti_id);

      /* reset number of conns */
      dti_channel->num_of_conns = 0;
      
      /* call disconnect_cb here */
      if (dti_channel->conn_cb)
      {
        (void)dti_channel->conn_cb(dti_id, DTI_CONN_STATE_DISCONNECTED);
      }
      else
      {
        TRACE_EVENT("conn_cb is NULL");
      }

      if (glob_params.num_entities NEQ 0)
      {
        dti_channel->conn_cb = glob_params.conn_cb;
        dti_conn_connect( dti_channel, glob_params.entity_list_buf, glob_params.num_entities, SPLIT );
        glob_params.num_entities = 0;
      }
      else
      {
        if (dti_channel->erase_channel EQ TRUE)
        {
          /* erase entry in DTI Conn Mng */
          dti_conn_erase_entry(dti_id);
        }
      }
    }
  }
}


/*
+-----------------------------------------------------------------------+
| PROJECT :                     MODULE  : DTI_CONN                      |
| STATE   : code                ROUTINE : dti_conn_close_all_connections|
+-----------------------------------------------------------------------+

  PURPOSE : This function is called to close all established DTI 
            connections.

*/
GLOBAL void dti_conn_close_all_connections()
{
  T_DTI_CONN_CHANNEL *dti_channel=NULL;

  TRACE_FUNCTION("dti_conn_close_all_connections()");
  
  while(TRUE)
  {
    dti_channel = get_next_element (dti_channel_list, dti_channel);
    if (dti_channel EQ NULL)
    {
      return;
    }

    if (dti_channel->state EQ DTI_CONN_STATE_CONNECTED)
    {
      dti_conn_close_dpath(dti_channel->dti_id);
      dti_channel->erase_channel = TRUE;
    }
    else
    {
      dti_conn_erase_entry(dti_channel->dti_id);
    }
   }
}