/************************************************************************/
/* Copyright 1990 - 1998 MBARI                                          */
/************************************************************************/
/* $Header: datamgr.h,v 7.2 99/02/04 15:08:04 bobh Exp $                */
/* Summary  : Type Definitions and Function Declarations for Data Manager*/
/* Filename : datamgr.h                                                 */
/* Author   : Bob Herlien (rah)                                         */
/* Project  : Tiburon ROV                                               */
/* $Revision: 7.2 $                                                     */
/* Created  : 02/26/90                                                  */
/************************************************************************/
/* Modification History:                                                */
/* $Log:        datamgr.h,v $
 * Revision 7.2  99/02/04  15:08:04  15:08:04  bobh (Bob Herlien)
 * Bug fixes (sequence numbers), better diagnostics
 *
 * Revision 7.1  98/11/05  16:37:33  16:37:33  bobh (Bob Herlien)
 * Added function logging
 *
 * Revision 7.0  98/02/20  08:26:56  08:26:56  bobh (Bob Herlien)
 * Integrate & test previous changes, start_consumer goes to all nodes.
 *
 * Revision 6.4  98/02/01  19:22:27  19:22:27  bobh (Bob Herlien)
 * Added type DmPid to fix pid reuse problem in VxWorks
 *
 * Revision 6.1  97/03/14  13:48:36  13:48:36  bobh (Bob Herlien)
 * Bug fix for dm_item_status
 *
 * Revision 6.0  96/12/04  15:18:02  15:18:02  bobh (Bob Herlien)
 * Boot Server, bug fixing
 *
 * Revision 5.1  94/12/06  15:10:41  15:10:41  hebo (Bob Herlien)
 * Changes due to code review and to enhance debugging of Unix version.
 * All tasks that executed dm_start_multiple() must execute dm_stop_multiple()
 * Added logfile keyword, logging enhancements.
 * Miscellaneous bug fixes
 *
 * Revision 5.0  94/08/19  12:06:08  12:06:08  hebo (Bob Herlien)
 * Unix port
 *
 * Revision 4.0  93/12/15  09:14:18  09:14:18  hebo (Bob Herlien)
 * Port to VxWorks 5.1.  Changed back to tCfgOut and tCfgIn tasks.
 *
 * Revision 3.2  93/07/20  16:35:06  16:35:06  hebo (Bob Herlien)
 * Fixed numerous bugs, including semaphore fixups, dm_cfginit problems,
 * and INIT_DATA.  Added dm_get_connect() and is_connect_source.  Fixed
 * group bugs and allowed multiple groups per item per task.
 *
 * Revision 3.1  93/04/12  16:00:59  16:00:59  hebo (Bob Herlien)
 * Misc minor bug fixes
 *
 * Revision 3.0  93/03/02  11:14:09  11:14:09  hebo (Bob Herlien)
 * Added type information to dm_create(), dm_create_items(), and dm_init()
 *
 * Revision 2.4  92/12/02  09:51:59  09:51:59  hebo (Bob Herlien)
 * Added dm_search()
 *
 * Revision 2.3  92/11/19  09:58:12  09:58:12  hebo (Bob Herlien)
 * added dm_[start/stop]_multiple
 *
 * Revision 2.1  92/07/30  10:06:17  10:06:17  hebo (Bob Herlien)
 * Changed name management to use VxWorks hash functions.
 * Changed nm_search to nm_each, similar to VxWorks hash and symbol functions.
 * This caused change to network init (dmcfginit), since nm_each locks entire
 *   name table for operation.
 * Added rtn_items parameter to dm_create(), added function dm_create_items()
 *
 * Revision 2.0  91/05/21  10:21:00  10:21:00  hebo (Bob Herlien 408-647-3748)
 * Port to VxWorks 5.0
 *
 * Revision 1.2  91/02/27  15:32:26  15:32:26  hebo (Bob Herlien 408-647-3748)
 * Added groups, minor changes (dm_write, dm_init)
 *
 * Revision 1.1  91/01/23  10:48:36  10:48:36  hebo (Bob Herlien 408-647-3748)
 * Minor changes mostly due to debug problems (vxgdb)
 *
 * Revision 1.0  90/09/06  09:15:29  09:15:29  hebo (Bob Herlien 408-647-3748)
 * Official release of distributed data manager
 *
 * Revision 0.8  90/08/13  15:27:47  15:27:47  hebo (Bob Herlien 408-647-3748)
 * First multi-cpu version, still some loose ends to clean up.
 *
 * Revision 0.6  90/05/29  14:04:38  14:04:38  hebo (Bob Herlien 408-647-3748)
 * Converted to vxgcc. We finally have ANSII C!
 *
 * Revision 0.5  90/05/08  18:22:17  18:22:17  hebo (Bob Herlien 408-647-3748)
 * First RCS version, bug fixes
 *      */
