/*
 ******************************************************************************
 *  Copyright 1995 DeltaLink bv. All Rights Reserved.
 ******************************************************************************
 *
 * DeltaLink Decoder Task
 *
 * File: dec_ct.c
 *
 * This file contains the ct_load function for the DeltaLink  Decoder Task
 *
 */

#include  <stdlib.h>
#include  <string.h>
#include  <stdio.h>
#include  <stdarg.h>

#include  <flib.h>             /* FactoryLink definitions */

#include  <fl_utils.h>

#include  <mci3.h>             /* Mailbox Communication Interface definitions */
#include  <format3.h>          /* Mailbox Communication Interface definitions */

#include  <decoder.h>          /* DeltaLink  Protocol Decoder definitions */

#define   DC_TABLE        0    /* Table 0 contains the Decoder Mailbox Tag */
#define   PD_TABLE        1    /* Table 1 contains Protocol Drivers with DataSets */
#define   TAGS_TABLE      2    /* Table 2 contains DataSets with overlay tags */

#define   NORMAL_WRITE    1    /* normal exception write */
#define   ENCODED_WRITE   2    /* encoded exception write */
 
/*
 * structure to read in the DeltaLink  Decoder Mailbox table which contans
 * information about the Protocol Driver
 */
 
#ifndef HPUX
#pragma pack(1)
#else
#pragma HP_ALIGN HPUX_WORD PUSH
#endif

typedef  struct {

  TAG    pd_mbx;            /* Protocol Driver mailbox */
  ushort nr_msg;            /* maximum number of messages in mailbox */
  ushort lan;               /* mailbox via lan */

} PD_HDR;

/*
 * structure to read in the DeltaLink  Datasets tables
 */
typedef  struct {

  TAG    ds_ctrl;             										/* dataset control tag */
  char   name[ MAX_TAG_NAME	+MAX_DIM_LENGTH	+2];	/* dataset control tag name */
  TAG    read;																		/* read trigger */
  TAG    write;																		/* write trigger */

  ushort f_read;																	/* flag for enabling read function */
  ushort f_excep;																	/* flag for enabling exception write function */
  ushort f_block;																	/* flag for enabling block write function */
  ushort f_unsol;																	/* flag for enabling unsolicited receive function */

  ushort abs;																			/* absolute or relative addressing */

  TAG    status;																  /* completion tag for read function */

  TAG    read_rdy;																/* completion tag for read function */
  TAG    write_rdy;																/* completion tag for write function */
  TAG    rcv_rdy;																	/* completion tag for rcv function */

  TAG    read_disable;														/* disable tag for read function */
  TAG    write_disable;														/* disable tag for write function */
  TAG    rcv_disable;															/* disalbe tag for rcv function */

  TAG    read_sync;									    					/* sync. tag for read function */
  TAG    write_sync;							   							/* sync. tag for write function */
  TAG    rcv_sync;   															/* sync. tag for rcv function */

} PD_REC;

/*
 * structure to read in the DeltaLink  Datasets tables
 */
typedef  struct {

  TAG   pd_mbx;             /* Protocol Driver mailbox */
  TAG   ds_ctrl;            /* DataSet Control Tag */

} DS_HDR;


/*
 * structure to read in the DeltaLink  Decoder Tags tables
 */
typedef  struct {

  TAG    tag;                  /* overlay tag */
  char   tag_name[50];         /* tag name as specified in table */
  char   tag_dimension[18];    /* dimension of the tag */
  ushort address;              /* address of tag in dataset */
  ushort bit;                  /* bit number */
  ushort length;               /* length of array or string */
  ushort conv;                 /* conversion of data */

} DS_REC;

#ifndef HPUX
#pragma pack()
#else
#pragma HP_ALIGN POP
#endif

void  pd_load         ( CT *);
void  tag_load        ( CT *);

/*
 * variables for limitation demo and lite versions  
 */
#ifdef DEMOOO

int nr_demo_pd   = 1;            /* one protocol driver supported in demo mode */
int nr_demo_ds   = 8;            /* 8 datasets supported in demo mode */
int nr_demo_tags = 128;          /* 128 tags supported in lite mode */

