/*
 ******************************************************************************
 *  Copyright 1998 DeltaLink bv. All Rights Reserved.
 ******************************************************************************
 *
 * File: sapi_ct.c
 *
 * This module contains the CT load function for the sapi driver.
 *
 */

#include  <stdlib.h>
#include  <string.h>
#include  <stdio.h>
#include  <stdarg.h>

#ifdef WIN32
#pragma warning( disable : 4121 )

#define NOMSG             			/* typedef MSG and associated routines */
#define _OLE2_H_          			/* no ole */

#include  <windows.h>
#include  <process.h>
#include  <signal.h>

#undef ERROR
#endif

#include  <flib.h>						 /* FactoryLink definitions */
#include  <fl_utils.h>
#include  <g_utils.h>

#pragma warning( disable : 4214 )
#include  <imx.h>              /* Mailbox Communication Interface definitions */
#include  <imx_fmt.h>          /* Mailbox Communication Interface definitions */
#include  <imx_mt.h>           /* Mailbox Communication Interface definitions */
#pragma warning( default : 4214 )

#include  <protocol.h>				 /*  DeltaLink SAPI definitions */
#pragma warning( disable : 4115 )
#include  <sapi_s7.h>					 /*  Siemens SAPI definitions   */
#pragma warning( default : 4115 )
#include  <sapi.h>						 /*  DeltaLink SAPI definitions */

#define   PD_TABLE        0    /* Table 1 contains Protocol Drivers with DataSets */
#define   DC_TABLE        1    /* Table 0 contains the decoder mailbox tag */
#define   DEV_TABLE       2    /* Table 2 contains DataSets with overlay tags */

#define		DS_OFFSET_TBL   2
#define		MIN_CT_TABLES   3    /* Minimum number of required tbales */

#define   NORMAL_WRITE    1    /* normal exception write */
#define   ENCODED_WRITE   2    /* encoded exception write */

/*
 * structure to read in the SAPI protcol driver mailbox
 */
typedef struct
{
  TAG    mbx;									/* protocol driver mailbox */
  ushort nr_msg;							/* maximum number of messages in mailbox */

} PD_MBX;

/*
 * structure to read in the device headers
 */
typedef struct
{
	char		name[ 18 ];

	TAG			board_tag;
	char		board_name[ MAX_TAG_NAME +MAX_DIM_LENGTH +2 ];

	char		connection[ 20 ];				/* connection names as defined in softnet */
	ushort	ctype;									/* type of connection, CP or CPU */

	ushort	encode;									/* DB number for encoded write */

  TAG     status;									/* status tag of the device */
  TAG     c_count;								/* count of cyclic resources */
  TAG     disable[ 3 ];						/* disable tags */

} DEV_HDR;

/*
 * structure to read in the dataset records
 */
typedef  struct
{
  TAG    decoder;                                 /* decoder mailbox tag */
  TAG    ds_ctrl;                                 /* dataset control tag */
  char   name[ MAX_TAG_NAME +MAX_DIM_LENGTH +2];  /* dataset control tag name */

	ushort	type;
	ushort	db_nr;
	ushort	start;
	ushort	length;
   
  TAG    cyclic_read;                             /* start/stop cyclic reads */

} DS_REC;

/* prototypes of functions defined in this module */

void device_load( CT *, IMX_DEVICE *);
void load_decoders	( CT * );

IMXSYSTEM   Imxsys;											/* system parameters of the IMX library */
IMXSYSTEM   Thr_system;
//IMXSYSTEM   Cb_system;


/*-----------------------------------------------------------------------------
 * FUNCTION: void  ctload ( void )
 *
 * PUPRPOSE: Load task Configuration Table file.
 *
 * This file will typically be named:
 *  <app_dir>/ct/<task>.ct
 *
 * This code demonstrates how to use the standard FactoryLink
 * configuration table archive format.
 -----------------------------------------------------------------------------*/

