/************************************************************************/
/* Copyright 1992 MBARI							*/
/************************************************************************/
/* $Header: rdmif.c,v 1.2 98/06/16 18:25:44 pean Exp $			*/
/* Summary  : Data Manager Interface for ROV User Interface		*/
/* Filename : rdmif.c							*/
/* Author   : Bob Herlien (rah)						*/
/* Project  : New ROV							*/
/* $Revision: 1.2 $							*/
/* Created  : 11/02/92							*/
/************************************************************************/
/* Originally the interface module to Remote Data Manager (rdm), a	*/
/* library for doing data manager calls via RPC to the VxWorks system,	*/
/* this module is now just a wrapper to interface to the Unix version	*/
/* of Data Manager, but the "rdm_" function naming has been retained.	*/
/************************************************************************/
/* Modification History:						*/
/* $Log:	rdmif.c,v $
 * Revision 1.2  98/06/16  18:25:44  18:25:44  pean (Andrew Pearce)
 * Temporary fix for DM urgent open race
 * 
 * Revision 1.1  1998/01/28 16:17:12  oreilly
 * Initial revision
 *
 * Revision 2.2  96/05/15  11:15:38  11:15:38  bobh (Bob Herlien)
 * Still supporting proto during final vehicle build
 * 
 * Revision 2.0  95/09/20  14:23:07  14:23:07  hebo (Bob Herlien)
 * Support for final vehicle integration.  AC, PDU micros.
 * 
 * Revision 1.8  94/08/19  17:20:27  17:20:27  hebo (Bob Herlien)
 * Interface to Unix version of Data Manager
 * 
 * Revision 1.6  93/12/17  15:05:05  15:05:05  hebo (Bob Herlien)
 * December Wet Test
 * 
 * Revision 1.5  93/07/08  18:11:00  18:11:00  hebo (Bob Herlien)
 * Prior to Prototype Phase I testing
 * 
 * Revision 1.4  93/05/27  15:48:06  15:48:06  hebo (Bob Herlien)
 * Data Manager Interface
 * 
 * Revision 1.2  93/01/21  10:34:21  10:34:21  hebo (Bob Herlien)
 * Changes after Level 0
 * 
 * Revision 1.0  92/11/20  12:03:29  12:03:29  hebo (Bob Herlien)
 * Initial revision
 * 
*/
/************************************************************************/

#include <mbari/types.h>
#include <mbari/const.h>
#include "rdmif.h"
#include <time.h>
#include <datamgr.h>
#include <dm_errno.h>
#include <stdio.h>
#include <unistd.h>


/************************/
/* External Functions	*/
/************************/

Extern Void	graphItemCnsmr( DM_Item item, Nat32 period );


/************************************************************************/
/* Function    : rdm_init						*/
/* Purpose     : Initialize Data Manager				*/
/* Inputs      : None							*/
/* Outputs     : Error number						*/
/* Comment     : Must be called exactly once per application		*/
/************************************************************************/
	Errno
rdm_init( Void )
{
    return( dm_init((DM_Define *)NULL) );

}/* rdm_init() */


/************************************************************************/
/* Function    : rdm_exist						*/
/* Purpose     : Return existence status of Data Manager		*/
/* Inputs      : None							*/
/* Outputs     : TRUE if DM exists, else FALSE				*/
/************************************************************************/
	MBool
rdm_exist( Void )
{
    return( dm_exist() );

} /* rdm_exist() */


/************************************************************************/
/* Function    : rdm_create						*/
/* Purpose     : Create remote DM item					*/
/* Inputs      : Name,number of items, array of return item IDs, type,	*/
/*		 number of elements					*/
/* Outputs     : Error number						*/
/* Comment     : Can be used to create only elemental types or arrays	*/
/*		 (no structs)						*/
/************************************************************************/
	Errno
