Subversion Repositories factorylink.fl

Rev

Blame | Last modification | View Log | Download

/*
 ******************************************************************************
 *  Copyright 1994 DeltaLink bv. All Rights Reserved.
 ******************************************************************************
 *
 * DeltaLink FactoryLink general utilities.
 *
 * File: fl_utils.c
 *
 * 
 *
 */
#ifdef UNIX
#include  <pthread.h>
#endif

#ifdef WIN32

#define NOMSG             // typedef MSG and associated routines
#define _OLE2_H_          // no ole

#include  <windows.h>
#include  <stdio.h>
#include  <stdlib.h>

#undef ERROR

#endif

#include  <string.h>
#include  <stdarg.h>
#include  <ctype.h>
#include  <time.h>
#include  <math.h>
#include  <float.h>

#if defined( WIN)
#include  <dir.h>
#endif

#if defined( OS2) || defined( NT)
#include  <direct.h>
#endif

#include  <flib.h>
#include  <flpath.h>
#include  <fl_utils.h>                     /* FactoryLink definitions */
#include  <fl_sync.h>                   /* Synchronization definitions */


/*
 * global variables used in the FactoryLink utility library
 */
EVENT_FNC **e_fnclist;                     /* list containing user function pointers */
TAG       *e_taglist;                     /* tag list which creates events */
u16       _nr_events;                     /* current number of events */

int       ( *null_fnc)( void);             /* pointer to user NULL function */

static uint e_index = 0;            /* initialize ths variable only once on zero */

#ifdef ECHANGING
int         e_changed;
#endif

/*-----------------------------------------------------------------------------
 * FUNCTION: uint calc_dimension( char *name, char *dimension)
 *
 * PUPRPOSE:
 -----------------------------------------------------------------------------*/
uint calc_dimension( char *name, char *dimension) {

  char *s;
  uint i = 0,                                              
       depth = 0,
       start = 0,
       len[5],
       total_len = 1;

  /*
   * check first the name if an array is specified, otherwise return dimension 1
   */
  if( ( s = strstr( name, "[")) == NULL) return 1;

  /*
   * get the dimension of the total array
   */
  s = dimension;

  s--;
  do {

    s++;
    len[ i++] = atoi( s);

  } while( ( s = strstr( s, ",")) != NULL);

  depth = (i -1);

  while( i > 0) total_len *= len[ --i];

  s = strstr( name, "[");

  do {

    /* get the start of the array specified in the table */

    while( !isdigit( *s)) s++;

    start += atoi( s);
    if( i < depth) start *= len[ i +1];

    i++;

  } while( ( s = strstr( s, "[")) != NULL);

  /* check if the start of array is not overdimensioned */

  if( start < total_len)
    return total_len - start;
  else
    return 0;
}

/*-----------------------------------------------------------------------------
 * FUNCTION: void  fl_status( TASK_ID Task_id, char *s, ANA n, ...)
 *
 * PUPRPOSE:
 *
 * status writes a message and a status value to the task's status tags.
 * The fl_xlate function is used to convert from the key string to a
 * language dependent message. The function accepts variable number of
 * parameters. The format of these parameters must be consistent with the
 * format in the language test file.
 -----------------------------------------------------------------------------*/

void fl_status( TASK_ID *task, char *s, ANA n, ...) {

  va_list arg_ptr;  /* pointer to argument list */
  FLMSG  m;            /* task message */

  if ( task->id < 0 )
    return;

  /* build the string with variable arguments */

  va_start( arg_ptr, n);  /* set the argument pointer to the first argument */

  if( ( m.m_ptr = ( char *)malloc( 1024 *2)) == ( char *)0)
    return; 

  vsprintf( m.m_ptr, fl_xlate( s), arg_ptr);  /* print the string in message */

  m.m_len = ( u16)strlen( m.m_ptr);
  m.m_max = MAX_MSG *2;
  fl_write( task->id, &task->k.e_msg, 1, &m);
  fl_write( task->id, &task->k.e_stat, 1, &n);

  va_end( arg_ptr);  /* set the argument pointer to NULL */

  debug_log( task, "%s", MINIMUM_LEVEL, m.m_ptr);

  free( m.m_ptr);
}


/*-----------------------------------------------------------------------------
 * FUNCTION: int debug_log_init( TASK_ID *task)
 *
 * PUPRPOSE:
 *
 * debug_log_init initialises the option level(s) and/or log-file for the
 * use of the function debug_log. This function should be called for any
 * call of debug_log, but after a (successfull) initialization of FL. 
 -----------------------------------------------------------------------------*/

