Subversion Repositories factorylink.mb_plus

Rev

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);
    else
      Mci_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;
}