rdm_create( char *name, Nat32 nitems, DM_Item *rtn_items, DM_Type dmtype,
	    DM_Num num_elts )
{
    Errno	rtn;

    rtn = dm_create(name, nitems, rtn_items, dmtype, num_elts, DM_ENDT);

    if ( rtn == EDM_NAME_EXISTS )
	rtn = SUCCESS;

    else if ( rtn != SUCCESS )
	fprintf(stderr, "Failure to create DM item %s, rtn code %#x\n", 
		name, rtn);

    return( rtn );

} /* rdm_create() */


/************************************************************************/
/* Function    : rdm_create_items					*/
/* Purpose     : Create remote DM item					*/
/* Inputs      : DM_Define ptr						*/
/* Outputs     : Error number						*/
/************************************************************************/
	Errno
rdm_create_items( DM_Define *itmp )
{
    Errno	rtn;

    if ( (rtn = dm_create_items(itmp)) == EDM_NAME_EXISTS )
	rtn = SUCCESS;

    else if ( rtn != SUCCESS )
	fprintf(stderr, "Failure to create DM item %s, rtn code %#x\n", 
		itmp->itm_name, rtn);

    return( rtn );

} /* rdm_create_items() */


/************************************************************************/
/* Function    : rdm_lookup						*/
/* Purpose     : Lookup remote DM item					*/
/* Inputs      : Name, element number					*/
/* Outputs     : DM_Item id						*/
/************************************************************************/
	DM_Item
rdm_lookup( char *name, Nat32 elt_no )
{
    DM_Item	rtn;

    if ( (rtn = dm_lookup(name, elt_no)) == NO_ITEM )
	fprintf(stderr, "Failed lookup on Data Manager item %s\n", name);

    return( rtn );

} /* rdm_lookup() */


/************************************************************************/
/* Function    : rdm_item_status					*/
/* Purpose     : Get remote DM Item Status				*/
/* Inputs      : Item, Status ptr					*/
/* Outputs     : Error Number						*/
/************************************************************************/
	Errno
rdm_item_status( DM_Item item, DmItemSts *sts )
{
    Errno	rtn;

    if ( (rtn = dm_item_status(item, sts)) != SUCCESS )
	fprintf(stderr, 
		"Failure to get status of DM item %#x, rtn code %#x\n", 
		item, rtn);

    return( rtn );

} /* rdm_item_status() */


/************************************************************************/
/* Function    : rdm_item_status					*/
/* Purpose     : Get remote DM Item Status				*/
/* Inputs      : Item, Status ptr					*/
/* Outputs     : Error Number						*/
/************************************************************************/
	Errno
rdm_item_status_free( DmItemSts *sts )
{
    return( dm_item_status_free(sts) );

} /* rdm_item_status_free() */


/************************************************************************/
/* Function    : rdm_search						*/
/* Purpose     : Search for remote DM item name				*/
/* Inputs      : Name, item to search from, return ptr for number items	*/
/* Outputs     : DM_Item id						*/
/************************************************************************/
	DM_Item
rdm_search( char *name, DM_Item from, DM_Num *nitems )
{
    return( dm_search(name, from, nitems) );

} /* rdm_search() */


/************************************************************************/
/* Function    : rdm_task_exit						*/
/* Purpose     : Perform Remote dm_task_exit on RemoteDm task		*/
/* Inputs      : None							*/
/* Outputs     : Error Number						*/
/* Comment     : Use this carefully! RemoteDm task serves ALL rdm clients!*/
/************************************************************************/
	Errno
rdm_task_exit( Void )
{
    Errno	rtn;

    if ( (rtn = dm_task_exit(0)) != SUCCESS )
	fprintf(stderr, "Failure on dm_task_exit(), rtn code %#x\n", rtn);

    return( rtn );

} /* rdm_task_exit() */


/************************************************************************/
/* Function    : rdm_start_provider					*/
/* Purpose     : Start provider on remote DM Item			*/
/* Inputs      : Item, period						*/
/* Outputs     : Error Number						*/
/************************************************************************/
	Errno