/* 01may90 rah, Rel 0.4, new string-oriented interface                  */
/* 30mar90 rah, Rel 0.2, local only, added urgent calls and signals     */
/* 20mar90 rah, Rel 0.1, local (single CPU) case only, no urgent calls  */
/* 26feb90 rah, created                                                 */
/************************************************************************/
/* Note - To avoid compiler errors, you need to include the following   */
/*        files AHEAD of this include file:                             */
/*        #include <mbari/types.h>                                      */
/*        #include <vxWorks.h> (VxWorks) or <dmUnix.h> (Unix)           */
/*        #include <sys/times.h> (VxWorks) or <time.h> (Unix)           */
/*        #include <semLib.h>                                           */
/*        #include <lstLib.h>                                           */
/*        #include <hashLib.h>                                          */
/************************************************************************/

#ifndef INCdatamgrh
#define INCdatamgrh     1

#ifdef __cplusplus
extern "C" {
#endif

typedef long int        Errno;          /* Return Code                  */
typedef unsigned int    DM_Item;        /* DM item handle               */
typedef unsigned int    DM_Size;        /* Size of DM item              */
typedef unsigned int    DM_Num;         /* Number of items in array     */

typedef struct timeval  DM_Time;        /* Time in vxWorks format       */

typedef unsigned long   Period;         /* Provider or consumer period  */
                                        /* (1/rate) in microseconds     */
typedef int             Signal;         /* Signal identifier            */
typedef int             Pid;            /* Process (Task) ID            */
typedef unsigned int    DM_Group;       /* DM_Item Group ID             */
typedef unsigned long   InAddr;         /* Internet address             */
typedef InAddr          CPU_No;         /* Remote CPU # = inet addr     */

#define NULL_INADDR     ((InAddr)0)     /* NULL Inet address            */

#ifndef SUCCESS
#define SUCCESS         0               /* SUCCESS - No error           */
#endif

#define MAX_ITM_SIZE    512             /* Max. size of data item       */
                                /* MUST allow data item to go into UDP pkt*/
                                /* Should minimize size of DataMsg      */
                                /* See dmnet.h (UDP_SIZE, DataMsg)      */
#define MAX_NMLEN       255     /* Max size Data Manager name           */
#define MAX_TYPES       32      /* Max nmbr of types in struct          */
#define MAX_PEERS       16      /* Max nmbr peers we can send in Init pkt*/


#define NO_ITEM         ((DM_Item)(0))  /* Error return on handle func  */
#define SEM_NULL        ((SEM_ID)0)     /* Null semaphore ID            */
#define NO_SIGNAL       ((Signal)(-1))  /* No error signal handler      */
                                /* SEE NOTES ON SIGNALS AT END OF FILE  */
#define NO_GROUP        (DM_Group)0     /* Not yet associated with group*/


#define PERIOD_MAX      ((Period)(-2))
#define NO_PERIOD       ((Period)(-1))

#define DM_ASYNC        ((Period)1)
                        /* No Provider or Consumer period               */
                        /* If provider uses this as its period, all     */
                        /*  consumers will be wakened on every write    */
                        /* If a consumer uses this as its consumer      */
                        /*  period, it will be wakened on every write   */
                        /* (assuming it passed a wakeup semaphore)      */

#define DM_STATIC       ((Period)0)
                        /* Similar to DM_ASYNC above, no prvdr period.  */
                        /* DM_STATIC data will also be sent on every    */
                        /* write.  In addition, it is sent to remote    */
                        /* nodes via TCP (reliable channel), and is sent*/
                        /* to ALL nodes, whether or not they currently  */
                        /* have a consumer.  Intended to be used for    */
                        /* static data, such as tables, transformation  */
                        /* matrices, etc., that are typically written   */
                        /* once (or a small nmbr or times) and don't change*/


typedef enum                            /********************************/
{                                       /* Data types for DM_Item data  */
    DM_ENDT = 0,                        /* Signifies end of DM_Element array*/
                                        /* Primitive types folllow:     */
    DM_EMPTY,                           /* Zero-length DM item          */
    DM_CHAR,                            /* char                         */
    DM_UCHAR,                           /* unsigned char                */
    DM_INT16,                           /* 16 bit int                   */
    DM_NAT16,                           /* 16 bit unsigned int          */
    DM_INT32,                           /* 32 bit int                   */
    DM_NAT32,                           /* 32 bit unsigned int          */
    DM_MBOOL,                           /* MBARI boolean type (short)   */
    DM_FLT32,                           /* 32 bit float (C float)       */
    DM_FLT64,                           /* 64 bit float (C double)      */
    DM_PTR,                             /* Any kind of pointer          */
    DM_ENUM,                            /* Enumerated data type         */
                                        /* Compound types               */
    DM_ARRAY,                           /* Array of primitive types     */
    DM_STRUCT                           /* Any kind of structure        */
} DM_Type;                              /********************************/

#define DM_COMPOUND     DM_ARRAY

typedef struct                          /********************************/
{                                       /* For one element of compound type*/
    DM_Type     elt_type;               /* Type of elemental item       */
    DM_Num      elt_num;                /* Number of elements of that type*/
} DM_Element;                           /********************************/

#define DMT_NULL        ((DM_Element *)0)

typedef enum                            /********************************/
{                                       /* Provider status type         */
    NOT_PRVDR = 0,                      /* Not a provider               */
    EXCL_PRVDR,                         /* Exclusive (dm_start_prvdr)   */
    MULT_PRVDR                          /* Multiple provider            */
} DmPrvdrType;                          /********************************/

typedef struct                          /********************************/
{                                       /* Structure to define DM Items */
    char        *itm_name;              /* Name of item                 */
    DM_Num      itm_nitems;             /* Number of DM_Items to create */
    DM_Type     itm_type;               /* Type of item, as above       */
    DM_Element  *itm_compound;          /* Ptr to array of primitive types*/
                                        /* term by zero-len elt, or DMT_NULL*/
    Void        *itm_data;              /* Array of initial values      */
} DM_Define;                            /********************************/

typedef struct                          /********************************/
{                                       /* DM Item Status Structure     */
    char        *is_name;               /* Ptr to returned name string  */
    DM_Num      is_item_num;            /* Item number if part of arry of*/
    DM_Size     is_size;                /* Total data size in bytes     */
    CPU_No      is_prvdr_cpu;           /* CPU ident that prvdr is on   */
    Pid         is_prvdr;               /* Provider Pid if cpu == CPU_LOCAL*/
    Period      is_prvdr_period;        /* Provider period              */
    Period      is_cnsmr_period;        /* Consumer period for calling  */
                                        /*  task; NO_PERIOD if not cnsmr*/
    Nat32       is_seq;                 /* Data sequence number         */
    DM_Type     is_type;                /* Type of data                 */
    DM_Element  *is_compound;           /* Ptr to array of primitive types*/
    DM_Num      is_num_compounds;       /* Number of types in *is_compound*/
    DM_Item     is_connect_source;      /* Source of data if dm_connect()ed*/
                                        /* If not, returns Item passed in*/
} DmItemSts;                            /********************************/

typedef enum                            /********************************/
{                                       /* Connection states for peer sts*/
    DMP_ERROR = -1,                     /* Network Error                */
    DMP_NOTCONN = 0,                    /* Not yet connected            */
    DMP_BOOT,                           /* Booting                      */
    DMP_INIT,                           /* Initializing                 */
    DMP_INIT2,                          /* Initialization phase 2       */
    DMP_INIT_SENT,                      /* Done sending init state      */
    DMP_INIT_RCVD,                      /* Done receivinging init state */
    DMP_CONN,                           /* Connected                    */
    DMP_SELF,                           /* Internal use only - not peer_sts*/
    DMP_NOPEER                          /* Ditto                        */
} PeerState;                            /********************************/

typedef struct                          /********************************/
{                                       /* Peer CPU Status              */
    InAddr      peer_addr;              /* Peer's internet address      */
    PeerState   peer_state;             /* Connection state             */
} DmPeerSts;                            /********************************/


#if (defined(__STDC__) || defined(__cplusplus))
                                        /* ANSII C function prototypes  */
#ifdef UNIX
        Errno                           /* INIT - Initialize Data Manager*/
dm_init( DM_Define *items );            /* Ptr to array of DM_Define's, */
                                        /*  terminated by NULL itm_name ptr*/
#else /* VxWorks */
        Errno                           /* INIT - Initialize Data Manager*/
dm_init(DM_Define *items, Nat32 noBootWait);/* Ptr to array of DM_Define's,*/
                                        /* flag to boot without waiting  */
#endif

        MBool                           /* EXIST - Return TRUE if Data  */
dm_exist( Void );                       /*  Manager exists & is initialized*/

        Errno                           /* CREATE Array of DM Items     */
dm_create(
        char    *name,                  /* Name of item array           */
        DM_Num  nitems,                 /* Number of items in array     */
        DM_Item *rtn_ids,               /* Place to return DM_Item ids  */
                                        /* Pairs of vararg args.  Type of elt*/
                                        /*  and num elements of dmtype. */
        ... );                          /* Terminate arg pairs with DM_ENDT*/

        Errno                           /* CREATE multiple initialized items*/
dm_create_items( DM_Define *itemp );    /* Array of DM_Define structs   */

        DM_Item                         /* LOOKUP - Convert string to ID*/
dm_lookup(                              /* Returns NO_ITEM if not found */
        char    *name,                  /* String name of item          */
        DM_Num  itm_no );               /* Item number of DM_Item array */

        Errno                           /* ITEM STATUS                  */
dm_item_status(
        DM_Item item,                   /* Data item ID to get status on*/
        DmItemSts *sts );               /* Ptr to struct to return status*/

        Errno                           /* Free Memory Allocated by ItemStatus*/
dm_item_status_free( DmItemSts *sts );  /* Struct used for dm_item_status() */

        DM_Item                         /* SEARCH - Search for matching */
dm_search(                              /*              DM Item name    */
        char    *name,                  /* Name ('*' and '?' expanded)  */
        DM_Item from,                   /* NO_ITEM to start, or last rtnd item*/
        DM_Num  *nitems );              /* Returns # items with name    */

        Errno                           /* START_PROVIDER - Identify    */
dm_start_provider(                      /*      yourself as a data source*/
        DM_Item item,                   /* Data item ID                 */
        Period  period );               /* Source period in us          */

        Errno                           /* START_MULTIPLE - Start a multi-*/
dm_start_multiple( DM_Item item );      /*   access DM item             */

        Errno                           /* START_CONSUMER - Identify    */
dm_start_consumer(                      /*      yourself as a data consumer*/
        DM_Item item,                   /* Data item ID                 */
        Period  cnsm_period,            /* 1/Rate you want to read data */
        SEM_ID  wakeup_sem );           /* SEM_ID to write when item is */
                                        /*    updated (0 for none)      */

        Errno                           /* STOP_PROVIDER - Declare you're*/
dm_stop_provider(                       /*      no longer sourcing info */
        DM_Item item );                 /* Data item to stop            */

        Errno                           /* STOP_MULTIPLE - Stop a multi-*/
dm_stop_multiple( DM_Item item );       /*   access DM item             */

        Errno                           /* STOP_CONSUMER - Declare you're*/
dm_stop_consumer(                       /*      no longer using info    */
        DM_Item item );                 /* Data item to stop            */

        Errno                           /* READ - Get a data item       */
dm_read(
        DM_Item item,                   /* Data item to read            */
        Void    *buffer,                /* Where to read it to          */
        DM_Size size,                   /* Max size to read             */
        DM_Time *upd_time );            /* Time of last update          */

        Errno                           /* WRITE - Write a data item    */
dm_write(
        DM_Item item,                   /* Data item to write           */
        Void    *buffer,                /* Where to write it from       */
        DM_Size size,                   /* Size to write                */
        DM_Time *upd_time );            /* Time item sampled (optional) */

        Errno                           /* SET PERIOD - Identify period */
dm_set_period(                          /*      at which you want to read*/
        DM_Item item,                   /* Data item                    */
        Period  period );               /* Consumer data period (1/rate)*/

        Errno                           /* TASK EXIT - Release any DM   */
dm_task_exit( Pid pid );                /*   resources owned by task    */

        Int32                           /* PEER STATUS - Return status  */
dm_peer_status(                         /*   of peer Data Manager nodes */
        DmPeerSts *stsp,                /* Ptr to buffer to hold status */
        Nat32     *npeers );            /* On entry, number of structs  */
                                        /*  in stsp.  On exit, number of*/
                                        /*  structs filled in           */
                                        /* Returns sequence number, allowing*/
                                        /* caller to detect changed status*/
                                        /* Returns -1 on error          */
        DM_Item                         /* DM_GET_CONNECT - Get head of */
dm_get_connect( DM_Item item );         /*  connect chain for item      */

        DmPrvdrType                     /* dmPrvdrStatus - Find out whether*/
dmPrvdrStatus( DM_Item item );          /*  an item has ANY provider    */

        DmPrvdrType                     /* dmPrvdrSelf - Find out whether*/
dmPrvdrSelf( DM_Item item );            /*  calling task is provider of item*/


/*  URGENT Calls                                                        */
/*    URGENT calls allow a task that detects an exceptional condition   */
/*    to unilaterally wrest control of a data item from its normal      */
/*    provider.  Until the exception task releases this control through */
/*    dm_urgent_close(), the normal data provider will get error returns*/
/*    from his calls to dm_write().                                     */

        Errno                           /* URGENT OPEN - Force yourself */
dm_urgent_open(                         /*      as provider             */
        DM_Item item,                   /* Data item                    */
        Period  period );               /* Source period in us          */

        Errno                           /* URGENT CLOSE - Restore previous*/
dm_urgent_close(                        /*      provider status         */
        DM_Item item );                 /* Data item                    */


/*  CONFIGURATION Calls                                                 */
/*    CONFIGURATION calls allow (a) configuration task(s) to create     */
/*    associations between data item sources and destinations.  When    */
/*    this association exists, any write to the source item will also   */
/*    write the destination item.  Conceptually, this allows another    */
/*    data item, rather than an external task, to be a data provider    */

        Errno                           /* CONNECT - Create association */
dm_connect(                             /*      between data items      */
        DM_Item source,                 /* Source data item             */
        DM_Item destination );          /* Destination data item        */

        Errno                           /* DISCONNECT - Break association*/
dm_disconnect(                          /*      between data items      */
        DM_Item destination );          /* Destination data item        */

/*   SIGNALs                                                            */
/* You can specify that the Data Manager should assert a signal to a    */
/* task when the Data Manager detects an error in any given DM_Item.    */
/* The signal is asserted in any of the following cases:                */
/* - the data provider goes away, due to a dm_stop_provider(),          */
/*      a dm_disconnect(), or a system error.                           */
/* - an error on dm_write()                                             */
/* - a system error (e.g. network error)                                */
/*                                                                      */
/* The use of this signal can be very important in a distributed system.*/
/* Dm_start_provider(), dm_urgent_open(), and dm_connect() will return  */
/* success if they pass checks on the local node.  They can, however,   */
/* fail remotely (e.g. a task on another node issues the same call at   */
/* the same time).  A dm_start_provider() that fails in this way will be*/
/* detected on the next dm_write(), but a dm_connect() failure may never*/
/* be detected without the use of an error signal.                      */
/*                                                                      */
/* A task may have signal handlers for as many DM Items as it wishes,   */
/* but a given task may specify only one signal number per DM Item.     */
/* If you call dm_signal a second time with the same item and sigtask   */
/* parameters, but a different signum, it REPLACES the signum of the    */
/* first call.  To specify that you no longer wish to receive a signal, */
/* call dm_signal with signum = NO_SIGNAL.                              */
/*                                                                      */
/* Signal handlers:                                                     */
/* VxWorks can pass an error code with the signal.  This is used        */
/* by the Data Manager to pass the Data Item number.  The actual        */
/* error number can then be obtained by calling dm_get_error().         */
/* Unfortunately, Unix(tm) signals don't pass error codes, so no error  */
/* information is passed to the signal handler under Unix.              */

        Errno                           /* SIGNAL -  Identify signal    */
dm_signal(                              /*      number to assert on error*/
           DM_Item item,                /* Item for which we want error sigs*/
           Pid     sigtask,             /* Task to receive error signal */
           Signal  signum );            /* Signal to assert on error    */


/*   GROUPs                                                             */
/* GROUPs are useful to associate a number of DM_Items for the purpose  */
/* of detecting changes in those items.                                 */
/* A group is identified by a group_id of type DM_Group.  This handle   */
/* is specific to a particular task.  That is, if a group is created    */
/* by task A, and the group_id is then used in a group function called  */
/* by task B, the function will fail.                                   */

        DM_Group                        /* CREATE_GROUP - Create a      */
dm_create_group( Void );                /*      consumer group          */
                                        /* Returns NO_GROUP if failed   */

        Errno                           /* DELETE_GROUP - Delete a      */
dm_delete_group(                        /*      consumer group          */
        DM_Group group_id );            /* Group ID                     */

        Errno                           /* GROUP_ADD_ITEM - Add item to */
dm_group_add_item(                      /*      consumer group          */
        DM_Group group_id,              /* Group ID                     */
        DM_Item item,                   /* Data item to add to group    */
        DWord   *id_bit );              /* Returns bit identifying item */

        Errno                           /* GROUP_DELETE_ITEM - Delete   */
dm_group_delete_item(                   /*      item from consumer group*/
        DM_Group group_id,              /* Group ID                     */
        DM_Item item );                 /* Data item to delete from group*/

        DWord                           /* GET_GROUP_CHANGES - Get id bits*/
dm_get_group_changes(                   /*   of items that have changed   */
        DM_Group group_id );            /* Group ID to get bits for       */
                                        /* This call clears the change vector*/

        DM_Item                         /* GROUP_LOOKUP - Convert group_id*/
dm_group_lookup(                        /*   and id bit to DM_Item      */
        DM_Group group_id,              /* Group ID                     */
        DWord    id_bit );              /* ID bit (one bit only)        */
                                        /* Returns valid DM_Item or     */
                                        /*      NO_ITEM if failed       */

#endif  /* __STDC__ */

#ifdef __cplusplus
}
#endif

#endif  /* INCdatamgrh */
