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 ECHANGINGint 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;elsereturn 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 NTif( ( temp = strstr( task->k.e_cmd, "-v")) != NULL){//Check for the debug levelif( ( temp[2] >= '1') && ( temp[2] <= '9'))task->msv_level = ( char)(temp[2] - '0');elsetask->msv_level = 1;}elsetask->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');elsetask->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');elsetask->log_level = 1;/* Open/create the log file */#ifdef OS2if( ( task->log_fhandle = fopen( task->log_fname, "w")) == NULL) {#elseif( ( task->log_fhandle = fopen( task->log_fname, "wt")) == NULL) {#endiftask->log_level = 0;return -1;}}elsetask->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 UNIXprintf( "%s\n", m);#elseprintf( "%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 UNIXif( fprintf( task->log_fhandle, "%s\r\n", m) == EOF) {#else#ifdef OS2if( fprintf( task->log_fhandle, "%s %s %s\n",_strdate( dbg_date),_strtime( dbg_time),m) == EOF){#elseif( 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 debuggingif (mslog){//if//sprintf( m, "%s\n", m);OutputDebugString( m);}//#endifva_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 */elsefl_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();//#endifexit( 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;elsereturn 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 */elsereturn 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 zeroif (!_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 ECHANGINGif ( LeaveCSection( &Critical_ESIGNAL ) == -1 )return FL_ERROR;if ( LeaveCSection( &Critical_ECHANGE ) == -1 )return FL_ERROR;#endifreturn FLE_OUT_OF_MEMORY;}if( ( e_fnclist = ( EVENT_FNC **)realloc( ( void *)e_fnclist,new_total * sizeof( EVENT_FNC *))) == NULL){#ifdef ECHANGINGif ( LeaveCSection( &Critical_ESIGNAL ) == -1 )return FL_ERROR;if ( LeaveCSection( &Critical_ECHANGE ) == -1 )return FL_ERROR;#endifreturn 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 ECHANGINGif ( LeaveCSection( &Critical_ESIGNAL ) == -1 )return FL_ERROR;if ( LeaveCSection( &Critical_ECHANGE ) == -1 )return FL_ERROR;#endifreturn 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 ECHANGINGif ( LeaveCSection( &Critical_ESIGNAL ) == -1 )return FL_ERROR;if ( LeaveCSection( &Critical_ECHANGE ) == -1 )return FL_ERROR;#endifreturn FLE_OUT_OF_MEMORY;}if( ( e_fnclist = ( EVENT_FNC **)realloc( ( void *)e_fnclist,new_total * sizeof( EVENT_FNC *))) == NULL){#ifdef ECHANGINGif ( LeaveCSection( &Critical_ESIGNAL ) == -1 )return FL_ERROR;if ( LeaveCSection( &Critical_ECHANGE ) == -1 )return FL_ERROR;#endifreturn 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 ECHANGINGif ( LeaveCSection( &Critical_ESIGNAL ) == -1 )return FL_ERROR;if ( LeaveCSection( &Critical_ECHANGE ) == -1 )return FL_ERROR;#endifreturn 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 ECHANGINGe_changed = 1;if ( LeaveCSection( &Critical_ESIGNAL ) == -1 )return FL_ERROR;if ( LeaveCSection( &Critical_ECHANGE ) == -1 )return FL_ERROR;#endifreturn 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]);elsefnc = 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 ECHANGINGif ( LeaveCSection( &Critical_ESIGNAL ) == -1 )return FL_ERROR;if ( LeaveCSection( &Critical_ECHANGE ) == -1 )return FL_ERROR;#endifreturn FLE_OUT_OF_MEMORY;}if( ( e_fnclist = ( EVENT_FNC **)realloc( ( void *)e_fnclist,_nr_events * sizeof( EVENT_FNC *))) == NULL){#ifdef ECHANGINGif ( LeaveCSection( &Critical_ESIGNAL ) == -1 )return FL_ERROR;if ( LeaveCSection( &Critical_ECHANGE ) == -1 )return FL_ERROR;#endifreturn FLE_OUT_OF_MEMORY;}}}/* reset the global event index because the number of event tags has been changed */e_index = 0;#ifdef ECHANGINGe_changed = 1;if ( LeaveCSection( &Critical_ESIGNAL ) == -1 )return FL_ERROR;if ( LeaveCSection( &Critical_ECHANGE ) == -1 )return FL_ERROR;#endifreturn 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 ECHANGINGe_changed = 1;if ( LeaveCSection( &Critical_ESIGNAL ) == -1 )return FL_ERROR;if ( LeaveCSection( &Critical_ECHANGE ) == -1 )return FL_ERROR;#endifreturn 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 ECHANGINGif ( 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 ECHANGINGif ( LeaveCSection( &Critical_ECHANGE ) == -1 )return FL_ERROR;#endifreturn 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 ECHANGINGif ( 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;#endifreturn 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 ECHANGINGif ( LeaveCSection( &Critical_ECHANGE ) == -1 )return FL_ERROR;#endifreturn GOOD;}else{e_index = 0;#ifdef ECHANGINGif ( LeaveCSection( &Critical_ECHANGE ) == -1 )return FL_ERROR;#endifreturn 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 ECHANGINGif ( LeaveCSection( &Critical_ECHANGE ) == -1 )return FL_ERROR;#endifreturn error;}#ifdef ECHANGINGif ( e_changed ){e_changed = 0;return GOOD;}#endiffnc = 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 ECHANGINGif ( LeaveCSection( &Critical_ECHANGE ) == -1 )return FL_ERROR;#endifreturn error;}#ifdef ECHANGINGif ( e_changed ){e_changed = 0;return GOOD;}#endiffnc = 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 ECHANGINGif ( LeaveCSection( &Critical_ECHANGE ) == -1 )return FL_ERROR;#endifreturn 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 ECHANGINGif ( LeaveCSection( &Critical_ECHANGE ) == -1 )return FL_ERROR;#endifreturn error;}#ifdef ECHANGINGif ( e_changed ){e_changed = 0;return GOOD;}#endiffnc = 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 ECHANGINGif ( LeaveCSection( &Critical_ECHANGE ) == -1 )return FL_ERROR;#endifreturn 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 ECHANGINGif ( LeaveCSection( &Critical_ECHANGE ) == -1 )return FL_ERROR;#endifreturn 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_HIGHu32 tmp_1; /* low */u32 tmp_2; /* high */#elseu32 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;}elsetmp_sie_val = -1 * tmp_sie_val;}sie_flt = (sie_flt & 0xff000000L) | (tmp_sie_val & 0x00ffffffL);}elsesie_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_HIGHu32 tmp_1; /* low */u32 tmp_2; /* high */#elseu32 tmp_2; /* high */u32 tmp_1; /* low */#endif} lng;} ieee;#ifdef afrondenchar *fstr;int dec,sign;#endifif( 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 afrondenfstr = 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;}