rdm_start_provider( DM_Item item, Nat32 period )
{
    Errno	rtn;
    DmItemSts	sts;

    if ( (rtn = dm_start_provider(item, period)) != SUCCESS )
    {
	fprintf(stderr, "Failure to start provider on ");

	if ( dm_item_status(item, &sts) == SUCCESS )
	{
	    fprintf( stderr, "%s", sts.is_name );
	    dm_item_status_free( &sts );
	}
	else
	    fprintf( stderr, "DM item %#x", item );

	fprintf(stderr, ", rtn code %#x\n", rtn);
    }

    return( rtn );

} /* rdm_start_provider() */


/************************************************************************/
/* Function    : rdm_start_multiple					*/
/* Purpose     : Start a DM Item as a multi-access item			*/
/* Inputs      : Data item						*/
/* Outputs     : Error Number						*/
/************************************************************************/
	Errno
rdm_start_multiple( DM_Item item )
{
    Errno	rtn;
    DmItemSts	sts;

    if ( (rtn = dm_start_multiple(item)) != SUCCESS )
    {
	fprintf(stderr, "Failure to start multiple provider on ");

	if ( dm_item_status(item, &sts) == SUCCESS )
	{
	    fprintf( stderr, "%s", sts.is_name );
	    dm_item_status_free( &sts );
	}
	else
	    fprintf( stderr, "DM item %#x", item );

	fprintf(stderr, ", rtn code %#x\n", rtn);
    }

    return( rtn );

} /* rdm_start_multiple() */


/************************************************************************/
/* Function    : rdm_stop_provider					*/
/* Purpose     : Stop provider on remote DM Item			*/
/* Inputs      : Item							*/
/* Outputs     : Error Number						*/
/************************************************************************/
	Errno
rdm_stop_provider( DM_Item item )
{
    Errno	rtn;

    if ( (rtn = dm_stop_provider(item)) != SUCCESS )
	fprintf(stderr, 
		"Failure to stop provider on DM item %#x, rtn code %#x\n", 
		item, rtn);

    return( rtn );

} /* rdm_stop_provider() */


/************************************************************************/
/* Function    : rdm_start_cnsmr					*/
/* Purpose     : Actual Start consumer function				*/
/* Inputs      : Item, period, semaphore ID				*/
/* Outputs     : Error Number						*/
/* Comment     : All GUI except graphcall module calls rdm_start_consumer()*/
/*		 rdm_start_consumer() and graphcall module call this routine*/
/************************************************************************/
	Errno
rdm_start_cnsmr( DM_Item item, Nat32 period, SEM_ID sem )
{
    Errno	rtn;
    DmItemSts	sts;

    rtn = dm_start_consumer( item, period, sem );

    switch( rtn )
    {
      case SUCCESS:
      case EDM_NOPROVIDER:
      case EDM_TOOFAST:
      case EDM_PERIOD:
	return( SUCCESS );

      case EDM_ISCONSUMER:
	if ( dm_item_status(item, &sts) != SUCCESS )
	    return( SUCCESS );

	dm_item_status_free( &sts );

	if ( period >= sts.is_cnsmr_period )
	    return( SUCCESS );

	return( dm_set_period(item, period) );

      default:
	fprintf(stderr, "Failure to start consumer on ");

	if ( dm_item_status(item, &sts) == SUCCESS )
	{
	    fprintf( stderr, "%s", sts.is_name );
	    dm_item_status_free( &sts );
	}
	else
	    fprintf( stderr, "DM item %#x", item );

	fprintf(stderr, ", rtn code %#x\n", rtn);
    }

    return( rtn );

} /* rdm_start_cnsmr() */


/************************************************************************/
/* Function    : rdm_start_consumer					*/
/* Purpose     : Start consumer on remote DM Item			*/
/* Inputs      : Item, period, semaphore ID				*/
/* Outputs     : Error Number						*/
/************************************************************************/
	Errno
rdm_start_consumer( DM_Item item, Nat32 period, SEM_ID sem )
{
    Errno	rtn;

    rtn = rdm_start_cnsmr( item, period, sem );
    graphItemCnsmr( item, period );
    return( rtn );

} /* rdm_start_consumer() */