int nr_lite_pd   = 2;            /* two protocol drivers supported in lite mode */
int nr_lite_ds   = 16;           /* 16 datasets supported in lite mode */
int nr_lite_tags = 256;          /* 256 tags supported in lite mode */

#endif

MCISYSTEM 	Mcisys;							/* system parameters of the mci library */


/*-----------------------------------------------------------------------------
 * 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) {

  CT  				ct_buf;             /* Configuartion Archive buffer */
	TAG					dc_mbx;							/* decoder's MCI mailbox tag */
  int 				num_cts,            /* number of tables in the archive */
      				ct_count,           /* counter for processing tables */
							ret;

  
  /* Open the CT archive file */

  if( ct_open( &ct_buf, "{FLAPP}", "{FLDOMAIN}/ct/decoder.ct") != GOOD ) {

    fl_status( &Task, "NOCT", FLS_INACTIVE);
    dl_exit_task( &Task, 1);
  }

  /* Determine the number of tables */

  if( ( num_cts = ct_get_ncts( &ct_buf)) < 3 )  {

    fl_status( &Task, "NOTRIGGERS", FLS_INACTIVE);
    dl_exit_task( &Task, 1);
  }

  /*
   * read first the Decoder Mailbox Tag
   */
  if ( ct_read_index( &ct_buf, 0) != GOOD ) {

    fl_status( &Task, "CTINDEX", FLS_INACTIVE);
    dl_exit_task( &Task, 1);
  }

  if ( ct_read_hdr( &ct_buf, &dc_mbx) != GOOD) {

    fl_status( &Task, "CTHEADER", FLS_INACTIVE);
    dl_exit_task( &Task, 1);
  }

  /*
   * allocate receive buffer for receiving all MCI messages
   */
	Rx_buf.m_max = RX_BUF_SIZE;

  if( ( Rx_buf.m_ptr = ( char *)calloc( RX_BUF_SIZE, sizeof( char))) == ( char *)0) {

    fl_status( &Task, "NOMEMORY", FLS_INACTIVE);
    dl_exit_task( &Task, 1);
  }

  /*
   * initialize the MCI library
   */
	Mci_Sys_Set_Task_Id		( &Mcisys, Task.id);									/* set the task id number */
	Mci_Sys_Set_Station_Id( &Mcisys, ( char)Task.station_id);		/* set the unique station id number */
	Mci_Sys_Set_Mbx				( &Mcisys, dc_mbx);										/* MCI mailbox of this task */
	Mci_Sys_Set_Functions	( &Mcisys, MCI_NO_FNC);								/* no active MCI functions supported */

  if( ( ret = Mci_Init( &Mcisys)) != GOOD) {

    fl_status( &Task, "IMX_INIT", FLS_INACTIVE, ret);    /*  indicate normal stop */
    dl_exit_task( &Task,1);                              /*  exit to OS */
  }

  /*
   * Allocate a tag array for holding tag values in the update routine
   */

  if (( Tags = ( TAG *)calloc( 50000, sizeof( TAG ))) == ( TAG *)0)
  {
    fl_status( &Task, "NOMEMORY", FLS_ERROR);
    dl_exit_task( &Task,1);                              /*  exit to OS */
  }

  /* allocate space to hold the tags which must be updated */

  if (( Chbits = ( u16 *)calloc( 50000, sizeof( u16 ))) == ( u16 *)0)
  {
    fl_status( &Task, "NOMEMORY", FLS_ERROR);
    dl_exit_task( &Task,1);                              /*  exit to OS */
  }

  /*
   * 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 = 1; ct_count < num_cts; ct_count++ ) {

    /* Read the index for this table */

    if ( ct_read_index( &ct_buf, ct_count) != GOOD ) {

      fl_status( &Task, "CTINDEX", FLS_INACTIVE);
      dl_exit_task( &Task, 1);
    }

    /* check what table type and call the appropiate function */

    if( ct_get_type( &ct_buf) == PD_TABLE) {

      pd_load( &ct_buf);

      /*
       * check the number of protocol drivers when running in demo mode
       */
#ifdef DEMOOO
      if( Task.mode & LIC_DEMO) {

        if( !nr_demo_pd) break;

        nr_demo_pd--;
      }

      /*
       * check the number of protocol drivers when running in lite mode
       */

      if( Task.mode & LIC_LITE) {

        if( !nr_lite_pd) break;

        nr_lite_pd--;
      }
#endif
    }
    else
      tag_load( &ct_buf);
  }

	/*
	 * register the only MCI event which is the receipt of MCI messages
	 */
	fl_add_events( &Task, &dc_mbx, NULL, 1, Mci_Event_Mbx);

  ct_close( &ct_buf);
}