void  ctload( void )
{
	static CT   ct_buf;										  /* Configuartion Archive buffer */
	int         num_cts,									  /* number of tables in the archive */
		          ct_count,										/* counter for processing tables */
			        ret,i;
	PD_MBX			pd;
	IMX_DEVICE	*imx_dev = NULL;										/* pointer to a logical IMX device */
	FLMSG					imx_buf;
	TAG         *imx_tag = NULL;										/* pointer to IMX event tags */
	void        **imx_data = NULL;									/* pointer to IMX event data */
	ulong       imx_num;										/* total number of IMX events */
	int         (**imx_fnc)( void *, VAL ) = NULL;	/* IMX function pointers */

  
  /* Open the CT archive file */

  if( ct_open( &ct_buf, "{FLAPP}", "{FLDOMAIN}/ct/sapi_s7.ct") != GOOD )
	{
		fl_status( &Task_win, "NOCT", FLS_INACTIVE);
    dl_exit_task( &Task_win, 1);
  }

		/* Determine the number of tables */

	if( ( num_cts = ct_get_ncts( &ct_buf )) < 3 )
	{
		fl_status( &Task_win, "NOTRIGGERS", FLS_INACTIVE);
		dl_exit_task( &Task_win, 1);
	}

	/*
	 * read first the decoder Mailbox Tag
	 */
	if ( ct_read_index( &ct_buf, PD_TABLE ) != GOOD )
	{
		fl_status( &Task_win, "CT_READ_INDEX", FLS_INACTIVE);
		dl_exit_task( &Task_win, 1);
	}

	if ( ct_read_rec( &ct_buf, &pd.mbx, 0) != GOOD)
	{
		fl_status( &Task_win, "CT_READ_REC", FLS_INACTIVE);
		dl_exit_task( &Task_win, 1);
	}

	/*
	 * allocate receive buffer for receiving all IMX messages
	 */
	Imx_buf.m_max = RX_BUF_SIZE;

	if( ( Imx_buf.m_ptr = ( char *)calloc( RX_BUF_SIZE, sizeof( char ))) == ( char *)0 )
	{
		fl_status( &Task_win, "NOMEMORY", FLS_INACTIVE);
		dl_exit_task( &Task_win, 1);
	}

	/*
	 * allocate receive buffer for receiving all SAPI events
	 */
	Sapi_buf.m_max = RX_BUF_SIZE;

	if( ( Sapi_buf.m_ptr = ( char *)calloc( RX_BUF_SIZE, sizeof( char ))) == ( char *)0 )
	{
		fl_status( &Task_win, "NOMEMORY", FLS_INACTIVE);
		dl_exit_task( &Task_win, 1);
	}

	/*
	 * load the configured decoders
	 */
	load_decoders( &ct_buf );

	/*
	 * initialize the IMX library
	 */
	Imx_Sys_Set_Task_Id   ( &Imxsys, Task_win.id );                  /* set the task id number [20] */
	Imx_Sys_Set_Station_Id( &Imxsys, ( char)Task_win.station_id );   /* set the unique station id number [0]*/
	Imx_Sys_Set_Mbx       ( &Imxsys, pd.mbx );                   /* IMX mailbox of this task [sapi mailbox 5 23]*/
	Imx_Sys_Set_Functions ( &Imxsys, IMX_ALL_FNC );              /* all active IMX functions supported */

	if( ( ret = Imx_Init( &Imxsys )) != GOOD )
	{
		fl_status( &Task_win, "IMX_INIT", FLS_INACTIVE, ret);
		dl_exit_task( &Task_win,1);
	}

  /* copy the MCI system structure */
  memcpy( &Thr_system, &Imxsys, sizeof( IMXSYSTEM ) );
  //memcpy( &Cb_system, &Imxsys, sizeof( IMXSYSTEM ) );

  Imx_Sys_Set_Task_Id( &Thr_system, Task_fl->id ); /* set the task id number */
  //Imx_Sys_Set_Task_Id( &Cb_system, Callback.id );  /* set the task id number */

  /*
   * allocate only one IMX device object
   */
  if ( ( imx_dev = ( IMX_DEVICE *)calloc( 1, sizeof( IMX_DEVICE ))) == ( IMX_DEVICE *)0 )
  {
    fl_status( &Task_win, "NOMEMORY", FLS_ERROR);
    dl_exit_task( &Task_win, 1);
  }

	if( ( ret = Imx_MT_Init( &Imxsys )) != GOOD )
	{
		fl_status( &Task_win, "IMX_INIT", FLS_INACTIVE, ret);
		dl_exit_task( &Task_win, 1);
	}
	
  Imx_MT_Set_Name( imx_dev, "SAPI" );

  /*
   * set the thread functions for the different functionalities
   */
  Imx_MT_Set_Thread( imx_dev, IMX_MT_READ,  sapi_read );
  Imx_MT_Set_Thread( imx_dev, IMX_MT_WRITE, sapi_write );
	Imx_MT_Set_Thread( imx_dev, IMX_MT_RCV, NULL );

	/*
	 * allocate the buffers for reading the pipe in the read and write thread
	 */
	for ( i = 0; i < 3; i++ )
	{
		if (( imx_buf.m_ptr = ( char *)calloc( RX_BUF_SIZE + sizeof( MT_IMXDS ), sizeof( char ))) == ( char *)0)
		{
			fl_status( &Task_win, "NOMEMORY", FLS_ERROR);
			dl_exit_task( &Task_win, 1);
		}

		imx_buf.m_max = RX_BUF_SIZE + sizeof( MT_IMXDS );
		imx_buf.m_len = 0;

		Imx_MT_Set_Buffer( imx_dev, &imx_buf, i );
	}

	/*
	 * Loop through the tables, processing each in turn. First the tables with the
	 * general Protocol Driver information will be read (Table type 0). After these
	 * tables the overlays of the datasets will be read in.
	 */
	for( ct_count = DS_OFFSET_TBL; ct_count < num_cts; ct_count++ )
	{
		/* Read the index for this table */

		if ( ct_read_index( &ct_buf, ct_count ) != GOOD )
		{
			fl_status( &Task_win, "CTINDEX", FLS_INACTIVE);
			dl_exit_task( &Task_win, 1);
		}

		/* load the device information with all dataset defined */
		device_load( &ct_buf, imx_dev );
	}

	/*
	 * connect all devices
	 */
	connect_all( &Task_win);


  /*
   * create the threads for this device
   */
  if ( Imx_MT_CreateThread( imx_dev ) != GOOD )
  {
    fl_status( &Task_win, "IMX_CREATE_THREAD", FLS_ERROR );
    dl_exit_task( &Task_win, 1 );
  }

	/*
	 * register the IMX event list to the FactoryLink kernel. The first event of
	 * IMX must be added separate to the event list because the function differs
	 * from all other events.
	 */
	Imx_Event_Retrieve( &imx_tag, &imx_data, &imx_num, &imx_fnc);

  if (imx_fnc == NULL)
	{
		fl_status( &Task_win, "NO_DATASETS", FLS_ERROR);
		dl_exit_task( &Task_win, 1);
	}

  if( fl_add_events( &Task_win, &imx_tag[ 0], &imx_data[0], 1, &imx_fnc[0]) != GOOD)
	{
		fl_status( &Task_win, "FL_ADD_EVENTS", FLS_ERROR);
		dl_exit_task( &Task_win, 1);
	}

  debug_log( &Task_win, "Imx_Event_Retrieve voltooid", 2);
  if( fl_add_events( &Task_win, &imx_tag[ 1], &imx_data[ 1], ( u16)( imx_num -1), &imx_fnc[ 1]) != GOOD)
  {
    fl_status( &Task_win, "FL_ADD_EVENTS", FLS_ERROR);
    dl_exit_task( &Task_win, 1);
  }

  debug_log( &Task_win, "Imx_Event_Retrieve voltooid", 2);
  ct_close( &ct_buf );
}