/************************************************************************/
/* Function    : rdm_set_period						*/
/* Purpose     : Set consumer period on remote DM Item			*/
/* Inputs      : Item, period						*/
/* Outputs     : Error Number						*/
/************************************************************************/
	Errno
rdm_set_period( DM_Item item, Nat32 period )
{
    Errno	rtn;

    return( dm_set_period(item, period) );

} /* rdm_set_period() */


/************************************************************************/
/* Function    : rdm_stop_consumer					*/
/* Purpose     : Stop consumer on remote DM Item			*/
/* Inputs      : Item							*/
/* Outputs     : Error Number						*/
/************************************************************************/
	Errno
rdm_stop_consumer( DM_Item item )
{
    Errno	rtn;

    rtn = dm_stop_consumer(item);

    switch( rtn )
    {
      case SUCCESS:
      case EDM_NOTCONSUMER:
	break;

      default:
	fprintf(stderr, 
		"Failure to stop consumer on DM item %#x, rtn code %#x\n", 
		item, rtn);
    }

    return( rtn );

} /* rdm_stop_consumer() */


/************************************************************************/
/* Function    : rdm_read						*/
/* Purpose     : Read Remote Data Manager item				*/
/* Inputs      : Item, buffer, size					*/
/* Outputs     : Error Number						*/
/************************************************************************/
	Errno
rdm_read( DM_Item item, char *buffer, Nat32 size )
{
    Errno	rtn;

    rtn = dm_read( item, buffer, size, (DM_Time *)NULL );

    if ( (rtn != SUCCESS) && (rtn != EDM_NOPROVIDER) )
	fprintf(stderr, "Failure to read DM item %#x, rtn code %#x\n", 
		item, rtn);

    return( rtn );

} /* rdm_read() */


/************************************************************************/
/* Function    : rdm_readtm						*/
/* Purpose     : Read Remote Data Manager item (including timestamp)	*/
/* Inputs      : Item, buffer, size, time ptr				*/
/* Outputs     : Error Number						*/
/************************************************************************/
	Errno
rdm_readtm( DM_Item item, char *buffer, Nat32 size, DM_Time *tm )
{
    Errno	rtn;

    rtn = dm_read( item, buffer, size, tm );

    if ( (rtn != SUCCESS) && (rtn != EDM_NOPROVIDER) )
	fprintf(stderr, "Failure to read DM item %#x, rtn code %#x\n", 
		item, rtn);

    return( rtn );

} /* rdm_readtm() */


/************************************************************************/
/* Function    : rdm_write						*/
/* Purpose     : Write Remote Data Manager item				*/
/* Inputs      : Item, buffer, update_time buffer			*/
/* Outputs     : Error Number						*/
/************************************************************************/
	Errno
rdm_write( DM_Item item, char *buffer, Nat32 size )
{
    Errno		rtn;
    struct timeval	curtime;
    struct timezone	tmzone;

    gettimeofday( &curtime, &tmzone );

    if ( (rtn = dm_write(item, buffer, size, &curtime)) != SUCCESS )
	fprintf(stderr, "Failure to write DM item %#x, rtn code %#x\n", 
		item, rtn);

    return( rtn );

} /* rdm_write() */


/************************************************************************/
/* Function    : rdm_write_once						*/
/* Purpose     : Write Remote Data Manager item one time		*/
/* Inputs      : Item, buffer, update_time buffer			*/
/* Outputs     : Error Number						*/
/************************************************************************/
	Errno
rdm_write_once( DM_Item item, char *buffer, Nat32 size )
{
    Errno		rtn;
    struct timeval	curtime;
    struct timezone	tmzone;
    struct timespec	interval = {0, 100000000}, remainder;

    dm_urgent_open( item, DM_STATIC );

    nanosleep(&interval, &remainder);	/* pean 6/16/98 temp fix for DM race */

    gettimeofday( &curtime, &tmzone );

    if ( (rtn = dm_write(item, buffer, size, &curtime)) != SUCCESS )
	fprintf(stderr, "Failure to write DM item %#x, rtn code %#x\n", 
		item, rtn);

    dm_urgent_close( item );

    return( rtn );

} /* rdm_write_once() */