int debug_log_init( TASK_ID *task) {

  char   *temp;
printf( "\nDebug init called");
  /*
   * Get the options '-l', -x, and/or '-d'
   *
   * -d  -->  print debug information of all levels in task window
   * -l  -->  log debug information of all levels in log file
   * -x  -->  log debug information of specific level in log file
   * -v  -->  debugging info for Microsoft NT
   */

  if (InitializeCSection( &task->log_file, 1) != GOOD)
  {

    task->log_level = 0;
    return 0;
  }

  /*
   * set the verbose level for Microsoft
   */
#ifdef NT
  if( ( temp = strstr( task->k.e_cmd, "-v")) != NULL)
  {

    //Check for the debug level
    if( ( temp[2] >= '1') && ( temp[2] <= '9'))
      task->msv_level = ( char)(temp[2] - '0');
    else
      task->msv_level = 1;
  }
  else
    task->msv_level = 0;
#endif

  /*
   * set the debug level
   */
  if( ( temp = strstr( task->k.e_cmd, "-d")) != NULL) {

     /* Check for the debug level */

    if( ( temp[2] >= '1') && ( temp[2] <= '9'))
      task->dbg_level = ( char)(temp[2] - '0');
    else
      task->dbg_level = 1;
  }
  else {

    task->dbg_level = 0;
  }

  /*
   * set the exclusive level parameter
   */
  if( ( temp = strstr( task->k.e_cmd, "-x")) != NULL) {

    task->exc_level = 1;
  }
  else {

    task->exc_level = 0;

  }

  /*
   * set the log level and create log file
   */
  if( ( temp = strstr( task->k.e_cmd, "-l")) != NULL) {

    /*
     * Create or open the log file (First of all the directory structure
     * must be present.
     * Log file: {FLAPP}/{FLNAME}/{FLDOMAIN}/{FLUSER}/LOG/{TASKNAME}.LOG
     */

    /* Create directory for log file if needed */

    strcat( strcat( strcpy( task->log_fname, task->k.e_adir), "/"), task->fl_name);
    mkdir( task->log_fname);
    strcat( strcat( task->log_fname, "/"), task->fl_domain);
    mkdir( task->log_fname);
    strcat( strcat( task->log_fname, "/"), task->fl_user);
    mkdir( task->log_fname);
    strcat( strcat( task->log_fname, "/"), "log");
    mkdir( task->log_fname);
    strcat( strcat( strcat( task->log_fname, "/"), task->name), ".log");

    /* Check for the log level */

    if( ( temp[2] >= '1') && ( temp[2] <= '9'))
      task->log_level = ( char)(temp[2] - '0');
    else
      task->log_level = 1;

    /* Open/create the log file */
#ifdef OS2
    if( ( task->log_fhandle = fopen( task->log_fname, "w")) == NULL) {
#else
    if( ( task->log_fhandle = fopen( task->log_fname, "wt")) == NULL) {
#endif     
      task->log_level = 0;
      return -1;
    }
  }
  else
    task->log_level = 0;

  return 0;
}


/*-----------------------------------------------------------------------------
 * FUNCTION: int debug_log( char *s, int level, ...)
 *
 * PUPRPOSE:
 *
 * debug_log writes a message to the screen and/or the log file.
 * The desired debug/log level (parameter n) is checked against the actual
 * level (global variables).
 * The fl_xlate function is used to convert from the key string to a
 * language dependent message. The function accepts variable number of
 * parameters. The format of these parameters must be consistent with the
 * format in the language test file.
 -----------------------------------------------------------------------------*/

int debug_log( TASK_ID *task, char *s, int level, ...) {

  va_list arg_ptr;            /* pointer to argument list */
  int     ret = 0;
  char    m[ MAX_MSG *10];
  char    dbg_date[15],
          dbg_time[15],
          print = 0,
          log = 0,
          mslog = 0;

  if( task->id < 0 ) return -1;

  /*
   * check first if level is exclusive else
   * return if specified level is lower then actual level
   */
  if( task->exc_level) {

    if( task->dbg_level && (level == task->dbg_level)) print = 1;
    if( task->log_level && (level == task->log_level)) log = 1;
    if( task->msv_level && (level == task->msv_level)) mslog = 1;
  }
  else {

    if( task->dbg_level && (level <= task->dbg_level)) print = 1;
    if( task->log_level && (level <= task->log_level)) log = 1;
    if( task->msv_level && (level <= task->msv_level)) mslog = 1;
  }

  //printf( "Exc_level = %d, mslog = %d,%d\n", task->exc_level, mslog,  task->msv_level);
  if( !print && !log && !mslog) return -1;

  EnterCSection( &task->log_file, 0);

  va_start( arg_ptr, level);                /* set the argument pointer to the first argument */

  vsprintf( m, fl_xlate( s), arg_ptr);      /* print the string in message */

  /* Only report state for debug facility */

  if( print)
  {

    /* Print "Date + Time + Mess." */
#ifdef UNIX
    printf( "%s\n", m);
#else
    printf( "%s %s %s\n", _strdate( dbg_date), _strtime( dbg_time), m);
#endif
  }

  /* Only report state for log facility */

  if( log && ( task->log_fname != NULL) && (task->log_fhandle != NULL))
  {

    /* Write "Date + Time + Mess." */
#ifdef UNIX
    if( fprintf( task->log_fhandle, "%s\r\n", m) == EOF) {
#else
#ifdef OS2
    if( fprintf( task->log_fhandle, "%s %s %s\n",
                 _strdate( dbg_date),
                 _strtime( dbg_time),
                 m) == EOF)
    {
#else
    if( fprintf( task->log_fhandle, "%s %s %s\r\n",
                 _strdate( dbg_date),
                 _strtime( dbg_time),
                 m) <= EOF)
    {
#endif
#endif

      /* Reset the log option, don't accept any errors!!!! */
      task->log_level = 0;
      fclose( task->log_fhandle);
      task->log_fhandle = NULL;

      ret = -1;
    }
  }

//#ifdef NT
  //Microsoft debugging
  if (mslog)
  {
    //if 
    //sprintf( m, "%s\n", m);
    OutputDebugString( m);
  }
//#endif
     
  va_end( arg_ptr);  /* set the argument pointer to NULL */

  LeaveCSection( &task->log_file);
  return ret;
}

/*-----------------------------------------------------------------------------
 * FUNCTION: void  debug_log_exit( TASK_ID *task)
 *
 * PURPOSE : exit the debug/log facility.
 -----------------------------------------------------------------------------*/
void debug_log_exit( TASK_ID *task) {


  /* Close the log file, if there is one opened */
  EnterCSection( &task->log_file, 0);

  if( task->log_fhandle != NULL) fclose( task->log_fhandle);

  task->log_fhandle = NULL;
  task->log_level = 0;

  LeaveCSection( &task->log_file);

  //remove critical section for log file
  //DeleteCSection( &task->log_file);
}


/*-----------------------------------------------------------------------------
 * FUNCTION: void mirror( char *buf, ushort length)
 *
 * PUPRPOSE:
 -----------------------------------------------------------------------------*/
void mirror( char *buf, ushort length) {

  uchar  temp;
  ushort i;

  /*
   * of start = 1 then the real start of the data is on index 0
   */
  for( i = 0; i < length/2; i++) {

    temp = buf[ (length -i) -1];
    buf[ (length -i) -1] = buf[ i];
    buf[ i] = temp;
  }

  return;
}
/*-----------------------------------------------------------------------------
 * FUNCTION: void  fl_shutdown(int error)
 *
 * PURPOSE : shutdown the task.
 -----------------------------------------------------------------------------*/
void  fl_shutdown( TASK_ID *task, int error) {

  ANA n = FLS_INACTIVE;

  if( !error) {

    if( task->mode & LIC_DEMO)
      fl_status( task, "DEMO_STOP", FLS_INACTIVE);          /* indicate normal stop */
    else
      fl_status( task, "STOP", FLS_INACTIVE);          /* indicate normal stop */

  }
  else {

    fl_sleep( 1000L);

    fl_write( task->id, &task->k.e_stat, 1, &n);
  }
     
  fl_proc_exit( task->id);                           /* terminate FL access */

  /*
   * close all open files
   */
//#if !defined( UNIX) && !defined( OS2_32)
//  fcloseall();
//#endif
   
  exit( error);                                       /* exit to OS  */
}

/*
 *-----------------------------------------------------------------------------
 * Function/Type: fl_gettype( *TAG)
 * Description  : Function equal to fl_get_tag_info but just for one TAG
 *
 *------------------- Parameters, Variables, & Conditions ---------------------
 * Enter with  : Pointer to a TAG
 *
 * Exits with   : Type of TAG
 *
 *-----------------------------------------------------------------------------
 */

i16 fl_gettype( TAG *fl_tag){

  i16 info;

  if( fl_get_tag_info( fl_tag, 1, &info, ( u16 *)0 ) == GOOD)
    return info;

  else
    return FL_UNDEFINED;
}

/*
 *-----------------------------------------------------------------------------
 * Function/Type: fl_chread
 * Description  : Function equal to fl_change_read but simpler
 *
 *------------------- Parameters, Variables, & Conditions ---------------------
 * Enter with  : tp, n, ip, vp
 *
 * Exits with   : CHANGED, NOCHANGE
 *
 *-----------------------------------------------------------------------------
 */

int fl_chread( TASK_ID *task, TAG *tp, uint n, uint *ip, void *vp){

  if ( fl_change_read( task->id, tp, n, ip, vp) != GOOD) {

    if ( fl_errno( task->id) != FLE_NO_CHANGE) 
       fl_status( task, "FL_CHREAD", FLS_ERROR, fl_errno( task->id));

    return NOCHANGE;
  }

  return CHANGED;
}

/*
 *-----------------------------------------------------------------------------
 * Function/Type: fl_dig_set
 * Description  : Function to check if a digital is set
 *
 *------------------- Parameters, Variables, & Conditions ---------------------
 * Enter with  : 
 *
 * Exits with  : FL_ERROR or GOOD
 *
 *-----------------------------------------------------------------------------
 */

int fl_dig_set( TASK_ID *task, TAG *dig){

  DIG v;

  /* check first if this tag is a digital */

  if( fl_gettype( dig) != FL_DIGITAL) return FL_ERROR;

  /* read the value of the digital */

  if( fl_read( task->id, dig, 1, &v) != GOOD) return FL_ERROR;

  if( v) return GOOD;
  else   return FL_ERROR;
}

/*
 *-----------------------------------------------------------------------------
 * Function/Type: fl_set_dig
 * Description  : Function forces a digital
 *
 *------------------- Parameters, Variables, & Conditions ---------------------
 * Enter with  : 
 *
 * Exits with  : FL_ERROR or GOOD
 *
 *-----------------------------------------------------------------------------
 */

int fl_set_dig( TASK_ID *task, TAG *dig){

  DIG v = 1;

  /* check first if this tag is a digital */

  if( fl_gettype( dig) != FL_DIGITAL) return FL_ERROR;

  /* read the value of the digital */

  if( fl_forced_write( task->id, dig, 1, &v) != GOOD) return FL_ERROR;

  return GOOD;
}
/*
 *-----------------------------------------------------------------------------
 * Function/Type: TVAL fl_read_tval( TAG tag)
 * Description  : Read the TVAL from the RTDB 
 *
 *------------------- Parameters, Variables, & Conditions ---------------------
 *
 * Enter with : tag = TAG to read from
 *
 * Exits with : TVAL = value in the TVAL format
 *
 *-----------------------------------------------------------------------------
 */

int fl_read_tval( TASK_ID *task, TAG *tag, TVAL *tval)
{

  VAL  val;
  char buf[ MAX_TMSG];  

  /*
   * check first if the tag exists
   */
  if( fl_gettype( tag) == FL_UNDEFINED) return FL_UNDEFINED;

  /* Setup the message structure */

  val.msg.m_ptr = buf;
  val.msg.m_max = MAX_TMSG;
  val.msg.m_len = 0;

  /* Read the value from the RTDB */

  if( fl_read( task->id, tag, 1, &val) == FL_ERROR) return fl_errno( task->id);

  switch( fl_gettype( tag)) {

    case FL_DIGITAL : tval->dig  = val.dig;  break;
    case FL_ANALOG  : tval->ana  = val.ana;  break;
    case FL_LANALOG : tval->lana = val.lana; break;
    case FL_MESSAGE : strncpy( tval->msg, val.msg.m_ptr, MAX_TMSG); break;
    case FL_FLOAT   : tval->flp  = val.flp;  break;
  }

  return GOOD;
}

/*
 *-----------------------------------------------------------------------------
 * Function/Type: TVAL fl_write_tval( TAG tag)
 * Description  : Write the TVAL to the RTDB 
 *
 *------------------- Parameters, Variables, & Conditions ---------------------
 *
 * Enter with : tag = TAG to read from
 *
 * Exits with : TVAL = value in the TVAL format
 *
 *-----------------------------------------------------------------------------
 */

int fl_write_tval( TASK_ID *task, TAG *tag, TVAL *tval) {

  VAL  val;
  char buf[ MAX_TMSG];  

  /* Setup the message structure */

  val.msg.m_ptr = buf;
  val.msg.m_max = MAX_TMSG;
  val.msg.m_len = 0;

  /* Transform the tval to a val */

  switch( fl_gettype( tag)) {

    case FL_DIGITAL : val.dig  = tval->dig; break;
    case FL_ANALOG  : val.ana  = tval->ana; break;
    case FL_LANALOG : val.lana = tval->lana; break;
    case FL_MESSAGE : strncpy( val.msg.m_ptr, tval->msg, MAX_TMSG); break;
    case FL_FLOAT   : val.flp  = tval->flp; break;

    default:
      return FL_UNDEFINED;
  }

  /* Write to the RTDB */

  if( fl_write( task->id, tag, 1, &val) == FL_ERROR) return fl_errno( task->id);

  return GOOD;
}

/*
 *-----------------------------------------------------------------------------
 * Function/Type: int fl_get_mbxmsg( TAG tag)
 * Description  : Read the First Message from a Mailbox 
 *
 *------------------- Parameters, Variables, & Conditions ---------------------
 *
 * Enter with : task = pointer to TAG to read from
 *
 * Exits with : TVAL = value in the TVAL format
 *
 *-----------------------------------------------------------------------------
 */

int fl_get_mbxmsg( TASK_ID *task, TAG *mbx, MBXMSG *msg, uint *cnt) {

  char *mptr;                          /* Save pointer for querymbx ! */

  /*
   * Make a copy of the mailbox message pointer.
   * fl_query resets the pointer to NULL !
   */
  mptr = msg->mm_msg.m_ptr;

  /*
   * Query the first mailbox message to determine the size
   */
  if ( fl_count_mbx( task->id, *mbx, cnt) != GOOD)
    return FL_ERROR;

  if ( *cnt == 0) return GOOD;

  /*
   * Query the first mailbox message to determine the size
   */
  if ( fl_query_mbx( task->id, *mbx, msg, 0, 1, cnt) != GOOD)
    return FL_ERROR;

  /*
   * Allocate enough space to read the data
   */
  if (((mptr = realloc( mptr, msg->mm_msg.m_len * sizeof( char))) == NULL) &&
       (msg->mm_msg.m_len != 0)) {

    return FL_ERROR;
  } 

  msg->mm_msg.m_ptr = mptr;
  msg->mm_msg.m_max = msg->mm_msg.m_len;

  /*
   * Read the data from the mailbox
   */
  if ( fl_read_app_mbx( task->id, task->id, *mbx, msg, 0) != GOOD)
    return FL_ERROR;

  return GOOD;
}

/*
 *-----------------------------------------------------------------------------
 * Function/Type: int fl_cmptag
 *
 * Description  : compare two tags with each other on segment and offset
 *
 *------------------- Parameters, Variables, & Conditions ---------------------
 *
 * Enter with : 
 *
 * Exits with :  0    tags are identical
 *              -1    tag a is smaller than tag b
 *               1    tag a is greater than tag b
 *
 *-----------------------------------------------------------------------------
 */
int fl_cmptag( TAG *a, TAG *b) {

  if( (a)->t_type > (b)->t_type )          
    return 1;                              /* segment is greater */
  else if( (a)->t_type < (b)->t_type )    
    return -1;                            /* segment is smaller */
  else if( (a)->t_data > (b)->t_data )    
    return 1;                              /* segment is equal and offset is greater */
  else if( (a)->t_data < (b)->t_data )    
    return -1;                            /* segment is equal and offset is smaller */
  else
   return 0;                              /* segment and offset are equal  */
}

/*-----------------------------------------------------------------------------
 * FUNCTION: void fl_convert
 *
 * PURPOSE : Converts a FactoryLink to another FactoryLink type
 *
 -----------------------------------------------------------------------------*/

void fl_convert( void *dst, i16 d_type, void *src, i16 s_type) {

  /* check first the parameters */

  if( dst == NULL || src == NULL) return;

  switch( s_type) {

    case FL_DIGITAL:

      switch( d_type) {

        case FL_DIGITAL:      /* FL_DIGITAL ---> FL_DIGITAL */

          *( DIG *)dst = *( DIG *)src;

          break;

        case FL_ANALOG:        /* FL_DIGITAL ---> FL_ANALOG */

          *( ANA *)dst = *( DIG *)src;

          break;

        case FL_LANALOG:      /* FL_DIGITAL ---> FL_LANALOG */

          *( LANA *)dst = *( DIG *)src;

          break;

        case FL_FLOAT:        /* FL_DIGITAL ---> FL_FLOAT */

          *( FLP *)dst = *( DIG *)src;

          break;

        case FL_MESSAGE:      /* FL_DIGITAL ---> FL_MESSAGE */

          if( (( FLMSG *)dst)->m_ptr)
            sprintf( (( FLMSG *)dst)->m_ptr, "%d", *( DIG *)src);

          break;
      }

      break;

    case FL_ANALOG:

      switch( d_type) {

        case FL_DIGITAL:      /* FL_ANALOG ---> FL_DIGITAL */

          if (*( ANA *)src)
            *( DIG *)dst = 1;
          else
            *( DIG *)dst = 0;

          break;

        case FL_ANALOG:        /* FL_ANALOG ---> FL_ANALOG */

          *( ANA *)dst = *( ANA *)src;

          break;

        case FL_LANALOG:      /* FL_ANALOG ---> FL_LANALOG */

          *( LANA *)dst = *( ANA *)src;

          break;

        case FL_FLOAT:        /* FL_ANALOG ---> FL_FLOAT */

          *( FLP *)dst = *( ANA *)src;

          break;

        case FL_MESSAGE:      /* FL_ANALOG ---> FL_MESSAGE */

          if( (( FLMSG *)dst)->m_ptr) 
            sprintf( (( FLMSG *)dst)->m_ptr, "%d", *( ANA *)src);

          break;
      }

      break;

    case FL_LANALOG:

      switch( d_type) {

        case FL_DIGITAL:      /* FL_LANALOG ---> FL_DIGITAL */

          if (*( LANA *)src)
            *( DIG *)dst = 1;
          else
            *( DIG *)dst = 0;

          break;

        case FL_ANALOG:        /* FL_LANALOG ---> FL_ANALOG */

          *( ANA *)dst = ( ANA)*( LANA *)src;

          break;

        case FL_LANALOG:      /* FL_LANALOG ---> FL_LANALOG */

          *( LANA *)dst = *( LANA *)src;

          break;

        case FL_FLOAT:        /* FL_LANALOG ---> FL_FLOAT */

          *( FLP *)dst = *( LANA *)src;

          break;

        case FL_MESSAGE:      /* FL_LANALOG ---> FL_MESSAGE */

          if( (( FLMSG *)dst)->m_ptr) 
            sprintf( (( FLMSG *)dst)->m_ptr, "%ld", *( LANA *)src);

          break;
      }

      break;

    case FL_FLOAT:

      //26-sept-2002: if there is a nan or inf, set the float value to zero
      if (!_finite( *(FLP *)src)) *(FLP *)src = 0.0;

      switch( d_type) {

        case FL_DIGITAL:      /* FL_FLOAT ---> FL_DIGITAL */

          if (*( FLP *)src)
            *( DIG *)dst = 1;
          else
            *( DIG *)dst = 0;

          break;

        case FL_ANALOG:        /* FL_FLOAT ---> FL_ANALOG */

          *( ANA *)dst = ( ANA)*( FLP *)src;

          break;

        case FL_LANALOG:      /* FL_FLOAT ---> FL_LANALOG */

          *( LANA *)dst = ( LANA)*( FLP *)src;

          break;

        case FL_FLOAT:        /* FL_FLOAT ---> FL_FLOAT */

          *( FLP *)dst = *( FLP *)src;

          break;

        case FL_MESSAGE:      /* FL_FLOAT ---> FL_MESSAGE */

          if( (( FLMSG *)dst)->m_ptr) 
            sprintf( (( FLMSG *)dst)->m_ptr, "%f", *( FLP *)src);

          break;
      }

      break;

    case FL_MESSAGE:

      switch( d_type) {

        case FL_DIGITAL:      /* FL_MESSAGE ---> FL_DIGITAL */

          *( DIG *)dst = ( DIG)atoi( (( FLMSG *)src)->m_ptr);

          if (*( DIG *)dst)
            *( DIG *)dst = 1;
          else
            *( DIG *)dst = 0;

          break;

        case FL_ANALOG:        /* FL_MESSAGE ---> FL_ANALOG */

          *( ANA *)dst = ( ANA)atoi( (( FLMSG *)src)->m_ptr);

          break;

        case FL_LANALOG:      /* FL_MESSAGE ---> FL_LANALOG */

          *( LANA *)dst = ( LANA)atol( (( FLMSG *)src)->m_ptr);

          break;

        case FL_FLOAT:        /* FL_MESSAGE ---> FL_FLOAT */

          *( FLP *)dst = ( FLP)atof( (( FLMSG *)src)->m_ptr);

          break;

        case FL_MESSAGE:      /* FL_MESSAGE ---> FL_MESSAGE */

          if( (( FLMSG *)dst)->m_ptr) {

            strncpy( (( FLMSG *)dst)->m_ptr,  (( FLMSG *)src)->m_ptr, (( FLMSG *)dst)->m_max);

            if( strlen( (( FLMSG *)dst)->m_ptr) > (( FLMSG *)dst)->m_max)
              (( FLMSG *)dst)->m_len = (( FLMSG *)dst)->m_max;
            else
              (( FLMSG *)dst)->m_len = strlen( (( FLMSG *)dst)->m_ptr);
          }

          break;
      }

      break;
  }

  return;
}


/*
 *-----------------------------------------------------------------------------
 * Function/Type: int fl_add_events
 *
 * Description  : Add a list of tags which can generate a an event. In case an
 *                event occures then the function pointer will be called with
 *                the user index and value of the tag.
 *
 *                The function supports chaining of function pointers in order
 *                to handle multiple functions on one event.  
 *
 *------------------- Parameters, Variables, & Conditions ---------------------
 *
 * Enter with : tagp    pointer to tag array
 *              u_data  user array with pointers to data
 *              n       number of tag elements
 *              fp      function pointer
 *                
 *
 * Exits with : 
 *
 *-----------------------------------------------------------------------------
 */
int fl_add_events( TASK_ID *task, TAG *tagp, void **u_data, u16 n, int ( *u_fnc)( void *, VAL)) {

  u16  i,
       index,
       new_total = ( u16)( n + _nr_events);


  /*
   * enter a critical section when changing the events
   */
#ifdef ECHANGING
  /*
   * send the user defined signal to wake up the fl_wait function to our own
   * process
   */
  if ( EnterCSection( &Critical_ESIGNAL, S_INFINITE ) == -1 )
    return FL_ERROR;

  fl_signal_critical();

  if ( EnterCSection( &Critical_ECHANGE, S_INFINITE ) == -1 )
    return FL_ERROR;

#endif

  /* reallocate the size of the event list to the new size */

  if( ( e_taglist = ( TAG *)realloc( ( void *)e_taglist, 
                                     new_total * sizeof( TAG))) == NULL)

  {
    #ifdef ECHANGING

    if ( LeaveCSection( &Critical_ESIGNAL ) == -1 )
      return FL_ERROR;

    if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
      return FL_ERROR;

    #endif

    return FLE_OUT_OF_MEMORY;
  }

  if( ( e_fnclist = ( EVENT_FNC **)realloc( ( void *)e_fnclist, 
                                              new_total * sizeof( EVENT_FNC *))) == NULL)
  {
    #ifdef ECHANGING

    if ( LeaveCSection( &Critical_ESIGNAL ) == -1 )
      return FL_ERROR;

    if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
      return FL_ERROR;

    #endif

    return FLE_OUT_OF_MEMORY;
  }

  /*
   * add the events one by one by sorting the event list
   */
  for( i = 0; i < n; i++) {

    /* try to find the event and return the index in the event array */

    if( !find_event( &tagp[ i], &index) ) {

      /* event already exists in the event list, add the event function */

      if( (  e_fnclist[ index] = ll_insert( e_fnclist[ index])) == NULL)
      {
        #ifdef ECHANGING

        if ( LeaveCSection( &Critical_ESIGNAL ) == -1 )
          return FL_ERROR;

        if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
          return FL_ERROR;

        #endif

        return FLE_OUT_OF_MEMORY;
      }

      e_fnclist[ index]->u_fnc   = u_fnc;
      e_fnclist[ index]->u_data  = u_data[ i];

      /* adjust the size of the event and function list to one less */

      new_total -= 1;

      if( ( e_taglist = ( TAG *)realloc( ( void *)e_taglist,
                                         new_total * sizeof( TAG))) == NULL)
      {
        #ifdef ECHANGING

        if ( LeaveCSection( &Critical_ESIGNAL ) == -1 )
          return FL_ERROR;

        if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
          return FL_ERROR;

        #endif

        return FLE_OUT_OF_MEMORY;
      }

      if( ( e_fnclist = ( EVENT_FNC **)realloc( ( void *)e_fnclist,
                                               new_total * sizeof( EVENT_FNC *))) == NULL)
      {
        #ifdef ECHANGING

        if ( LeaveCSection( &Critical_ESIGNAL ) == -1 )
          return FL_ERROR;

        if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
          return FL_ERROR;

        #endif

        return FLE_OUT_OF_MEMORY;
      }
    }
    else {

      /* add the new unique event to the event list*/

      if( _nr_events && ( index <= _nr_events)) {

        memmove( ( char *)&e_taglist[ index +1], ( char *)&e_taglist[ index], (_nr_events - index) * sizeof( TAG));
        memmove( ( char *)&e_fnclist[ index +1], ( char *)&e_fnclist[ index], (_nr_events - index) * sizeof( EVENT_FNC *));
      }

      /* insert the new tag event on the write index */

      memcpy( ( char *)&e_taglist[ index], ( char *)&tagp[ i], sizeof( TAG));

      /* create the first new element in the list of the same tag events */

      if( ( e_fnclist[ index] = ll_insert( NULL)) == NULL)
      {
        #ifdef ECHANGING

        if ( LeaveCSection( &Critical_ESIGNAL ) == -1 )
          return FL_ERROR;

        if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
          return FL_ERROR;

        #endif

        return FLE_OUT_OF_MEMORY;
      }

      e_fnclist[ index]->u_fnc   = u_fnc;

      if( u_data)
        e_fnclist[ index]->u_data  = u_data[ i];

      _nr_events++;
    }
  }

  #ifdef ECHANGING

  e_changed = 1;

  if ( LeaveCSection( &Critical_ESIGNAL ) == -1 )
    return FL_ERROR;

  if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
    return FL_ERROR;

  #endif

  return GOOD;
}
/*
 *-----------------------------------------------------------------------------
 * Function/Type: int fl_add_null_event
 *
 * Description  : Register the null event function. This function will be called
 *                when there are no changes left after the first real event 
 *                occured. This way the user knows that was the last event and
 *                can initiate final processing.
 *
 *------------------- Parameters, Variables, & Conditions ---------------------
 *
 * Enter with : 
 *              u_null      NULL event function pointer
 *                
 *
 * Exits with : 
 *
 *-----------------------------------------------------------------------------
 */
int fl_register_null_event( TASK_ID *task, int ( *u_null)( void)) {

  if( null_fnc) return FL_ERROR;

  null_fnc = u_null;

  return GOOD;
}

/*
 *-----------------------------------------------------------------------------
 * Function/Type: int fl_clr_events
 *
 * Description  : Clear a list of events from the event list
 *
 *------------------- Parameters, Variables, & Conditions ---------------------
 *
 * Enter with : tagp    pointer to tag array
 *              uindex  user index array
 *
 * Exits with : 
 *
 *-----------------------------------------------------------------------------
 */
int fl_clr_events( TASK_ID *task, TAG *tagp, void **u_data, u16 n)
{
  u16        i,
             index;
  EVENT_FNC   *fnc;

  
  #ifdef ECHANGING

  /*
   * send the user defined signal to wake up the fl_wait function to our own
   * process
   */
  if ( EnterCSection( &Critical_ESIGNAL, S_INFINITE ) == -1 )
    return FL_ERROR;

  fl_signal_critical();

  if ( EnterCSection( &Critical_ECHANGE, S_INFINITE ) == -1 )
    return FL_ERROR;

  #endif

  /*
   * delete every single event from the event list
   */
  for( i = 0; i < n; i++)
  {
    /* search for the element to delete */

    if( find_event( &tagp[ i], &index) ) continue;

    /* clear the elements in the event function list */

    fnc = e_fnclist[ index];

    do {

      if( fnc->u_data == u_data[ i])
        fnc = ll_delete( fnc, &e_fnclist[ index]);
      else
        fnc = fnc->next;

    } while( fnc != NULL);

    /* check if there are any functions left for this event */

    if( !e_fnclist[ index]) {

      /* delete the entry in the tag and function event lists */

      if( (_nr_events - index) > 1) {

        memmove( ( char *)&e_taglist[ index], ( char *)&e_taglist[ index +1], ((_nr_events -1) - index) * sizeof( TAG));
        memmove( ( char *)&e_fnclist[ index], ( char *)&e_fnclist[ index +1], ((_nr_events -1) - index) * sizeof( EVENT_FNC *));
      }

      _nr_events--;

      /* adjust the memory size the tag and function event lists */

      if( ( e_taglist = ( TAG *)realloc( ( void *)e_taglist,
                                         _nr_events * sizeof( TAG))) == NULL)
      {
        #ifdef ECHANGING

        if ( LeaveCSection( &Critical_ESIGNAL ) == -1 )
          return FL_ERROR;

        if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
          return FL_ERROR;

        #endif

        return FLE_OUT_OF_MEMORY;
      }

      if( ( e_fnclist = ( EVENT_FNC **)realloc( ( void *)e_fnclist, 
                                                _nr_events * sizeof( EVENT_FNC *))) == NULL)
      {
        #ifdef ECHANGING

        if ( LeaveCSection( &Critical_ESIGNAL ) == -1 )
          return FL_ERROR;

        if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
          return FL_ERROR;

        #endif

        return FLE_OUT_OF_MEMORY;
      }
    }
  }

  /* reset the global event index because the number of event tags has been changed */

  e_index = 0;

  #ifdef ECHANGING

  e_changed = 1;

  if ( LeaveCSection( &Critical_ESIGNAL ) == -1 )
    return FL_ERROR;

  if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
    return FL_ERROR;

  #endif

  return GOOD;
}

/*
 *-----------------------------------------------------------------------------
 * Function/Type: int fl_clr_eventlist
 *
 * Description  : Clear all the events
 *
 *------------------- Parameters, Variables, & Conditions ---------------------
 *
 * Enter with : tagp    pointer to tag array
 *              uindex  user index array
 *
 * Exits with : 
 *
 *-----------------------------------------------------------------------------
 */
int fl_clr_eventlist( TASK_ID *task) {

  u32  i;

  #ifdef ECHANGING

  /*
   * send the user defined signal to wake up the fl_wait function to our own
   * process
   */
  if ( EnterCSection( &Critical_ESIGNAL, S_INFINITE ) == -1 )
    return FL_ERROR;

  fl_signal_critical();

  if ( EnterCSection( &Critical_ECHANGE, S_INFINITE ) == -1 )
    return FL_ERROR;

  #endif

  /*
   * delete every event from the event function list
   */
  for( i = 0; i < _nr_events; i++) {

    /* 
     * clear the linked list of functions
     */
    while( e_fnclist[ i] != NULL)
        ll_delete( e_fnclist[ i], &e_fnclist[ i]);
  }

  /* 
   * free the total event and function list from memory
   */
  free( e_taglist);
  free( e_fnclist);

  e_taglist = NULL;
  e_fnclist = NULL;

  e_index = 0;

  #ifdef ECHANGING

  e_changed = 1;

  if ( LeaveCSection( &Critical_ESIGNAL ) == -1 )
    return FL_ERROR;

  if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
    return FL_ERROR;

  #endif

  return GOOD;
}

/*
 *-----------------------------------------------------------------------------
 * Function/Type: int fl_wait_event
 *
 * Description  : Wait on an event to happen and in case this happens call the
 *                correct user function.
 *
 *------------------- Parameters, Variables, & Conditions ---------------------
 *
 * Enter with : 
 * Exits with : 
 *
 *-----------------------------------------------------------------------------
 */
int fl_wait_event( TASK_ID *task) {

  int          error;
  uint         end_total;
  EVENT_FNC    *fnc;
  VAL          val;
  char         buf[ MAX_MSG];


  /* set the mode of the task to event driven */

  task->e_driven = 1;
  task->signal   = 0;

  /* check the validity of the tag aray */

  /*if( fl_get_tag_info( e_taglist,
                       _nr_events,
                       NULL,
                       NULL) != GOOD)
    return FL_ERROR;*/

  /* reset the value parameter */

  memset( &val, 0x00, sizeof( VAL));

  /* set char buffer for message tags */
  val.msg.m_ptr = buf;
  val.msg.m_max = MAX_MSG;

  #ifdef ECHANGING

  if ( EnterCSection( &Critical_ECHANGE, S_INFINITE ) == -1 )
    return FL_ERROR;

  #endif

  /*
   *  go into a change wait. This function blocks until an event occurs
   */
  if( fl_change_wait( task->id,
                      e_taglist,
                      _nr_events,
                      &e_index,
                      ( void *)&val) != GOOD) {

    /*
     * check what kind of error occured
     */
    if( ( task->signal = fl_errno( task->id)) == FLE_SIGNALLED )
    {
      /* check what kind fo signal received */

      if( ( task->signal = fl_recv_sig( task->id)) == FL_ERROR)
      {
        #ifdef ECHANGING

        if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
          return FL_ERROR;

        #endif

        return fl_errno( task->id);
      }
      else {

        if( task->signal == FLC_SIG_TERMINATED ||
            task->signal == FLC_SIG_TERM_FLAG_SET ||
            task->signal == FLC_SIG_RTDB_ACCESS
          ) {

          e_index = 0;

          #ifdef ECHANGING

          if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
            return FL_ERROR;

          if ( EnterCSection( &Critical_ESIGNAL, S_INFINITE ) == -1 )
            return FL_ERROR;

          fl_sleep( 1);

          if ( LeaveCSection( &Critical_ESIGNAL ) == -1 )
            return FL_ERROR;

          #endif

          return GOOD;
        }
      }
    }
    else {

      /* convert the error from fl_change_wait to a signal */

      if( task->signal == FLE_TERM_FLAG_SET)
      {

        task->signal = FLC_SIG_TERM_FLAG_SET;

        #ifdef ECHANGING

        if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
          return FL_ERROR;

        #endif

        return GOOD;
      }
      else
      {
        e_index = 0;

        #ifdef ECHANGING

        if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
          return FL_ERROR;

        #endif

        return task->signal;
      }
    }
  }

  /*
   * call the user function(s) which is related to this event
   */

  fnc = e_fnclist[ e_index];

  while( fnc != NULL) {

    /* call the user function with the user index and the value */

    if( ( error = fnc->u_fnc( fnc->u_data, val)) != GOOD)
    {
      #ifdef ECHANGING

      if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
       return FL_ERROR;

      #endif

      return error;
    }

    #ifdef ECHANGING
    if ( e_changed ) 
    {
      e_changed = 0;
      return GOOD;
    }
    #endif

    fnc = fnc->next;
  }

  /*
   * check the rest of the event tag list ( wrap around ) for a change.
   * Check first the last part and then the first part.
   */
  if( e_index == ( uint)( _nr_events -1))
    end_total = ( uint)( _nr_events -1);
  else {

    end_total = e_index;
    e_index++;

    /* set char buffer for message tags */

    val.msg.m_ptr = buf;
    val.msg.m_max = MAX_MSG;

    while( ( error = fl_change_read(  task->id,
                                       e_taglist,
                                       _nr_events,
                                       &e_index,
                                       &val)) == GOOD) {

      /*
       * call the user function(s) which is related to this event
       */

      fnc = e_fnclist[ e_index];

      while( fnc != NULL) {

        /* call the user function with the user index and the value */

        if( ( error = fnc->u_fnc( fnc->u_data, val)) != GOOD)
        {
          #ifdef ECHANGING

          if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
           return FL_ERROR;

          #endif

          return error;
        }

        #ifdef ECHANGING

        if ( e_changed ) 
        {
          e_changed = 0;
          return GOOD;
        }
        #endif

        fnc = fnc->next;
      }

      /* increment the index to prevent blocking */

      e_index++;

      if( e_index >= _nr_events) {
      
        e_index = 0;
        break;
      }

      /* set char buffer for message tags */
      val.msg.m_ptr = buf;
      val.msg.m_max = MAX_MSG;
    }

    /* check if the change read went ok and process the first part */

    if( ( error != GOOD) && ( fl_errno( task->id) != FLE_NO_CHANGE))
    {
      #ifdef ECHANGING

      if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
       return FL_ERROR;

      #endif

      return fl_errno( task->id);
    }
  }

  e_index = 0;

  if( end_total) {

    /* set char buffer for message tags */

    val.msg.m_ptr = buf;
    val.msg.m_max = MAX_MSG;

    while( ( error = fl_change_read( task->id,
                                     e_taglist,
                                     end_total,
                                     &e_index,
                                     &val)) == GOOD)
    {
      /*
       * call the user function(s) which is related to this event
       */

      fnc = e_fnclist[ e_index];

      while( fnc != NULL)
      {
        /* call the user function with the user index and the value */

        if( ( error = fnc->u_fnc( fnc->u_data, val)) != GOOD)
        {
          #ifdef ECHANGING

          if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
           return FL_ERROR;

          #endif

          return error;
        }


        #ifdef ECHANGING
        if ( e_changed ) 
        {
          e_changed = 0;
          return GOOD;
        }
        #endif

        fnc = fnc->next;
      }

      /* increment the index to prevent blocking */

      e_index++;

      if( e_index >= end_total)
      {
        e_index = 0;
        break;
      }

      /* set char buffer for message tags */

      val.msg.m_ptr = buf;
      val.msg.m_max = MAX_MSG;
    }

    /* check if the change erad went ok and process the first part */

    if( ( error != GOOD) && ( fl_errno( task->id) != FLE_NO_CHANGE))
    {
      #ifdef ECHANGING

      if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
       return FL_ERROR;

      #endif

      return fl_errno( task->id);
    }
  }

  /*
   *  call the NULL function in order to notify the user that there are no
   *  more changes
   */
  if( null_fnc != NULL)  null_fnc();

  #ifdef ECHANGING

  if ( LeaveCSection( &Critical_ECHANGE ) == -1 )
   return FL_ERROR;

  #endif

  return GOOD;
}


/*
 *-----------------------------------------------------------------------------
 * Function/Type: int fl_wait_event
 *
 * Description  : Execute the user event function for the event with the given
 *                tag.
 *                The value of the tag should be set by the user before calling
 *                this function.
 *
 *------------------- Parameters, Variables, & Conditions ---------------------
 *
 * Enter with : 
 * Exits with : 
 *
 *-----------------------------------------------------------------------------
 */
int fl_exec_event( TASK_ID *task, TAG *event)
{

  u16           index;
  EVENT_FNC     *fnc;
  int           error;
  int           ret = GOOD;
  char          buf[ MAX_MSG];
  VAL           val;


  /* first locate the event */
  if (find_event( event, &index))
    return FLE_NULL_POINTER;

  /* set char buffer for message tags */
  val.msg.m_ptr = buf;
  val.msg.m_max = MAX_MSG;

  /* read the tag value */
  if (fl_read( task->id, event, 1, &val) != GOOD)
    return fl_errno( task->id);

  /*
   * call the user function(s) which is related to this event
   */

  fnc = e_fnclist[ index];

  while( fnc != NULL) {

    /* call the user function with the user index and the value */

    if( ( error = fnc->u_fnc( fnc->u_data, val)) != GOOD)
      ret = error;

    fnc = fnc->next;
  }

  return ret;
}

/*
 *-----------------------------------------------------------------------------
 * Function/Type: int fl_change_bits_read
 *
 * Description  : This function reads all values of changes tags of one tag 
 *                array at one time.
 *
 *------------------- Parameters, Variables, & Conditions ---------------------
 *
 * Enter with : 
 * Exits with : 
 *
 *-----------------------------------------------------------------------------
 */
int fl_change_bits_read( id_t id, TAG FAR *tp, uint n, u16 FAR *ch )
{
  uint ip = 0;
  VAL  value;


  /* reset the change array */

  memset( ch, 0x00, n * sizeof( u16 ));

  /* check first if there are any changes within the array */

  while( fl_change_read( id, tp, n, &ip, &value ) == GOOD )
  {
    /* update the changed and value array */

    ch[ ip ] = 1;
  }

  /* check if there was no change at all */

  if ( fl_errno( id ) != FLE_NO_CHANGE )
  {
    return FL_ERROR;
  }

  return GOOD;
}


/*-----------------------------------------------------------------------------
 *
 * FUNCTION: long  ieee2sie( sie_val)
 *
 * Purpose : convert a value in IEEE floating point format
 *                to SIEMENS floating point format.
 *
 *                Format SIE: 32 bit EEEEEEEE MMMMMMMM MMMMMMMM MMMMMMMM
 *                - Exponent:  8 bit, bit 31 (MSB) to bit 24 (LSB) in
 *                             2's complement;
 *                - Mantissa : 24 bit, bit 23 (MSB) to bit 0 (LSB) in
 *                             2's complement;
 *                             0.5 <= positive mantissa <   1;
 *                              -1 <  negative mantissa <= -0.5;
 *
 *                Format IEEE:  64 bit SEEEEEEE EEEEMMMM MMMMMMMM MMMMMMMM
 *                                     MMMMMMMM MMMMMMMM MMMMMMMM MMMMMMMM
 *                - Exponent:  11 bit, bit 62 (MSB) to bit 52 (LSB) in
 *                              excess 1023;
 *                - Mantissa:  53 bit, absolute value and sign;
 *                             sign:  bit 63;
 *                             absolute value: bit 52 (MSB) to bit 0 (LSB);
 *                             1 <= mantissa < 2;
 *
 *
 -----------------------------------------------------------------------------*/
u32 ieee2sie( FLP ieee_val) {

  union {  /*  union used to set-up the SIEMENS long from the PC FLP */

    FLP flt;

    struct {

#ifdef HOST_LOW_2_HIGH
      u32 tmp_1;          /*  low */
      u32 tmp_2;          /*  high */
#else
      u32 tmp_2;          /*  high */
      u32 tmp_1;          /*  low */
#endif

    } lng;

  } ieee;

  u32   tmp_sie_val,
        sie_flt = 0;

  /*
   *
   * Conversion from IEEE format to SIEMENS format:
   *
   * Format SIE : 32 bit EEEEEEEE MMMMMMMM MMMMMMMM MMMMMMMM
   *
   * - Exponent : 8 bit, bit 31 (MSB) to bit 24 (LSB); 2's complement;
   * - Mantissa : 24 bit, bit 23 (MSB) to bit 0 (LSB); 2's complement;
   *            0.5 <= positive mantissa <   1;
   *             -1 <  negative mantissa <= -0.5;
   *
   * Format IEEE: 64 bit SEEEEEEE EEEEMMMM MMMMMMMM MMMMMMMM
   *            MMMMMMMM MMMMMMMM MMMMMMMM MMMMMMMM
   *
   * - Exponent : 11 bit, bit 62 (MSB) to bit 52 (LSB); excess 1023;
   * - Mantissa : 53 bit, absolute value and sign; sign:  bit 63;
   *        absolute value: bit 52 (MSB) to bit 0 (LSB);
   *            1 <= mantissa < 2;
   */
  if( ieee_val != ( FLP)0) {

    ieee.flt = ieee_val;
    
    /* calculate exponent: convert excess 1023 to 2's complement */

    sie_flt = (( ieee.lng.tmp_2 >> 20) & 0x000007ffL) - 1022;
    sie_flt = ( sie_flt << 24) & 0xff000000L;

    /* calculate mantissa */

    tmp_sie_val = ( ieee.lng.tmp_2 << 2) | ( ieee.lng.tmp_1 >> 30);
    tmp_sie_val &= 0x003fffffL;

    /* bit 22 is always set to 1 */

    tmp_sie_val |= 0x00400000L;

    if( ( ieee.lng.tmp_2 & 0x80000000L) != 0) {

      if( tmp_sie_val == 0x00400000L) {

        tmp_sie_val = 0x00800000L;
        sie_flt = sie_flt - 0x01000000L;
      }
      else
        tmp_sie_val = -1 * tmp_sie_val;
    }
    sie_flt = (sie_flt & 0xff000000L) | (tmp_sie_val & 0x00ffffffL);
  }
  else
    sie_flt = 0x80000000L;

  /*
   * the SIEMENS plc uses LOW:HIGH double addressing. This means that the words must
   * be swapped
   */
  return sie_flt;
}

/*-----------------------------------------------------------------------------
 *
 * FUNCTION: FLP sie2ieee( sie_val)
 * PURPOSE : convert a value in SIEMENS floating point format
 *                to IEEE floating point format.
 *
 *                Format SIE: 32 bit EEEEEEEE MMMMMMMM MMMMMMMM MMMMMMMM
 *                - Exponent:  8 bit, bit 31 (MSB) to bit 24 (LSB) in
 *                             2's complement;
 *                - Mantissa : 24 bit, bit 23 (MSB) to bit 0 (LSB) in
 *                             2's complement;
 *                             0.5 <= positive mantissa <   1;
 *                              -1 <  negative mantissa <= -0.5;
 *
 *                Format IEEE:  64 bit SSEEEEEE EEEEMMMM MMMMMMMM MMMMMMMM
 *                                     MMMMMMMM MMMMMMMM MMMMMMMM MMMMMMMM
 *                - Exponent:  11 bit, bit 62 (MSB) to bit 52 (LSB) in
 *                              excess 1023; this means a sign bit with an
 *                              absolute value
 *                - Mantissa:  53 bit, absolute value and sign;
 *                             sign:  bit 63;
 *                             absolute value: bit 52 (MSB) to bit 0 (LSB);
 *                             1 <= mantissa < 2;
 *         
 -----------------------------------------------------------------------------*/
FLP sie2ieee( u32 sie_flt) {

  union {                 /*  union used to set-up the FLP from the SIEMENS long */

    FLP flt;

    struct {

#ifdef HOST_LOW_2_HIGH
      u32 tmp_1;          /*  low */
      u32 tmp_2;          /*  high */
#else
      u32 tmp_2;          /*  high */
      u32 tmp_1;          /*  low */
#endif

    } lng;
    
  } ieee;

#ifdef afronden
  char  *fstr;
  int    dec,
        sign;
#endif

  if( sie_flt == 0 || sie_flt == 0x80000000L) {
  
    ieee.flt = ( FLP)0;
  }  
  else {
     
    /*
     * move the SIEMENS exponent in place for IEEE exponent
     */
    ieee.lng.tmp_2 = sie_flt >> 4;

    /*
     * Note: if SIEMENS mantissa = 0x800000 increment IEEE exponent by 1
     */
    /*ieee.lng.tmp_2 += sie_flt & 0x00800000;*/

    if( sie_flt & 0x80000000)
      ieee.lng.tmp_2 |= 0xF0000000;

    /* conversion from 2's complement to Excess 1023 */

    /*
     * add 1022 (0x3FE) not 1023 as the exponent of SIEMENS is 1 greater
     * than the exponent of IEEE float
     */
    ieee.lng.tmp_2 = ((ieee.lng.tmp_2 + 0x3fe00000L) & 0x7ff00000L);

    /*
     * get sign of SIEMENS mantissa. The IEEE mantissa is always absolute, the
     * SIEMENS mantissa has a sign bit.
     */
    if( ( sie_flt & 0x00800000L) != 0) {

      /* if negative set the IEEE sign bit and 2's complement the SIEMENS mantissa */

      ieee.lng.tmp_2 |= 0x80000000L;
      sie_flt =  -1 * ( sie_flt | 0xff000000L);

      /*
       * increment the IEEE exponent with one because siemens uses its mantissa
       * in two's complement 
       */
      if( sie_flt & 0x00800000L) ieee.lng.tmp_2 += 0x00100000L;
    }

    /*
     * ignore the most significant bit of the SIEMENS mantissa
     *
     * ignore most significant bit of SIEMENS mantissa which means that the
     * SIEMENS mantissa is multiplied by two to get the mantissa value between
     * 1 and 2
     */
    ieee.lng.tmp_2 |= ( ( sie_flt >> 2) & 0x000FFFFFL);

    /*
     * recover the 2 least significant bits in second part of IEEE mantissa
     * and set the remaining mantissa bits to round it up
     */
    /*ieee.lng.tmp_1 = (sie_flt << 30) | 0x3FFFFFFFL;*/
    ieee.lng.tmp_1 = sie_flt << 30;

    /*
     * because the FLP has a much greater precision as the Siemens float
     * the mantissa bits which fall out of range of the Siemens float must
     * be set to a zero value on the IEEE float
     */
#ifdef afronden
    fstr = fcvt( ieee.flt, 7, &dec, &sign);

    if( dec > 0) {

      if( dec > strlen( fstr)) return ( FLP)0;        /* invalid value */

      fstr[ strlen( fstr) - dec] = '\0';
    }

    ieee.flt = atof( fstr);
    ieee.flt *= pow10( -strlen( fstr) + dec);

    if( sign) ieee.flt *= -1;
#endif
  }

  return ieee.flt;
}


/*
 *-----------------------------------------------------------------------------
 * Function/Type: void fl_task_xlate_load( TASK_ID *task)
 *
 * Description  : Load the Xlation file for task, first the located in the FL
 *                system directory, second the one located in the {FLAPP}/msg
 *                directory.
 *
 *------------------- Parameters, Variables, & Conditions ---------------------
 *
 * Enter with : 
 * Exits with : 
 *
 *-----------------------------------------------------------------------------
 */
void fl_task_xlate_load( TASK_ID *task)
{

  NPATH  *np;
  char   xlate_file[ MAX_FILE_NAME];


  /* load the default translation file */
  fl_xlate_init( task->name, NULL, 0);

  /* allocate structure for normalizing */
  if ((np = fl_path_alloc()) == NULL) 
    return;

  /* fill in the default directory */
  fl_path_set_dir( np, task->k.e_adir);
  fl_path_add_dir( np, "msg");

  /* fill in th efile name */
  strcpy( xlate_file, task->name);
  strcat( xlate_file, ".txt");

  fl_path_set_file( np, xlate_file);

  /* create normalised file name */
  fl_path_sys( np, xlate_file, MAX_FILE_NAME);

  /* try to load the application msg file */
  fl_xlate_load( xlate_file);

  return;

}