/*-----------------------------------------------------------------------------
 * FUNCTION: void  device_load( CT *ct_buf )
 *
 * PUPRPOSE:
 -----------------------------------------------------------------------------*/
void device_load( CT *ct_buf, IMX_DEVICE *imx_dev)
{
  int						i;
  #ifndef _COMSIM
  int  error;
  #endif
  uint					rec_count,      /* counter for processing records */
								num_recs;
  IMXDS					t_ds,           /* dummy dataset for registering datasets */
								*ds;
	FLMSG						msg;
  DS_INFO				*ds_info;				/* temporary pointer to additional dataset information */
  DEV_HDR				header;					/* DeltaLink  Decoder Mailbox table */
  DS_REC				ds_rec;					/* DeltaLink  Datasets table */
  void					*event_data;
	int         (*imx_fnc)( void *, VAL ) = NULL;	/* IMX function pointers */
														  
	
	/* Read the table header */
	
  if ( ct_read_hdr( ct_buf, &header ) != GOOD )
	{
    fl_status( &Task_win, "CTHEADER", FLS_INACTIVE);
    dl_exit_task( &Task_win, 1);
  }
	
	/*
   * check if the decoder mailbox has been configured
	 */
	   
  //for( i = 0; i < Nr_decoders; i++ )
  //{
  //  if( CMPTAG( &ds_rec.decoder, &Decoder[ i].mbx ) )
  //    break;
  //}

  /*
   * check if there are any datasets defined in this device
   */
  if( ( num_recs = ct_get_nrecs( ct_buf )) == 0 )
	  return;

  /*
   * allocate additional device information
   */

  if( ( Device = ( DEVICE **)realloc( Device,
                                      sizeof( DEVICE *) * ( Nr_devices +1) )) == ( DEVICE **)0 )
  {
    fl_status( &Task_win, "NOMEMORY", FLS_ERROR);
    dl_exit_task( &Task_win, 1);
  }

  if( ( Device[ Nr_devices ] = ( DEVICE *)calloc( 1, sizeof( DEVICE ) )) == ( DEVICE *)0 )
  {
    fl_status( &Task_win, "NOMEMORY", FLS_ERROR);
    dl_exit_task( &Task_win, 1);
  }

  strcpy( Device[ Nr_devices ]->name, header.name );			/* device name of remote module */

	/* copy the connection names */

	strcpy( Device[ Nr_devices ]->connection, header.connection );

	Device[ Nr_devices ]->ctype = header.ctype;

  /*
   * Initialize the connection status as be ing disconnected and disabled
   */
  Device[ Nr_devices ]->connect = CS_DISCONNECTED;
  Device[ Nr_devices ]->disable[ IMX_READ ][ INTERNAL ] = 1;
  Device[ Nr_devices ]->disable[ IMX_WRITE ][ INTERNAL ] = 1;

	/*
	 * check if the board name will be set through tag or constant
	 */

	if ( fl_gettype( &header.board_tag ) != FL_UNDEFINED )
	{
		/* read the initial board name value */

		msg.m_ptr = header.board_name;
		msg.m_max = MAX_TAG_NAME +MAX_DIM_LENGTH +2;

		if( fl_read( Task_win.id, &header.board_tag, 1, &msg ) != GOOD )
		{
      fl_status( &Task_win, "FL_READ", FLS_ERROR );
      dl_exit_task( &Task_win, 1 );
		}

		event_data = ( void *)Device[ Nr_devices ];
    imx_fnc = set_board;
		if( fl_add_events( &Task_win,
                           &header.board_tag,
                           &event_data,
                           1,
                           &imx_fnc ) != GOOD )
		{
			fl_status( &Task_win, "FL_ADD_EVENTS", FLS_ERROR);
			dl_exit_task( &Task_win, 1);
		}
	}

	strcpy( Device[ Nr_devices ]->board_name, header.board_name );

	if ( create_sem( Device[ Nr_devices ] ) != 0 )
  {
    fl_status( &Task_win, "CREATE_SEM", FLS_ERROR);
    dl_exit_task( &Task_win, 1);
  }

	/* update the board pointer on the device structure */

	Device[ Nr_devices ]->encode = header.encode;						/* DB number for encoded write */
  Device[ Nr_devices ]->status = header.status;           /* status tag of the device */
  Device[ Nr_devices ]->c_count= header.c_count;          /* cyclic count of resources */

  #ifndef _COMSIM

	if ( ( error = sapi_board_init( &Task_win, Device[ Nr_devices ] ) ) != GOOD )
	{
		fl_status( &Task_win, "INIT_BOARD", FLS_ERROR, error );
		dl_exit_task( &Task_win, 1);
	}

  #endif

  /* 
	 * set the additional device information, will not be used in the eventual thread 
	 * because this value is everytime overwritten
	 */
  Imx_MT_Set_DevInfo( imx_dev, Device[ Nr_devices ] );

  /*
   * Add the disable tags in case these are defined
   */
  for ( i = 0; i < 3; i++ )
  {
    if ( fl_gettype( &header.disable[ i ]) != FL_UNDEFINED )
    {
      event_data = ( void *)&Device[ Nr_devices ]->disable[ i ][0];
      imx_fnc = disable_fnc;
      if( fl_add_events(  &Task_win,
                          &header.disable[ i ],
                          &event_data,
                          1,
                          &imx_fnc ) != GOOD)
      {
        fl_status( &Task_win, "FL_ADD_EVENTS", FLS_ERROR);
        dl_exit_task( &Task_win, 1);
      }

		  if( fl_set_chng( Task_win.id, &header.disable[ i ], 1 ) != GOOD )
		  {
        fl_status( &Task_win, "FL_SET_CHNG", FLS_ERROR );
        dl_exit_task( &Task_win, 1 );
		  }
    }

	  /* allocate the communications buffers for the devices */

    if ( ( Device[ Nr_devices ]->buffer[ i ] = ( char *)calloc( 1, BUFFER_SIZE )) == ( char *)0 )
    {
      fl_status( &Task_win, "NOMEMORY", FLS_ERROR);
      dl_exit_task( &Task_win, 1);
    }
  }

  /*
   * read all datasets specified
   */
  for( rec_count = 0; rec_count < num_recs; rec_count++ )
  {
    /* read the record with dataset information from the CT file */

    if ( ct_read_rec( ct_buf, &ds_rec, rec_count) != GOOD )
		{
      fl_status( &Task_win, "CTRECORD", FLS_INACTIVE);
      dl_exit_task( &Task_win, 1);
    }

    /*
     * get information of the mailbox tag and verify
     */
    if( fl_gettype( &ds_rec.decoder ) != FL_MAILBOX )
		{
      fl_status( &Task_win, "BAD_MAILBOX", FLS_ERROR, ct_get_name( ct_buf ), rec_count );
      dl_exit_task( &Task_win, 1);
    }

    /*
     * check if the decoder mailbox has been configured
     */
    for( i = 0; i < Nr_decoders; i++ )
    {
      if( CMPTAG( &ds_rec.decoder, &Decoder[ i].mbx ) )
        break;
    }

    if( i == Nr_decoders)
		{
      fl_status( &Task_win, "UNKNOWN_DEC", FLS_ERROR, ct_get_name( ct_buf ), rec_count );
      dl_exit_task( &Task_win, 1);
    }

    /* allocate the additional dataset information buffer */

    if( ( ds_info = ( DS_INFO *)calloc( 1, sizeof( DS_INFO) )) == ( DS_INFO *)0 )
		{
      fl_status( &Task_win, "NOMEMORY", FLS_INACTIVE);
      dl_exit_task( &Task_win, 1);
    }

    /* set the defined parameters of the dataset */

    memset( &t_ds, 0x00, sizeof( IMXDS ));              /* reset the temporary dataset */
    memset( Imx_buf.m_ptr, 0x00, sizeof( IMXHDR ));     /* reset the dataset header */

    Imx_Set_Snd_Mbx   ( &t_ds, ds_rec.decoder );				/* decoder driver mailbox */
    Imx_Set_Ds_Ctrl   ( &t_ds, ds_rec.ds_ctrl);					/* dataset control tag */
    Imx_Set_Name      ( &t_ds, ds_rec.name);						/* name of the dataset control tag */

    Imx_Set_Udata_Ptr ( &t_ds, ds_info);                /* additional dataset information */
    Imx_Set_Ufnc_Ptr  ( &t_ds, imx_event);              /* user function for these events */

    Imx_Set_R_Buffer  ( &t_ds, &Imx_buf);               /* set receive buffer for registation */
    Imx_Set_T_Buffer  ( &t_ds, &Imx_buf);               /* set also temporary buffer for registation */

		/* load all parameter on the additional dataset information structure */

    ds_info->max_msg = Decoder[ i ].max_msg;            /* maximum number of messages in mailbox */

		ds_info->device = ( DEVICE * )Imx_MT_Get_DevInfo ( imx_dev );

    /*
     * check if the cyclic read tag has been defined and if so, add to the events
     */
	  if ( fl_gettype( &ds_rec.cyclic_read ) != FL_UNDEFINED )
	  {
		  /* read the initial cyclic read value */

		  if( fl_read( Task_win.id, &ds_rec.cyclic_read, 1, &ds_info->cyclic_read ) != GOOD )
		  {
        fl_status( &Task_win, "FL_READ", FLS_ERROR );
        dl_exit_task( &Task_win, 1 );
		  }

		  event_data = ( void *)ds_info;

      imx_fnc = cyclic_read;
		  if( fl_add_events(  &Task_win,
												  &ds_rec.cyclic_read,
												  &event_data,
												  1,
												  &imx_fnc ) != GOOD )
		  {
			  fl_status( &Task_win, "FL_ADD_EVENTS", FLS_ERROR);
			  dl_exit_task( &Task_win, 1);
		  }

      /* trigger the cyclic read tag to start the cyclic read */

		  /*if( fl_set_chng( Task_win.id, &ds_rec.cyclic_read, 1 ) != GOOD )
		  {
        fl_status( &Task_win, "FL_SET_CHNG", FLS_ERROR );
        dl_exit_task( &Task_win, 1 );
		  }*/
	  }

    /* 
     * update the dataset information in the dataset object 
     *
     * Depending on the DB number the type may be changed. 
     * The H1 protocol does NOT support DB number above 255,
     * to be able to support higher numbers the type is changed!
     *
     * For DB > 255 the type is calculated as follows:
     *        type = (DB NO. MOD 256) + 119       
     * So for DB numbers between 256 and 511 the type is 120!
     * The DB number is lower to a valaue less then 256.
     * The PLC calculates the original DB number from the type
     * and the (new) DB number
     */

    if ( Device[ Nr_devices ]->ctype == S7_CPU_DEVICE &&  
			   ( ds_rec.type == H1_DB ) && 
				 ( ds_rec.db_nr > 255 )
			 )
    {
      /* here is the caluculation of the type */      

      ds_info->type = (ds_rec.db_nr / 256) + 119;
      ds_info->db_nr = (uchar)(ds_rec.db_nr % 256);
    }
    else
    {
      ds_info->type  = ds_rec.type;
      ds_info->db_nr = ds_rec.db_nr;
    }

    Imx_Set_Start ( &t_ds, ds_rec.start);
    Imx_Set_Len   ( &t_ds, ds_rec.length);

    /* 
     * set the boundary addressing of this dataset in case global parameters
     * are used
     */
    switch ( ds_rec.type )
    {
      case RW_BYTEL:          /* device */

        /* set the IMX parameters for this dataset */

        Imx_Set_Boundary    ( &t_ds, IMX_BYTE_BND);
        Imx_Set_Bnd_Dir     ( &t_ds, IMX_LOW_2_HIGH);
        Imx_Set_Bit_Dir     ( &t_ds, IMX_LOW_2_HIGH);

        break;

      case RW_WORDL:          /* device */

        /* set the IMX parameters for this dataset */

        Imx_Set_Boundary    ( &t_ds, IMX_WORD_BND);
        Imx_Set_Bnd_Dir     ( &t_ds, IMX_LOW_2_HIGH);
        Imx_Set_Bit_Dir     ( &t_ds, IMX_LOW_2_HIGH);

        break;

      case RW_LONGL:          /* device with long boundary and low to high direction */

        /* set the IMX parameters for this dataset */

        Imx_Set_Boundary    ( &t_ds, IMX_LONG_BND);
        Imx_Set_Bnd_Dir     ( &t_ds, IMX_LOW_2_HIGH);
        Imx_Set_Bit_Dir     ( &t_ds, IMX_LOW_2_HIGH);

        break;

      case RW_BYTEH:          /* device */

        /* set the IMX parameters for this dataset */

        Imx_Set_Boundary    ( &t_ds, IMX_BYTE_BND);
        Imx_Set_Bnd_Dir     ( &t_ds, IMX_HIGH_2_LOW);
        Imx_Set_Bit_Dir     ( &t_ds, IMX_HIGH_2_LOW);

        break;

      case RW_WORDH:             /* device with word boundary and high to low direction */

        /* set the IMX parameters for this dataset */

        Imx_Set_Boundary    ( &t_ds, IMX_WORD_BND);
        Imx_Set_Bnd_Dir     ( &t_ds, IMX_HIGH_2_LOW);
        Imx_Set_Bit_Dir     ( &t_ds, IMX_HIGH_2_LOW);

        break;

      case RW_LONGH:             /* device with long boundary and high to low direction */


        /* set the IMX parameters for this dataset */

        Imx_Set_Boundary    ( &t_ds, IMX_LONG_BND);
        Imx_Set_Bnd_Dir     ( &t_ds, IMX_HIGH_2_LOW);
        Imx_Set_Bit_Dir     ( &t_ds, IMX_HIGH_2_LOW);

        break;

			default:

        Imx_Set_Boundary    ( &t_ds, IMX_BYTE_BND );
        Imx_Set_Bnd_Dir     ( &t_ds, IMX_HIGH_2_LOW);
        Imx_Set_Bit_Dir     ( &t_ds, IMX_HIGH_2_LOW);

        Imx_Set_Bnd_Offset  ( &t_ds, 0);
        Imx_Set_Bit_Offset  ( &t_ds, 0);

				break;
    }

    /* register the dataset to the IMX library */

    if( ( ds = Imx_MT_Ds_Register( &t_ds, imx_dev )) == NULL )
		{
      fl_status( &Task_win, "IMX_DS_REGISTER", FLS_INACTIVE, ds_rec.name);
      dl_exit_task( &Task_win, 1);
    }

		/* alocate pointer in the device DS array */

    if ((ds_info->device->dataset = (IMXDS **)realloc( ds_info->device->dataset, 
																											 ((ds_info->device->Nr_Datasets+1)* sizeof( IMXDS **)) )) == ( IMXDS **)0 )
		{
      fl_status( &Task_win, "NOMEMORY", FLS_INACTIVE);
      dl_exit_task( &Task_win, 1 );
    }

    ds_info->ds_index = ds_info->device->Nr_Datasets;
		ds_info->device->dataset[ ds_info->device->Nr_Datasets++ ] = ds;

		/* alocate pointer in the global DS array */

    if ( ( Ds = ( IMXDS **)realloc( Ds, ( ( Nr_ds +1) * sizeof( IMXDS **)) )) == ( IMXDS **)0 )
		{
      fl_status( &Task_win, "NOMEMORY", FLS_INACTIVE);
      dl_exit_task( &Task_win, 1 );
    }

		Ds[ Nr_ds ] = ds;

		/* update the additional info with the index to this dataset */

		//ds_info->ds_index = Nr_ds++;
    Nr_ds++;
  }

	/* increase the total number of devices */

	Nr_devices++;

  return;
}