/*-----------------------------------------------------------------------------
 * FUNCTION: void  pd_load( CT *ct_buf)
 *
 * PUPRPOSE:
 -----------------------------------------------------------------------------*/
void pd_load( CT *ct_buf) {

	int			ret;
  uint    rec_count,			/* counter for processing records */
					num_rec_ds;
	MCIDS		t_ds,							/* dummy dataset fir registering datasets */
					*ds;
	DS_INFO	*ds_info;					/* temporary pointer to additional dataset information */
  PD_HDR  hdr_buf;					/* DeltaLink  Decoder Mailbox table */
  PD_REC  rec_buf;					/* DeltaLink  Datasets table */

  /* Read the table header */

  if ( ct_read_hdr( ct_buf, &hdr_buf) != GOOD ) {

    fl_status( &Task, "CTHEADER", FLS_INACTIVE);
    dl_exit_task( &Task, 1);
  }

	/*
   * process every record and update the MCI datasets
   */
  num_rec_ds = ct_get_nrecs( ct_buf);

  /*
   * check the number of datasets when running in demo mode
   */
#ifdef DEMOOOO
  if( Task.mode & LIC_DEMO) {

    if( (nr_demo_ds - ( int)num_rec_ds) < 0) num_rec_ds = nr_demo_ds;

    nr_demo_ds -= num_rec_ds;
  }

  /*
   * check the number of datasets when running in lite mode
   */
  if( Task.mode & LIC_LITE) {

    if( (nr_lite_ds - ( int)num_rec_ds) < 0) num_rec_ds = nr_lite_ds;

    nr_lite_ds -= num_rec_ds;
  }
#endif

  /* if no datasets then return immediately */

  if( !num_rec_ds) return;

	/*
	 * read all datasets specified
	 */
  for( rec_count = 0; rec_count < num_rec_ds; rec_count++) {

		/* read the record with dataset information from the CT file */

    if ( ct_read_rec( ct_buf, &rec_buf, rec_count) != GOOD ) {

      fl_status( &Task, "CTRECORD", FLS_INACTIVE);
      dl_exit_task( &Task, 1);
    }

		/* allocate the additional dataset information buffer */

	  if( ( ds_info = ( DS_INFO *)calloc( 1, sizeof( DS_INFO))) == ( DS_INFO *)0) {

	    fl_status( &Task, "NOMEMORY", FLS_INACTIVE);
	    dl_exit_task( &Task, 1);
	  }

    ds_info->ct_start = 0xffff;

		/* set the defined parameters of the dataset */

		memset( &t_ds, 0x00, sizeof( MCIDS));								/* reset the temporary dataset */
		memset( Rx_buf.m_ptr, 0x00, sizeof( MCIHDR));				/* reset the dataset header */

		Mci_Set_Snd_Mbx		( &t_ds, hdr_buf.pd_mbx);					/* Protocol Driver Mailbox */
		Mci_Set_Ds_Ctrl		( &t_ds, rec_buf.ds_ctrl);				/* dataset control tag */
		Mci_Set_Name			( &t_ds, rec_buf.name);						/* name of the dataset control tag */

		Mci_Set_Udata_Ptr	( &t_ds, ds_info);								/* additional dataset information */
		Mci_Set_Ufnc_Ptr	( &t_ds, mci_event);							/* no MCI user function for these events */

		Mci_Set_R_Buffer	( &t_ds, &Rx_buf);								/* set receive buffer for registation */
		Mci_Set_T_Buffer	( &t_ds, &Rx_buf);								/* set also temporary buffer for registation */

  	ds_info->nr_msg = hdr_buf.nr_msg;             			/* maximum number of messages in mailbox */

    if( rec_buf.f_excep) { 															/* flag for enabling exception write function */

      if( rec_buf.f_excep == NORMAL_WRITE) {

        ds_info->fnc |= EW_MASK;   											/* normal exception */
				Mci_Set_Handling( &t_ds, MCI_NORMAL_WRITE);
			}
      else {

        ds_info->fnc |= CW_MASK;   														/* encoded exception */
				Mci_Set_Handling( &t_ds, MCI_ENCODED_WRITE);
			}
    }

    if( rec_buf.f_unsol )              												/* flag for enabling unsolicited receive function */
    {
      if ( rec_buf.f_unsol == NORMAL_FNC )
			  ds_info->fnc |= UR_MASK;
      else
      {
			  ds_info->fnc |= ERD_MASK | UR_MASK;
			  ds_info->start_check = 1;
      }
    }

		/* register the dataset to the MCI library */

		if( ( ds = Mci_Ds_Register( &t_ds)) == NULL) {

			fl_status( &Task, "IMX_DS_REGISTER", FLS_INACTIVE, rec_buf.name);
	    dl_exit_task( &Task, 1);
		}

		/* send a query message to protocol driver of the registered dataset */

		if( ( ret = Mci_Ds_Query( ds)) != GOOD) {

			fl_status( &Task, "IMX_DS_QUERY", FLS_INACTIVE, rec_buf.name, ret);
	    dl_exit_task( &Task, 1);
		}

    /* check if the triggered read tag is defined */

    if( rec_buf.f_read)
    {
      if ( rec_buf.f_read == NORMAL_FNC )
			  ds_info->fnc |= RD_MASK;
      else
      {
			  ds_info->fnc |= ERD_MASK | RD_MASK;
			  ds_info->start_check = 1;
      }

			/* check if a trigger tag has been defined */

      if( fl_gettype( &rec_buf.read) == FL_DIGITAL)
				fl_add_events( &Task, &rec_buf.read, ( void **)&ds, 1, block_read);
			else
				ds_info->continuous = 1;
    }

    /* check if the block write tag is defined */

    if( rec_buf.f_block) {             

      if( fl_gettype( &rec_buf.write) == FL_DIGITAL) {

	      ds_info->fnc |= BW_MASK;

				fl_add_events( &Task, &rec_buf.write, ( void **)&ds, 1, block_write);
			}
      else
				 fl_status( &Task, "NO_BWTRIGGER", FLS_INACTIVE, Mci_Get_Name( ds));
    }

    ds_info->abs = rec_buf.abs;   									/* absolute or relative addressing */

    /* add read disable trigger */

    if( fl_gettype( &rec_buf.read_disable) == FL_DIGITAL)
    {

      /* add the trigger */
      fl_add_events( &Task, &rec_buf.read_disable, ( void **)&ds, 1, read_disable);

      /* mark the trigger as changed */
      fl_set_chng( Task.id, &rec_buf.read_disable, 1);

      /* first disable the functionality */
      ds_info->read_disable = 1;
    }
    else
      ds_info->read_disable = 0;

    /* add write disable trigger */

    if( fl_gettype( &rec_buf.write_disable) == FL_DIGITAL)
    {

      /* add the trigger */
      fl_add_events( &Task, &rec_buf.write_disable, ( void **)&ds, 1, write_disable);

      /* mark the trigger as changed */
      fl_set_chng( Task.id, &rec_buf.write_disable, 1);

      /* first disable the functionality */
      ds_info->write_disable = 1;
    }
    else
      ds_info->write_disable = 0;

    /* add receive disable trigger */

    if( fl_gettype( &rec_buf.rcv_disable) == FL_DIGITAL)
    {

      /* add the trigger */
      fl_add_events( &Task, &rec_buf.rcv_disable, ( void **)&ds, 1, rcv_disable);

      /* mark the trigger as changed */
      fl_set_chng( Task.id, &rec_buf.rcv_disable, 1);

      /* first disable the functionality */
      ds_info->rcv_disable = 1;
    }
    else
      ds_info->rcv_disable = 0;

    /* add read sync. trigger */

    if ((fl_gettype( &rec_buf.read_sync) == FL_DIGITAL) || (fl_gettype( &rec_buf.read_sync) == FL_ANALOG))
    {

      /* add the trigger */
      fl_add_events( &Task, &rec_buf.read_sync, ( void **)&ds, 1, read_sync);

      /* mark the trigger as changed */
      fl_set_chng( Task.id, &rec_buf.read_sync, 1);

      /* first disable the functionality */
      ds_info->read_sync = 1;
    }
    else
      ds_info->read_sync = 0;

    /* add write sync. trigger */

    if ((fl_gettype( &rec_buf.write_sync) == FL_DIGITAL) || (fl_gettype( &rec_buf.write_sync) == FL_ANALOG))
    {

      /* add the trigger */
      fl_add_events( &Task, &rec_buf.write_sync, ( void **)&ds, 1, write_sync);

      /* mark the trigger as changed */
      fl_set_chng( Task.id, &rec_buf.write_sync, 1);

      /* first disable the functionality */
      ds_info->write_sync = 2;
    }
    else
      ds_info->write_sync = 0;

    /* add receive sync. trigger */

    if ((fl_gettype( &rec_buf.rcv_sync) == FL_DIGITAL) || (fl_gettype( &rec_buf.rcv_sync) == FL_ANALOG))
    {

      /* add the trigger */
      fl_add_events( &Task, &rec_buf.rcv_sync, ( void **)&ds, 1, rcv_sync);

      /* mark the trigger as changed */
      fl_set_chng( Task.id, &rec_buf.rcv_sync, 1);

      /* first disable the functionality */
      ds_info->rcv_sync = 3;
    }
    else
      ds_info->rcv_sync = 0;

    /*
     * update the disable tags for every functionality
     */
    ds_info->status    = rec_buf.status;

    ds_info->ready[ RD_FUNCTION] = rec_buf.read_rdy;
    ds_info->ready[ WR_FUNCTION] = rec_buf.write_rdy;
    ds_info->ready[ RCV_FUNCTION] = rec_buf.rcv_rdy;

    ds_info->sync[ RD_FUNCTION]  = rec_buf.read_sync;
    ds_info->sync[ WR_FUNCTION]  = rec_buf.write_sync;
    ds_info->sync[ RCV_FUNCTION]  = rec_buf.rcv_sync;
  }

  return;
}