/************************************************************************/
/* Function    : rdm_create_group					*/
/* Purpose     : Create remote DM group					*/
/* Inputs      : Error string						*/
/* Outputs     : Group ID, or NULL if error				*/
/************************************************************************/
	DM_Group
rdm_create_group( char *s )
{
    DM_Group	rtn;

    if ( (rtn = dm_create_group()) == NO_GROUP )
	fprintf(stderr, "Failure to create DM group for %s\n", s);

    return( rtn );

} /* rdm_create_group() */


/************************************************************************/
/* Function    : rdm_group_add_item					*/
/* Purpose     : Add an item to a remote DM group			*/
/* Inputs      : DM Group ID, DM_Item to add, place to return ID bit	*/
/* Outputs     : Error Number						*/
/************************************************************************/
	Errno
rdm_group_add_item( DM_Group gid, DM_Item dmid, DWord *id_bit )
{
    Errno	rtn;
    DmItemSts	sts;

    rtn = dm_group_add_item(gid, dmid, id_bit);

    if ( (rtn != SUCCESS) && (rtn != EDM_GROUP_SIZE) )
    {
	if ( dm_item_status(dmid, &sts) == SUCCESS )
	{
	    fprintf( stderr, "Failure to add %s", sts.is_name );
	    dm_item_status_free( &sts );
	}
	else
	    fprintf( stderr, "Failure to add DM item %#x", dmid );

	fprintf(stderr, " to DM group %#x; rtn = %#x\n", gid, rtn );
    }

    return( rtn );

} /* rdm_group_add_item() */


/************************************************************************/
/* Function    : rdm_group_delete_item					*/
/* Purpose     : Delete an item from a remote DM group			*/
/* Inputs      : DM Group ID, DM_Item to add				*/
/* Outputs     : Error Number						*/
/************************************************************************/
	Errno
rdm_group_delete_item( DM_Group gid, DM_Item dmid )
{
    Errno	rtn;
    DmItemSts	sts;

    rtn = dm_group_delete_item(gid, dmid);

    if ( (rtn != SUCCESS) && (rtn != EDM_GROUP_SIZE) )
    {
	if ( dm_item_status(dmid, &sts) == SUCCESS )
	{
	    fprintf( stderr, "Failure to delete %s", sts.is_name );
	    dm_item_status_free( &sts );
	}
	else
	    fprintf( stderr, "Failure to delete DM item %#x", dmid );

	fprintf(stderr, " from DM group %#x; rtn = %#x\n", gid, rtn );
    }

    return( rtn );

} /* rdm_group_delete_item() */


/************************************************************************/
/* Function    : rdm_get_group_changes					*/
/* Purpose     : Get bit vector of changes to a DM group		*/
/* Inputs      : DM Group ID						*/
/* Outputs     : Bit vector of items that have changed			*/
/************************************************************************/
	DWord
rdm_get_group_changes( DM_Group gid )
{
    return( dm_get_group_changes(gid) );

} /* rdm_get_group_changes() */


/************************************************************************/
/* Function    : rdm_delete_group					*/
/* Purpose     : Delete a remote DM group				*/
/* Inputs      : DM Group ID						*/
/* Outputs     : Error Number						*/
/************************************************************************/
	Errno
rdm_delete_group( DM_Group gid )
{
    Errno	rtn;

    if ( (rtn = dm_delete_group(gid)) != SUCCESS )
	fprintf(stderr, "Failure to delete DM group %x; rtn code = %#x\n",
		gid, rtn);

    return( rtn );

} /* rdm_delete_group() */

/************************************************************************/
/* Function    : rdm_peer_status					*/
/* Purpose     : Get Data Manager Peer status				*/
/* Inputs      : Ptr to DmPeerSts array, number of structs in array	*/
/* Outputs     : Peer status sequence number				*/
/************************************************************************/
	Int32
rdm_peer_status( DmPeerSts *stsp, Nat32 *npeers )
{
    return( dm_peer_status(stsp, npeers) );

} /* rdm_peer_status() */