/*-----------------------------------------------------------------------------
 * FUNCTION: void  load_decoders(void)
 *
 * PUPRPOSE: Load all configured decoders.
 *
 -----------------------------------------------------------------------------*/
void load_decoders( CT *ct_buf )
{
  uint   rec;                      /* counter for processing records */
  i16    info;                     /* TAG information */


  /* set the index to the decoder table */

  if( ct_read_index( ct_buf, DC_TABLE) != GOOD )
  {
    fl_status( &Task_win, "CTINDEX", FLS_ERROR);
    dl_exit_task( &Task_win, 1);
  }

  /* determine the number of decoders */

  if( ( Nr_decoders = (ushort)ct_get_nrecs( ct_buf)) == 0 )
  {
    fl_status( &Task_win, "NO_DECODERS", FLS_ERROR);
    dl_exit_task( &Task_win, 1);
  }

  /* allocate space for the decoders */

  if( ( Decoder = ( XLATOR *)calloc( Nr_decoders, sizeof( XLATOR ))) == ( XLATOR *)0 )
  {
    fl_status( &Task_win, "NOMEMORY", FLS_ERROR);
    dl_exit_task( &Task_win, 1);
  }

  /* process every record in this CT file */

  for( rec = 0; rec < Nr_decoders; rec++)
  {
    /* read the total record in */

    if ( ct_read_rec( ct_buf, &Decoder[ rec], rec) != GOOD )
    {
      fl_status( &Task_win, "CTRECORD", FLS_ERROR);
      dl_exit_task( &Task_win, 1);
    }

    /*
     * get information of the mailbox tag and verify
     */
    fl_get_tag_info( &Decoder[ rec].mbx, 1, &info, ( u16 *)0);

    if ( info != FL_MAILBOX )
    {
      fl_status( &Task_win, "BAD_MAILBOX", FLS_ERROR, ct_get_name( ct_buf), rec, info);
      dl_exit_task( &Task_win, 1);
    }
  }

  return;
}