/*-----------------------------------------------------------------------------
 * FUNCTION: void  tag_load( CT *ct_buf)
 *
 * PUPRPOSE:
 -----------------------------------------------------------------------------*/
void  tag_load( CT *ct_buf)
{

  DS_HDR  hdr_buf;             /* DeltaLink  Datasets table */
  DS_REC  rec_buf;             /* DeltaLink  Decoder Tags table */
	DS_INFO	*ds_info;
	MCIDS		*ds;
	void		*data;

  i16			t_info;
  u16			offset = 0;
  uint 		i,
       		array,
       		dimension,
       		record,              /* counter for processing records */
       		r;                   /* counter for keeping track of tags in array */
  int  		ds_end = 0;

  char 		fix;


  /* Read the table header */

  if ( ct_read_hdr( ct_buf, &hdr_buf) != GOOD )
  {

    fl_status( &Task, "CTHEADER", FLS_INACTIVE);
    dl_exit_task( &Task, 1);
  }

  /* search for the dataset control tag */

	if ((ds = Mci_Ds_R_Search( &hdr_buf.ds_ctrl)) == NULL)
  {

		/*fl_status( &Task, "IMX_DS_SEARCH", FLS_INACTIVE);
    dl_exit_task( &Task, 1);*/
    return;
  }

	ds_info = ( DS_INFO *)Mci_Get_Udata_Ptr( ds);

  /* get the number of overlay tags */

  ds_info->nr_tags = ct_get_nrecs( ct_buf);

  /* if no tag elements then return immediately */

  if (!ds_info->nr_tags)
    return;


  /* allocate space to hold the tags */

  if ((ds_info->tags = (TAG *)calloc( ds_info->nr_tags, sizeof( TAG))) == (TAG *)0)
  {

    fl_status( &Task, "NOMEMORY", FLS_INACTIVE);
    dl_exit_task( &Task, 1);
  }

  /* allocate space to hold the info of the tags */

  if ((ds_info->info = (INFO *)calloc( ds_info->nr_tags, sizeof( INFO))) == (INFO *)0)
  {

    fl_status( &Task, "NOMEMORY", FLS_INACTIVE);
    dl_exit_task( &Task, 1);
  }

  /* allocate memory to hold the values of the overlay tags */

  if ((ds_info->val = (void *)calloc( ds_info->nr_tags, sizeof( VAL))) == (void *)0)
  {

    fl_status( &Task, "NOMEMORY", FLS_INACTIVE);
    dl_exit_task( &Task, 1);
  }

	if ( ds_info->fnc & ERD_MASK )
  {
    if (( ds_info->old_val = ( void *)calloc( ds_info->nr_tags, sizeof( VAL ))) == ( void *)0)
    {

      fl_status( &Task, "NOMEMORY", FLS_INACTIVE);
      dl_exit_task( &Task, 1);
    }
  }

  /* allocate space to hold tag types and offsets */

  if ((ds_info->t_type = (i16 *)calloc( ds_info->nr_tags, sizeof( i16))) == (i16 *)0)
  {

    fl_status( &Task, "NOMEMORY", FLS_INACTIVE);
    dl_exit_task( &Task, 1);
  }

  if ((ds_info->offset = (u16 *)calloc( ds_info->nr_tags, sizeof( u16))) == (u16 *)0)
  {

    fl_status( &Task, "NOMEMORY", FLS_INACTIVE);
    dl_exit_task( &Task, 1);
  }

  /*
   * process every record in the overlay table 
   */
  for (r = 0, record = 0; r < ds_info->nr_tags; r += dimension, record++)
  {

    if (ct_read_rec( ct_buf, &rec_buf, record) != GOOD )
    {

      fl_status( &Task, "CTRECORD", FLS_INACTIVE);
      dl_exit_task( &Task, 1);
    }

    /* check the validity of the tag */

    if (fl_get_tag_info( &rec_buf.tag, 1, &t_info, NULL) == ERROR)
    {

			fl_status( &Task, "CTTAGVAL", FLS_INACTIVE, rec_buf.tag_name);
      dl_exit_task( &Task, 1);
    }

    /*
     * check if the tag is an array
     */
    if ((array = calc_dimension( rec_buf.tag_name, rec_buf.tag_dimension)) > 1)
    {

      /*
       * check if length is shorter than array dimension 
       */
      if (array < rec_buf.length)
      {

        fl_status( &Task, "ARRAY", FLS_INACTIVE, rec_buf.tag_name);

        dl_exit_task( &Task, 1);
      }

      /* adjust the length of number of tags in this dataset with additional number of tags */

      ds_info->nr_tags += rec_buf.length -1;

      /*
       * adjust the space to hold data with the size of the array 
       */
      if ((ds_info->tags = (TAG *)realloc( ds_info->tags,
                                           ds_info->nr_tags * sizeof( TAG))) == (TAG *)0)
      {

        fl_status( &Task, "NOMEMORY", FLS_INACTIVE);
        dl_exit_task( &Task, 1);
      }

      /* allocate space to hold the info of the tags */

      if ((ds_info->info = (INFO *)realloc( ds_info->info,
                                            ds_info->nr_tags * sizeof( INFO))) == (INFO *)0)
      {

        fl_status( &Task, "NOMEMORY", FLS_INACTIVE);
        dl_exit_task( &Task, 1);
      }

      /* allocate memory to hold the values of the overlay tags */

      if ((ds_info->val = (void *)realloc( ds_info->val,
                                           ds_info->nr_tags * sizeof( VAL))) == (void *)0)
      {

        fl_status( &Task, "NOMEMORY", FLS_INACTIVE);
        dl_exit_task( &Task, 1);
      }

			if ( ds_info->fnc & ERD_MASK )
      {
        if (( ds_info->old_val = ( void *)realloc( ds_info->old_val,
                                             ds_info->nr_tags * sizeof( VAL ))) == ( void *)0)
        {

          fl_status( &Task, "NOMEMORY", FLS_INACTIVE);
          dl_exit_task( &Task, 1);
        }
      }

      /* allocate space to hold tag types and offsets */

      if ((ds_info->t_type = (i16 *)realloc( ds_info->t_type,
                                             ds_info->nr_tags * sizeof( i16))) == (i16 *)0)
      {

        fl_status( &Task, "NOMEMORY", FLS_INACTIVE);
        dl_exit_task( &Task, 1);
      }

      if ((ds_info->offset = (u16 *)realloc( ds_info->offset,
                                             ds_info->nr_tags * sizeof( u16))) == (u16 *)0)
      {

        fl_status( &Task, "NOMEMORY", FLS_INACTIVE);
        dl_exit_task( &Task, 1);
      }

      dimension = rec_buf.length;    /* array length */
    }
    else 
    {

      if( array == 0)
      {

        fl_status( &Task, "ARRAY", FLS_INACTIVE, rec_buf.tag_name);
        dl_exit_task( &Task, 1);
      }
      else
        dimension = 1;
    }

    /* update the record information for every tag */

    for( i = 0, fix = 0; i < dimension; i++)
    {

      ds_info->tags[ r + i]             = rec_buf.tag;				/* overlay tag */

			ds_info->info[ r + i].ds					= ds;									/* Pointer to MCI dataset */
      ds_info->info[ r + i].t_type      = t_info;							/* overlay tag type */
      ds_info->info[ r + i].address     = rec_buf.address;		/* address of tag in dataset */
      ds_info->info[ r + i].bit         = rec_buf.bit;				/* bit number */
      ds_info->info[ r + i].conv        = rec_buf.conv;				/* conversion of data */

      ds_info->info[ r + i].fix        	= fix;                /* flag for fixing address */

      if (!fix)
        ds_info->info[ r + i].base     	= rec_buf.address;    /* base address */
      else
        ds_info->info[ r + i].base     	= ds_info->info[ r].base;

      /* update addressing information specified in CT of dataset */

      if( rec_buf.address < ds_info->ct_start)
        ds_info->ct_start = rec_buf.address;

      if( rec_buf.address > ds_end)
        ds_end = rec_buf.address;

      /*
       * set the code for the encode write function
       */
      switch( rec_buf.conv) {

        case C_BIT:                                         /* BIT conversion */
          ds_info->info[ r + i].operation = ( u16)( rec_buf.bit + CDE_B0_15);
          break;
        case C_BYTE:                                        /* BYTE conversion */
        case C_BCD2:                                        /* byte BCD conversion */
          ds_info->info[ r + i].operation = CDE_BYTE;
          break;

        case C_TIM0:                                        /* user defined time conversion */
        case C_TIM1:                                        /* user defined time conversion */
        case C_TIM2:                                        /* user defined time conversion */
        case C_TIM3:                                        /* user defined time conversion */
        case C_TIM4:                                        /* user defined time conversion */
        case C_TIM5:                                        /* user defined time conversion */
        case C_TIM6:                                        /* user defined time conversion */
        case C_TIM7:                                        /* user defined time conversion */
        case C_TIM8:                                        /* user defined time conversion */
        case C_TIM9:                                        /* user defined time conversion */

          rec_buf.bit = MAX_MSG;
          ds_info->info[ r + i].bit = dec_time[ rec_buf.conv - C_TIM0].size;
          ds_info->info[ r + i].operation = CDE_BYTE;
          if (ds_info->info[ r + i].bit > 2)
            ds_info->info[ r + i].operation = CDE_SIGNED;
          if (ds_info->info[ r + i].bit > 4)
            ds_info->info[ r + i].operation = CDE_LONG;
          if (ds_info->info[ r + i].bit > 8)
            ds_info->info[ r + i].operation = CDE_DOUBLE_IEEE_FLT;
                                                    
          /*
           * adjust the length of the specified CT length
           */
//          if( rec_buf.address + ds_info->info[ r + i].bit > ds_end)
//            ds_end = rec_buf.address + ds_info->info[ r + i].bit;
          break;

        case C_BYTE_R:                                      /* RIGHT byte conversion */
          ds_info->info[ r + i].operation = CDE_BYTE;
          break;
        case C_BYTE_L:                                      /* LEFT byte conversion */
          ds_info->info[ r + i].operation = CDE_BYTE +8;
          break;
        case C_WORD:                                        /* WORD conversion */
        case C_VALMET_FLT:                                   
          ds_info->info[ r + i].operation = CDE_SIGNED;
          break;

        case C_TIME:                                        /* Time, SECTIME conversion */
          rec_buf.bit = MAX_MSG;
        case C_LONG:                                        /* LONG conversion */
        case C_R_LONG:                                      /* reversed LONG conversion */
        case C_IEEE_FLT:                                    /* IEEE single point float conversion */
        case C_R_FLT:                                       /* reversed IEEE single point float conversion */
        case C_SIE_FLT:                                     /* SIEMENS float conversion */
        case C_BCD8:                                        /* Long BCD conversion */

          ds_info->info[ r + i].operation = CDE_LONG;

          break;
        case C_IEEE_DOUBLE:                                 /* IEEE DOUBLE point float conversion */
          ds_info->info[ r + i].operation = CDE_DOUBLE_IEEE_FLT;
          break;
        case C_MSG:                                         /* message conversion */

          /*
           * adjust the length of the specified CT length
           */
//          if( rec_buf.address + rec_buf.bit > ds_end)
//            ds_end = rec_buf.address + rec_buf.bit;

          ds_info->info[ r + i].operation = CDE_STRING;
          break;
        case C_IBG:                                         /* Interbus-S Gain for analog in/out */
        case C_IBAU:                                        /* Interbus-S Analog Input/Output 12 bits Unsigned */
        case C_IBAS:                                        /* Interbus-S Analog Input/Output 12 bits two's complement */
          break;

        case C_BCD:                                         /* Binary Coded Decimal conversion */
        case C_BCD4:
          ds_info->info[ r + i].operation = CDE_UBCD;
          break;

				default:

					fl_status( &Task, "CTCONV", FLS_INACTIVE, Mci_Get_Name( ds), r);
          dl_exit_task( &Task, 1);
          break;
      }

      /* check if the tag is of the type message */

      if (t_info == FL_MESSAGE)
      {

        ds_info->info[ r + i].m_len = rec_buf.bit;          /* length of message buffer */

        if( ( ds_info->info[ r + i].m_ptr = ( char *)calloc( ds_info->info[ r + i].m_len + 1,
                                                     sizeof( char))) == ( char *)0) {
          fl_status( &Task, "NOMEMORY", FLS_INACTIVE);
          dl_exit_task( &Task, 1);
        }

        /* set the values in the message tag */

        (( MSG *)&(( char *)ds_info->val)[ offset])->m_ptr = ds_info->info[ r + i].m_ptr;
        (( MSG *)&(( char *)ds_info->val)[ offset])->m_max = rec_buf.bit;
        (( MSG *)&(( char *)ds_info->val)[ offset])->m_len = rec_buf.bit;
      }

			/* keep track of the offset in the value buffer */

      offset += fl_sizes[ t_info];                        /* overlay tag size */

      /*
       * update values in case processing an array
       */
      rec_buf.tag.t_data++;

      /*
       * in case of bit conversion accumulate bit address an fix at run time the
       * true addressing
       */
      if( rec_buf.conv == C_BIT)
				rec_buf.bit++;
			else
				rec_buf.address++;

			fix = 1;
		}
  }

	/*
	 * in case of exception write add all tag events. Do this here
	 * because all pointers must be definite. Realloc can adjust in the
	 * loop the pointer to the info array !! 
	 */
	if( ds_info->fnc & EW_MASK || ds_info->fnc & CW_MASK ) {

		for( i = 0; i < ds_info->nr_tags; i++) {

			data = ( void *)&ds_info->info[ i];

			fl_add_events( &Task, &ds_info->tags[ i], &data, 1, ex_write);
		}
  }

	/* set the specified length of the dataset in the CT */

  ds_info->ct_len = ( u16)( ds_end - ds_info->ct_start +1);

  /* get the tag types and offsets */

  if( fl_get_tag_info( ds_info->tags,
                       ds_info->nr_tags,
                       ds_info->t_type,
                       ds_info->offset) == ERROR) {

    fl_status( &Task, "CTTAGVAL", FLS_INACTIVE, Mci_Get_Name( ds));
    dl_exit_task( &Task, 1);
  }

  /*
   * reset the change flags of all tags
   */
  if( fl_clear_chng( Task.id,
                     ds_info->tags,
                     ds_info->nr_tags ) != GOOD)
		fl_status( &Task, "FL_CLEAR_CHG", FLS_ERROR, "CTLOAD", Mci_Get_Name( ds), fl_error( Task.id));

  return;
}
