Blame | Last modification | View Log | Download
/******************************************************************************** Copyright 1995 DeltaLink b.v. All Rights Reserved.******************************************************************************** DeltaLink Mailbox Communication Interface** File : mci_event.c** Version : 3.00** Developed by : Leon Westervoort.**/#include <stdlib.h>#include <string.h>#include <stdio.h>#include <stdarg.h>#include <flib.h> /* FactoryLink definitions */#include <mci3.h> /* Mailbox Communication Interface definitions */#include <mci3_int.h> /* Mailbox Communication Interface definitions */#include <format3.h> /* Mailbox Communication Interface definitions *//** FUNCTION: Mci_Event_Retrieve** PURPOSE: Returns arrays of events which can be used to pass to event functions.* A pointer to an array of tags (tags), array of pointers to datasets (datasets),* the number of events and an array of functions that will be called at event time* will be returned. All registered datasets will be returned for event regisration.* The data of the arrays are linked parallel with the same indexes together.**/int Mci_Event_Retrieve( TAG **tags, void **datasets[], u32 *num, int (***u_fnc)( void *, VAL)) {if( tags)*tags = _Mci_L_ds; /* return the pointer to the local datasets and mailbox */if( datasets)*datasets = ( void **)_Mci_ds; /* pointer to array pointers with dataset info */if( num)*num = _Mci_num_ds;if( u_fnc)*u_fnc = _Mci_fnc; /* pointer to array of function pointers */return GOOD;}/** FUNCTION: Mci_Event_Mbx** PURPOSE: This function must be called as event handling for the MCI mailbox tag of the* MCI application. The function MCI retrieve will return this function as event* function for the MCI malibox which will be index 0 in the event arrays.**/int Mci_Event_Mbx( void *dataset, VAL val ){int ret = GOOD;uint i,total,q_index,q_active_save;MBXMSG query;MCIDS tmp_ds,*ds;/* initialize the temporary datase and header */memset( &tmp_ds, 0x00, sizeof( MCIDS));/* read the total number of messages actual in the queue */if( ( ret = Mci_Q_Num( &_Mci_system, &total)) != GOOD)return ret;/** Check mesages left in the mailbox, if there no new message go to sleep*/if (total <= _Mci_q_num_active)fl_sleep( 10);/** process all datasets that came in new*/for( i = q_index = _Mci_q_num_active; i < total; i++) {/* increment the number of active messages in the queue */q_active_save = _Mci_q_num_active;_Mci_q_num_active++;/* perform a query on the queue to retrieve the dataset parameters */Mci_Set_Index( &tmp_ds, q_index); /* set the index in the queue of message */if( ( ret = Mci_Qi_Query( &_Mci_system, &tmp_ds)) != GOOD) {/* remove the message from the queue and continue */if( ( ret = Mci_Q_Msg_Remove( &_Mci_system, &tmp_ds)) != GOOD)return ret;continue;}/** check if a query message came in*/switch( Mci_Get_Type( &tmp_ds) ) {case MCI_QUERY_CMD : /* MCI info message *//** check if the functionality is supported by the MCI application and if so* if the received dataset is registered locally*/if( !( Mci_Sys_Get_Functions( &_Mci_system) & MCI_QUERY_FNC) ) {/* remove the message from the queue and continue */if( ( ret = Mci_Recv( &_Mci_system, &tmp_ds)) != GOOD)return ret;if( ( ret = Mci_Send_Error( &_Mci_system, &tmp_ds, MCI_FNC_NOT_SUPPORT)) != GOOD)return ret;continue;}/* handle the query event and continue with processing the queue */if( ( ret = Mci_Event_Query_Cmd( &tmp_ds)) != GOOD)return ret;continue;case MCI_QUERY_RSP : /* MCI info message feed back *//* handle query response event */if( ( ret = Mci_Event_Query_Rsp( &tmp_ds)) != GOOD)return ret;continue;case MCI_READ_REQ : /* read request *//* check if the functionality is supported by the MCI application */if( !( Mci_Sys_Get_Functions( &_Mci_system ) & MCI_READ_FNC )) {/* remove the message from the queue and continue */if( ( ret = Mci_Q_Msg_Remove( &_Mci_system, &tmp_ds)) != GOOD)return ret;/* return a function not supported error to the other task */if( ( ret = Mci_Send_Error( &_Mci_system, &tmp_ds, MCI_FNC_NOT_SUPPORT)) != GOOD)return ret;continue;}break;case MCI_WRITE_REQ : /* write request *//* check if the functionality is supported by the MCI application */if( !( Mci_Sys_Get_Functions( &_Mci_system) & MCI_WRITE_FNC)) {/* remove the message from the queue and continue */if( ( ret = Mci_Q_Msg_Remove( &_Mci_system, &tmp_ds)) != GOOD)return ret;/* return a function not supported error to the other task */if( ( ret = Mci_Send_Error( &_Mci_system, &tmp_ds, MCI_FNC_NOT_SUPPORT)) != GOOD)return ret;continue;}break;case MCI_READ_RSP : /* read feed back */case MCI_RCV_RDY : /* unsolicited receive ready */break;case MCI_QUERY_ERROR : /* MCI info message feed back */case MCI_READ_ERROR : /* read feed back */case MCI_WRITE_ERROR : /* write feed back */case MCI_WRITE_RSP : /* write feed back */case MCI_RCV_ACT : /* unsolicited receive active */case MCI_RCV_ERROR : /* unsolicited receive ready */break;default:/* message received with an unknown type, discard the message */if( ( ret = Mci_Q_Msg_Remove( &_Mci_system, &tmp_ds)) != GOOD)return ret;return MCI_BAD_TYPE;}/* search for the received dataset in the internal arrays */if( ( ds = Mci_Array_Ds_Srch( &tmp_ds)) == NULL) {/* remove the message from the queue and continue */if( ( ret = Mci_Q_Msg_Remove( &_Mci_system, &tmp_ds)) != GOOD) return ret;if( ( ret = Mci_Send_Error( &_Mci_system, &tmp_ds, MCI_NOT_REGISTERED)) != GOOD)return ret;return MCI_NOT_REGISTERED;}/** copy the registered dataset to a temporary and use this one so that other threads can't* be affected*/memcpy( ( char *)&query, ( char *)&tmp_ds.msg.mbx, sizeof( MBXMSG));memcpy( ( char *)&tmp_ds, ( char *)ds, sizeof( MCIDS ));Mci_Set_Org( &tmp_ds, MCI_ORG_MAILBOX);Mci_Reset_Buffer( &tmp_ds);/* copy the queried data to the dataset in the array and reset */memcpy( ( char *)&tmp_ds.msg.mbx, ( char *)&query, sizeof( MBXMSG));/* set the index on the registered dataset */Mci_Set_Index( &tmp_ds, q_index);/* call the user event function */if( ds->u_fnc) ret = ds->u_fnc( &tmp_ds);/* check if the application already processed a message for adjusting the queue index */if( q_active_save != _Mci_q_num_active) {q_index = _Mci_q_num_active; /* read the next message after the last active message */}}return ret;}/** FUNCTION: Mci_Event_Ds** PURPOSE: This function must be called as event handling in case a dataset control tag* has been triggered. The function is automatically linked to the datasets with* the Mci_Event_Retrieve function.**/int Mci_Event_Ds( void *ds, VAL val) {int ret;MCIHDR hdr;MSG buf;memset( &hdr, 0x00, sizeof( MCIHDR));/* check first if the dataset was a genuine trigger */if( !val.dig) return GOOD;/* check if this application supports the read functionality */if( !( Mci_Sys_Get_Functions( &_Mci_system ) & MCI_READ_FNC )) return GOOD;/* prepare the dataset with a read requets */buf.m_ptr = ( char *)&hdr;buf.m_max = sizeof( MCIHDR);if( ( ret = Mci_Ds_Prepare( ( MCIDS *)ds, &buf)) != GOOD)return ret;Mci_Set_Type( ( MCIDS *)ds, MCI_READ_REQ);/* mark this dataset as originated from a trigger and not from the queue */Mci_Set_Org( ( MCIDS *)ds, MCI_ORG_TRIGGER);/** call the user function*/(( MCIDS *)ds)->u_fnc( ds);return GOOD;}/** FUNCTION: Mci_Event_Check** PURPOSE: This function must be used when MCI will be handled cyclic and not on events.* The routine checks if MCI commands come in and passes them to the MCI* application. When this function is used no event function may be used in the* application.**/int Mci_Event_Check( void ){uint index = 0;VAL val;/* check the array of dataset control tags together with the MCI mailbox */while( fl_change_read( Mci_Sys_Get_Task_Id( &_Mci_system ),_Mci_L_ds,_Mci_num_ds,&index,&val) == GOOD) {/* check what kind of event happened */if( index == 0)Mci_Event_Mbx( NULL, val);elseMci_Event_Ds( _Mci_ds[ index], val);/* start the search for new events at the next element */index++;if( index == _Mci_num_ds) break;}/** check if the completion of the change read returned an error*/if( ( index != _Mci_num_ds) && ( fl_errno( Mci_Sys_Get_Task_Id( &_Mci_system)) != FLE_NO_CHANGE) )return fl_errno( Mci_Sys_Get_Task_Id( &_Mci_system));return GOOD;}/** FUNCTION: Mci_Event_Query_Cmd** PURPOSE: Handle an incoming query by checking dataset registration and sending back* dataset information**/int Mci_Event_Query_Cmd( MCIDS *ds) {MSG msg;MCIDS *q_ds;TAG l_ctrl,r_ctrl;int ret,r_station;/* first receive the message in order to retrieve the tag name */msg.m_max = ( u16)( Mci_Get_Msg_Len( ds) +1);msg.m_len = 0;if( ( ret = Mci_Buffer_Alloc( &msg)) != GOOD ) return ret;Mci_Set_T_Buffer( ds, &msg);/* receive the message from the queue */if( ( ret = Mci_Recv( &_Mci_system, ds )) != GOOD) {free( msg.m_ptr);Mci_Reset_Buffer( ds);return ret;}/** in case the query came from a remote system then check if the* dataset control tag exists on this system*/if( Mci_Get_Station_Id( ds) != Mci_Sys_Get_Station_Id( &_Mci_system)) {/* check if the remote dataset control tag existst on this system */if( Mci_name2tag( Mci_Get_U_Buffer( ds), &l_ctrl) == ERROR) {free( msg.m_ptr);Mci_Reset_Buffer( ds);if( ( ret = Mci_Send_Error( &_Mci_system, ds, MCI_DS_NOT_DEFINED)) != GOOD)return ret;return MCI_DS_NOT_DEFINED;}}/* save the value of the remote dataset control tag and station id */r_ctrl = *Mci_Get_Ds_Ctrl( ds);r_station = Mci_Get_Station_Id( ds);/* set the station id to the local station for search */Mci_Set_Station_Id( ds, Mci_Sys_Get_Station_Id( &_Mci_system));/* search for the dataset control in the local dataset array */if( ( q_ds = Mci_Array_Ds_Srch( ds)) == NULL) {free( msg.m_ptr);Mci_Reset_Buffer( ds);if( ( ret = Mci_Send_Error( &_Mci_system, ds, MCI_NOT_REGISTERED)) != GOOD)return ret;return MCI_NOT_REGISTERED;}/* update the remote dataset control and station id array */_Mci_R_station_id[ q_ds->ds_index] = r_station;_Mci_R_ds[ q_ds->ds_index] = r_ctrl;/** prepare and send the dataset information*/if( ( ret = Mci_Ds_Prepare( q_ds, Mci_Get_T_Buffer( ds))) != GOOD)return ret;Mci_Set_Type ( q_ds, MCI_QUERY_RSP);Mci_Set_Len ( q_ds, ( u16)strlen( Mci_Get_Name( q_ds)));strcpy( Mci_Get_U_Buffer( q_ds), Mci_Get_Name( q_ds));/* send the query response to the calling task */ret = Mci_Send( &_Mci_system, q_ds );free( msg.m_ptr);Mci_Reset_Buffer( ds);return ret;}/** FUNCTION: Mci_Event_Query_Rsp** PURPOSE: Handle the query response by updating the dataset information and* renote dataset control tag and station id information.**/int Mci_Event_Query_Rsp( MCIDS *ds) {MSG msg;MCIDS *q_ds;TAG l_ctrl,r_ctrl;u8 r_id;int ret;/* first receive the message in order to retrieve the tag name */msg.m_max = ( u16)( Mci_Get_Msg_Len( ds) +1);msg.m_len = 0;if( ( msg.m_ptr = calloc( 1, msg.m_max)) == NULL ) return FLE_OUT_OF_MEMORY;Mci_Set_T_Buffer( ds, &msg);/* receive the message from the queue */if( ( ret = Mci_Recv( &_Mci_system, ds)) != GOOD) {free( msg.m_ptr);Mci_Reset_Buffer( ds);return ret;}/** in case the query came from a remote system then update the remote* dataset control tag and station id*/if( Mci_Get_Station_Id( ds) != Mci_Sys_Get_Station_Id( &_Mci_system)) {/* check if the remote dataset control tag existst on this system */if( Mci_name2tag( Mci_Get_U_Buffer( ds), &l_ctrl) == ERROR) {free( msg.m_ptr);Mci_Reset_Buffer( ds);return MCI_DS_NOT_DEFINED;}/* save the remote dataset control tag and set the local parameters on the temporary dataset */r_ctrl = *Mci_Get_Ds_Ctrl( ds);r_id = Mci_Get_Station_Id( ds);Mci_Set_Ds_Ctrl( ds, l_ctrl);Mci_Set_Station_Id( ds, Mci_Sys_Get_Station_Id( &_Mci_system));}else {r_ctrl = *Mci_Get_Ds_Ctrl( ds);r_id = Mci_Get_Station_Id( ds);}/* search for the dataset control in the local dataset array */if( ( q_ds = Mci_Array_Ds_Srch( ds)) == NULL) {free( msg.m_ptr);Mci_Reset_Buffer( ds);return MCI_NOT_REGISTERED;}/* update the remote dataset control and station id array */_Mci_R_station_id[ q_ds->ds_index] = r_id;_Mci_R_ds[ q_ds->ds_index] = r_ctrl;/* update the dataset information structure */q_ds->start = Mci_Get_Start ( ds); /* start address */q_ds->len = Mci_Get_Len ( ds); /* length of data depending on boundary */q_ds->boundary = Mci_Get_Boundary ( ds); /* boundary addressing */q_ds->bnd_dir = Mci_Get_Bnd_Dir ( ds); /* direction of boundary data */q_ds->bit_dir = Mci_Get_Bit_Dir ( ds); /* direction of bit data */q_ds->bnd_offset = Mci_Get_Bnd_Offset ( ds); /* addressing offset of boundary data */q_ds->bit_offset = Mci_Get_Bit_Offset ( ds); /* addressing offset of bit data *//* copy the complete message to the registered dataset on the registered buffer */memcpy( ( char *)&q_ds->msg.mbx, ( char *)&ds->msg.mbx, sizeof( MBXMSG));Mci_Set_T_Buffer( q_ds, Mci_Get_R_Buffer( q_ds));memcpy( q_ds->msg.mbx.mm_msg.m_ptr, ds->msg.mbx.mm_msg.m_ptr, sizeof( MCIHDR));/* copy the complete message to the registered dataset */Mci_Set_Org ( q_ds, MCI_ORG_QUERY);/* call the user event function */if( q_ds->u_fnc) q_ds->u_fnc( q_ds);free( msg.m_ptr);Mci_Reset_Buffer( ds);return GOOD;}