/************************************************************************/
/* Copyright 1992 MBARI							*/
/************************************************************************/
/* $Header: /usr/tiburon/unix/gui/proto/RCS/ibc.c,v 1.1 1998/01/28 16:17:12 oreilly Exp $		*/
/* Summary  : Routines to create IBC Screens for ROV User Interface	*/
/* Filename : ibc.c							*/
/* Author   : Bob Herlien (rah)						*/
/* Project  : New ROV							*/
/* $Revision: 1.1 $							*/
/* Created  : 05/21/92							*/
/************************************************************************/
/* Modification History:						*/
/* $Log: ibc.c,v $
 * Revision 1.1  1998/01/28 16:17:12  oreilly
 * Initial revision
 *
 * Revision 2.2  96/05/15  11:15:35  11:15:35  bobh (Bob Herlien)
 * Still supporting proto during final vehicle build
 * 
 * Revision 2.0  95/09/20  14:23:03  14:23:03  hebo (Bob Herlien)
 * Support for final vehicle integration.  AC, PDU micros.
 * 
 * Revision 1.7  94/03/21  14:15:17  14:15:17  hebo (Bob Herlien)
 * Misc bug fixes and enhancements
 * 
 * Revision 1.6  93/12/17  15:04:59  15:04:59  hebo (Bob Herlien)
 * December Wet Test
 * 
 * Revision 1.5  93/07/08  18:10:57  18:10:57  hebo (Bob Herlien)
 * Prior to Prototype Phase I testing
 * 
 * Revision 1.4  93/05/27  15:48:02  15:48:02  hebo (Bob Herlien)
 * Data Manager Interface
 * 
 * Revision 1.2  93/01/21  10:34:18  10:34:18  hebo (Bob Herlien)
 * Changes after Level 0
 * 
 * Revision 1.0  92/11/20  12:03:28  12:03:28  hebo (Bob Herlien)
 * Initial revision
 * 
*/
/************************************************************************/

#include <mbari/types.h>
#include <mbari/const.h>
#include <Xm/Xm.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xlib.h>
#include <Xm/Text.h>
#include <Xm/TextF.h>
#include <Xm/Separator.h>
#include <Xm/Label.h>
#include <Xm/LabelG.h>
#include <Xm/ScrolledW.h>
#include <Xm/Form.h>
#include <Xm/BulletinB.h>
#include <Xm/RowColumn.h>
#include <Xm/PushB.h>
#include <Xm/PushBG.h>
#include <X11/Xc/Xc.h>
#include <X11/Xc/ToggleB.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
#include "rdmif.h"
#include <datamgr.h>
#include <dm_errno.h>
#include "rov.h"
#include "alarm.h"
#include "ibc.h"
#include <thrusterDM.h>
#include <microdef.h>
#include <ibc_card.h>

typedef struct				/********************************/
{					/* IBC Board Struct		*/
    Nat16	numCards;		/* Number of cards		*/
    Word	boardAddr[IBC_MAX_CARDS]; /* Addresses of cards		*/
} ibcBoard;				/********************************/

typedef struct				/********************************/
{					/* Struct for Names of IBC Boards*/
    Word	boardAddr;		/* Board Address		*/
    Word	boardMask;		/* Bits to mask off mult boards	*/
    Word	boardRange;		/* Number of I/O addr for 1 board*/
    char	*boardName;		/* Name of Board		*/
} ibcBoardName;				/********************************/

#define IBC_BOARDS_PER_LINE	2


/********************************/
/*	External Functions	*/
/********************************/

Extern Widget	rovCreateQuestionDialog(Widget parent, char *title, char *msg);
Extern char 	*rovMalloc( Nat32 size );
Extern MBool	graphItemInUse( DM_Item item );
Extern Int32	printType( DM_Type dtype, DM_Size size, char *dat, char *buff );


/********************************/
/*	External Data		*/
/********************************/

Extern XtAppContext	appcontext;	/* The application context	*/
Extern AppData		appdata;	/* Application-wide resources	*/
Extern Widget		ibcRowColumn;	/* Parent to all IBC group RowCols*/
Extern ibcItemDesc	*ibcDescs[];
Extern Select		*ibcSelects[];
Extern ibcItemSet	*ibcSets[];
Extern SelectStatus	ibcSts;
Extern Nat32		typeSizes[];
Extern char		buff[];		/* Misc buffer used application-wide*/


/********************************/
/*	Module Local Data	*/
/********************************/

MLocal Widget	 	ibcDialog;
MLocal MBool		textFUpdate = FALSE;
MLocal ibcItem		*multItem;
MLocal ibcItemDesc	*currentIbcItemDesc;
MLocal Pixel		ibcToggleOnColor;
MLocal Pixel		gfCurrentColor;
MLocal char		ibcBuff[1024];

MLocal ibcBoardName	ibcBdNames[] =
{ { 0,     0,    0x10, "CPU196" },
  { 0x10,  0x7,  2,    "12V Low Pwr Switch" },
  { 0x18,  0x7,  2,    "24V Low Pwr Switch" },
  { 0x20,  0x7,  2,    "48V Low Pwr Switch" },
  { 0x28,  0x7,  2,    "Var Low Pwr Switch" },
  { 0x40,  0x7,  4,    "Parallel I/O"},
  { 0x48,  0x7,  2,    "Ground Fault"},
  { 0x50,  0x7,  2,    "Quad A/D"},
  { 0x60,  0,    4,    "Nav Interface"},
  { 0x63,  0,    1,    "Hydrophone PSU"},
  { 0x64,  0x1,  1,    "Regen Control"},
  { 0x70,  0x0f, 2,    "High Pwr Switch"},
  { 0x80,  0x1f, 0x20, "Quad Serial"},
  { 0xc0,  0x0f, 4,    "Isolated I/O"},
  { 0x200, 0x1,  1,    "Dual Vicor"},
  { 0x210, 0,    1,    "Data Switch"}
};


/************************************************************************/
/* Function    : pushButtonCreate					*/
/* Purpose     : Create a PushButton					*/
/* Inputs      : Unused widget ID, ibcItem ptr				*/
/* Outputs     : None							*/
/* Parameters  : itm->parm1 = left position, itm->parm2 = right position*/
/*		 itm->ptrparm = ptr to array of 2 strings --		*/
/*		   button label, and confirmation dialog string		*/
/************************************************************************/
	Void
pushButtonCreate( Widget parent, ibcItem *itm )
{
    XmString	labelString;

    labelString = XmStringCreateLtoR( *(char **)(itm->ptrparm),
				      XmSTRING_DEFAULT_CHARSET );
    itm->widget = XtVaCreateManagedWidget(
			    *(char **)(itm->ptrparm),
			    xmPushButtonWidgetClass, parent,
			    XmNheight, BUTTON_HEIGHT,
			    XmNlabelString, labelString,
			    XmNleftAttachment, XmATTACH_POSITION,
			    XmNrightAttachment, XmATTACH_POSITION,
			    XmNleftPosition, itm->parm1,
			    XmNrightPosition, itm->parm2,
			    XmNrecomputeSize, False,
			    NULL);

    XmStringFree( labelString );

    if ( itm->activate )
	XtAddCallback( itm->widget, XmNactivateCallback, itm->activate, itm );

} /* pushButtonCreate() */


/************************************************************************/
/* Function    : resetButtonCreate					*/
/* Purpose     : Create Reset PushButton				*/
/* Inputs      : Parent Widget ID, ibcItem ptr				*/
/* Outputs     : None							*/
/* Parameters  : itm->parm1 = left position, itm->parm2 = right position*/
/*		 itm->ptrparm = ptr to array of 2 strings --		*/
/*		   button label, and confirmation dialog string		*/
/************************************************************************/
	Void
resetButtonCreate( Widget parent, ibcItem *itm )
{
    pushButtonCreate( parent, itm );

    ibcDialog = rovCreateQuestionDialog( parent, "Confirm", NULL );

} /* resetButtonCreate() */


/************************************************************************/
/* Function    : toggleButtonCreate					*/
/* Purpose     : Create a ToggleButton					*/
/* Inputs      : Unused widget ID, ibcItem ptr				*/
/* Outputs     : None							*/
/* Parameters  : itm->parm1 = left position, itm->parm2 = right position*/
/************************************************************************/
	Void
toggleButtonCreate( Widget parent, ibcItem *itm )
{
    itm->widget = XtVaCreateManagedWidget(
			    "button", xcToggleButtonWidgetClass, parent,
			    XtNheight, TOGGLE_BUTTON_HEIGHT,
			    XmNtopAttachment, XmATTACH_NONE,
			    XmNbottomAttachment, XmATTACH_FORM,
			    XmNleftAttachment, XmATTACH_POSITION,
			    XmNrightAttachment, XmATTACH_POSITION,
			    XmNleftPosition, itm->parm1,
			    XmNrightPosition, itm->parm2,
			    XcNlabel, itm->ptrparm,
			    NULL);

    if ( itm->activate )
	XtAddCallback( itm->widget, XmNactivateCallback, itm->activate, itm );

    XtVaGetValues( itm->widget, XcNonColor, &ibcToggleOnColor, NULL );

} /* toggleButtonCreate() */


/************************************************************************/
/* Function    : labelCreate						*/
/* Purpose     : Create a label for displaying IBC information		*/
/* Inputs      : Parent Widget ID, ibcItem ptr, left & right positions	*/
/* Outputs     : None							*/
/* Parameters  : For normal labels, none				*/
/*		 For enum labels, parm1 = number of enum values		*/	
/*				  ptrparm = ptr to string array		*/
/*		 For fixed pt, parm1 = positions to display rt of dec pt*/
/*			       parm2 = divisor for item value		*/
/* Comment     : Changed to xmTextField for efficiency			*/
/************************************************************************/
	Void
labelCreate( Widget parent, ibcItem *itm, Int32 lpos, Int32 rpos )
{
    itm->widget = XtVaCreateManagedWidget(
			    "ibcValueLabel", xmTextFieldWidgetClass, parent,
			    XmNtopAttachment, XmATTACH_FORM,
			    XmNbottomAttachment, XmATTACH_FORM,
			    XmNleftAttachment, XmATTACH_POSITION,
			    XmNrightAttachment, XmATTACH_POSITION,
			    XmNleftPosition, lpos,
			    XmNrightPosition, rpos,
			    XmNvalue, itm->dmname,
			    XmNeditable, False,
			    XmNshadowThickness, 0,
			    XmNcursorPositionVisible, False,
			    NULL);

} /* labelCreate() */


/************************************************************************/
/* Function    : labelVarCreate						*/
/* Purpose     : Create a variable size label for IBC information	*/
/* Inputs      : Parent Widget ID, ibcItem ptr, left & right positions	*/
/* Outputs     : None							*/
/* Parameters  : Same as labelCreate					*/
/* Comment     : Changed to xmTextField for efficiency			*/
/************************************************************************/
	Void
labelVarCreate( Widget parent, ibcItem *itm, Int32 lpos, Int32 rpos )
{
    itm->widget = XtVaCreateManagedWidget(
			    "ibcValueLabel", xmTextFieldWidgetClass, parent,
			    XmNtopAttachment, XmATTACH_FORM,
			    XmNbottomAttachment, XmATTACH_FORM,
			    XmNleftAttachment, XmATTACH_POSITION,
			    XmNrightAttachment, XmATTACH_FORM,
			    XmNleftPosition, lpos,
			    XmNvalue, itm->dmname,
			    XmNeditable, False,
			    XmNshadowThickness, 0,
			    XmNcursorPositionVisible, False,
			    NULL);

} /* labelVarCreate() */


/************************************************************************/
/* Function    : staticLabelCreate					*/
/* Purpose     : Create a static (unchanging) label			*/
/* Inputs      : Parent Widget ID, ibcItem ptr, left & right positions	*/
/* Outputs     : None							*/
/* Parameters  : ptrparm = label string					*/
/************************************************************************/
	Void
staticLabelCreate( Widget parent, ibcItem *itm, Int32 lpos, Int32 rpos )
{
    XmString	str;

    str = XmStringCreateSimple(itm->ptrparm);

    itm->widget = XtVaCreateManagedWidget(
			    "ibcValueLabel", xmLabelWidgetClass, parent,
			    XmNtopAttachment, XmATTACH_FORM,
			    XmNbottomAttachment, XmATTACH_FORM,
			    XmNleftAttachment, XmATTACH_POSITION,
			    XmNrightAttachment, XmATTACH_FORM,
			    XmNleftPosition, lpos,
			    XmNvalue, itm->dmname,
			    XmNlabelString, str,
			    NULL);
    XmStringFree(str);

} /* staticLabelCreate() */


/************************************************************************/
/* Function    : xmLabelCreate						*/
/* Purpose     : Create a label for displaying IBC information		*/
/* Inputs      : Parent Widget ID, ibcItem ptr, left & right positions	*/
/* Outputs     : None							*/
/* Parameters  : For normal labels, none				*/
/*		 For enum labels, parm1 = number of enum values		*/	
/*				  ptrparm = ptr to string array		*/
/*		 For fixed pt, parm1 = positions to display rt of dec pt*/
/*			       parm2 = divisor for item value		*/
/* Comment     : This is to REALLY create labels			*/
/************************************************************************/
	Void
xmLabelCreate( Widget parent, ibcItem *itm, Int32 lpos, Int32 rpos )
{
    XmString	str;

    str = XmStringCreateSimple(itm->dmname);

    itm->widget = XtVaCreateManagedWidget(
			    "ibcValueLabel", xmLabelWidgetClass, parent,
			    XmNtopAttachment, XmATTACH_FORM,
			    XmNbottomAttachment, XmATTACH_FORM,
			    XmNleftAttachment, XmATTACH_POSITION,
			    XmNleftPosition, lpos,
			    XmNrecomputeSize, TRUE,
			    XmNlabelString, str,
			    NULL);
    XmStringFree(str);

} /* xmLabelCreate() */


/************************************************************************/
/* Function    : labelGroupCreate					*/
/* Purpose     : Create one of a group of Labels for IBC		*/
/* Inputs      : Parent Widget ID, ibcItem ptr, left & right positions	*/
/* Outputs     : None							*/
/* Parameters  : ptrparm = ptr to array of Widget IDs to store		*/
/*		 parm1 = which array entry to store widget ID in 	*/
/************************************************************************/
	Void
labelGroupCreate( Widget parent, ibcItem *itm, Int32 lpos, Int32 rpos )
{
    labelCreate( parent, itm, lpos, rpos );

    ((Widget *)(itm->ptrparm))[itm->parm1] = itm->widget;

    XtVaGetValues( itm->widget, XtNbackground, &gfCurrentColor, NULL );

} /* labelGroupCreate() */


/************************************************************************/
/* Function    : cancelTextField					*/
/* Purpose     : Callback for "Cancel" pushbutton adjacent to TextField	*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
cancelTextField( Widget w, ibcItem *itm, XmAnyCallbackStruct *cbp )
{
    if ( itm->update )
	(*itm->update)(itm);

} /* cancelTextField() */


/************************************************************************/
/* Function    : textFieldCreate					*/
/* Purpose     : Create a TextField for modifying IBC information	*/
/* Inputs      : Parent Widget ID, ibcItem ptr, left & right positions	*/
/* Outputs     : None							*/
/* Parameters  : parm1 = XmNmaxLength					*/
/*		 For fixed pt, parm2 = positions to display rt of dec pt*/
/*		 For fixed pt, (Nat32)ptrparm = divisor for item value	*/
/************************************************************************/
	Void
textFieldCreate( Widget parent, ibcItem *itm, Int32 lpos, Int32 rpos )
{
    XmString	str;

    itm->widget = XtVaCreateManagedWidget(
			    "textField", xmTextFieldWidgetClass, parent,
			    XmNtopAttachment, XmATTACH_FORM,
			    XmNbottomAttachment, XmATTACH_FORM,
			    XmNleftAttachment, XmATTACH_POSITION,
			    XmNrightAttachment, XmATTACH_POSITION,
			    XmNleftPosition, lpos,
			    XmNrightPosition, rpos,
			    XmNmaxLength, itm->parm1, 
			    NULL);

    str = XmStringCreateSimple("OK");
    itm->auxWid1 = XtVaCreateWidget("OKButton", xmPushButtonWidgetClass,
			    parent, XmNtopAttachment, XmATTACH_FORM,
			    XmNbottomAttachment, XmATTACH_FORM,
			    XmNleftAttachment, XmATTACH_POSITION,
			    XmNleftPosition, rpos + 3,
			    XmNlabelString, str,
			    NULL);
    XmStringFree(str);

    str = XmStringCreateSimple("Cancel");
    itm->auxWid2 = XtVaCreateWidget("CancelButton", xmPushButtonWidgetClass,
			    parent, XmNtopAttachment, XmATTACH_FORM,
			    XmNbottomAttachment, XmATTACH_FORM,
			    XmNleftAttachment, XmATTACH_WIDGET,
			    XmNleftWidget, itm->auxWid1,
			    XmNlabelString, str,
			    NULL);
    XmStringFree(str);

    if ( itm->activate )
    {
	XtAddCallback( itm->widget, XmNactivateCallback, itm->activate, itm );
	XtAddCallback( itm->auxWid1, XmNactivateCallback, itm->activate, itm );
    }

    XtAddCallback( itm->auxWid2, XmNactivateCallback, 
		   (XtCallbackProc)cancelTextField, itm);

    if ( itm->modify )
	XtAddCallback( itm->widget, XmNmodifyVerifyCallback, itm->modify, itm );

} /* textFieldCreate() */


/************************************************************************/
/* Function    : multHdrCreate						*/
/* Purpose     : Create header for multiple textField items		*/
/* Inputs      : Parent Widget ID, ibcItem ptr				*/
/* Outputs     : None							*/
/* Parameters  : itm->dm_nels = number of elements to create		*/
/*		 Stores ptr to array of ibcItem ptrs in itm->ptrparm	*/
/************************************************************************/
	Void
multHdrCreate( Widget parent, ibcItem *itm )
{
    multItem = itm;
    itm->ptrparm = XtCalloc( itm->dm_nels, sizeof(ibcItem *) );

} /* multHdrCreate() */


/************************************************************************/
/* Function    : multFieldCreate					*/
/* Purpose     : Create textField that's one of multiple items		*/
/* Inputs      : Parent Widget ID, ibcItem ptr				*/
/* Outputs     : None							*/
/* Parameters  : itm->parm1 = XmNmaxLength				*/
/*		 itm->parm2 = element number of controlling DM_Item	*/
/*		 Stores ibcItem ptr in the ptrparm array of prev multItem*/
/* Comments    : Depends on multHdrCreate being executed before this func*/
/*		 Passing info via this static sucks, but these damn arrays*/
/*		 of parameters in a single DM_Item suck too		*/
/************************************************************************/
	Void
multFieldCreate( Widget parent, ibcItem *itm, Int32 lpos, Int32 rpos )
{
    if ( (multItem == NULLI) || (multItem->ptrparm == NULL) )
	return;

    itm->ptrparm = multItem;
    *((ibcItem **)(multItem->ptrparm) + itm->parm2) = itm;
    textFieldCreate( parent, itm, lpos, rpos );

} /* multFieldCreate() */


/************************************************************************/
/* Function    : optionMenuCreate					*/
/* Purpose     : Create an Option Menu for modifying IBC information	*/
/* Inputs      : Parent Widget ID, ibcItem ptr, left & right positions	*/
/* Outputs     : None							*/
/* Parameters  : itm->parm1 = Number of Menu items			*/
/*		 itm->ptrparm = ptr to array of ibcMenuItems		*/
/************************************************************************/
	Void
optionMenuCreate( Widget parent, ibcItem *itm, Int32 lpos, Int32 rpos )
{
    Widget		w;
    Reg Nat32		i;
    Reg ibcMenuItem	*mp;
    Arg			args[10];

    if ( (mp = (ibcMenuItem *)rovMalloc(itm->parm1 * sizeof(ibcMenuItem))) 
			== (ibcMenuItem *)NULL )
    {
	itm->update = NULLF;
	itm->activate = NULLF;
	return;
    }

    bcopy( itm->ptrparm, (char *)mp, itm->parm1 * sizeof(ibcMenuItem) );
    itm->ptrparm = (XtPointer)mp;

    w = XmCreatePulldownMenu( parent, "pulldown", (ArgList)NULL, 0 );

    XtSetArg( args[0], XmNsubMenuId, w );
    itm->widget = XmCreateOptionMenu( parent, "optionMenu", args, 1 );

    XtVaSetValues( itm->widget, XmNtopAttachment, XmATTACH_FORM,
		  		XmNbottomAttachment, XmATTACH_FORM,
				XmNleftAttachment, XmATTACH_POSITION,
		  		XmNleftPosition, lpos, NULL );

    for ( i = 0; i < itm->parm1; i++, mp++ )
    {
	mp->widget = XtVaCreateManagedWidget(mp->label, 
					     xmPushButtonGadgetClass, w, NULL);
	if ( itm->activate )
	    XtAddCallback( mp->widget, XmNactivateCallback, 
			   itm->activate, itm );
    }

    XtManageChild( itm->widget );

} /* optionMenuCreate() */


/************************************************************************/
/* Function    : createIbcGroup						*/
/* Purpose     : Creation routine for creating  IBC			*/
/* Inputs      : Parent, Item Descriptor, Window width,			*/
/*		 Left and Right position of information widget		*/
/* Outputs     : RowColumn Widget					*/
/* Side Effect : Fills in isp->widget with RowColumn widget		*/
/************************************************************************/
	Widget
createIbcGroup( Widget parent, ibcItemSet *isp, Dimension width, 
	        Int32 lpos, Int32 rpos )
{
    Reg Nat32		i;
    Reg ibcItem		*ip;
    Widget		form, label, commonForm;
    XmString		str;

    isp->widget = XtVaCreateWidget("ibcGroupRowCol", xmRowColumnWidgetClass,
				   parent, NULL );

    commonForm = NULLW;

/* Create the Main IBC items	*/

    for ( i = 0, ip = isp->set_items; i < isp->set_nitems; i++, ip++ )
    {
	if ( ip->label != NULL )
	{
	    form = XtVaCreateManagedWidget("form", xmFormWidgetClass,
					   isp->widget, XmNwidth, width,
					   NULL);
	    str = XmStringCreateSimple(ip->label);
	    XtVaCreateManagedWidget("ibcItemLabel", xmLabelGadgetClass, form,
				    XmNtopAttachment, XmATTACH_FORM,
				    XmNbottomAttachment, XmATTACH_FORM,
				    XmNleftAttachment, XmATTACH_FORM,
				    XmNrightAttachment, XmATTACH_POSITION,
				    XmNrightPosition, lpos,
				    XmNlabelString, str,
				    NULL);
	    XmStringFree(str);
	    commonForm = NULLW;
	}
	else
	{
	    if ( commonForm == NULLW )
		commonForm = XtVaCreateManagedWidget("form", xmFormWidgetClass,
					 isp->widget, XmNwidth, width, NULL);
	    form = commonForm;
	}

	if ( ip->create )
	    (*ip->create)(form, ip, lpos, rpos);
    }

    return( isp->widget );

} /* createIbcGroup() */


/************************************************************************/
/* Function    : readIntItem						*/
/* Purpose     : Get the data for an Integer ibcItem			*/
/* Inputs      : DM_Item, DM_Type					*/
/* Outputs     : Data as Int32						*/
/************************************************************************/
	Int32
readIntItem( DM_Item dmitem, DM_Type dmtype )
{
    TypeUnion	udat;
    
    bzero( &udat, sizeof(udat) );
    rdm_read( dmitem, (char *)&udat, typeSizes[dmtype] );

    switch( dmtype )
    {
      case DM_CHAR:
      case DM_UCHAR:
	return( (Int32)udat.c );

      case DM_INT16:
      case DM_MBOOL:
	return( (Int32)udat.int16 );

      case DM_NAT16:
	return( (Nat32)udat.nat16 );
	    
      case DM_INT32:
      case DM_ENUM:
      case DM_NAT32:
      case DM_PTR:
	return( udat.nat32 );

      case DM_FLT32:
	return( (Int32)udat.flt32 );

      case DM_FLT64:
	return( (Int32)udat.flt64 );

      default:
	return( 0 );

    } /* switch */

} /* readIntItem() */


/************************************************************************/
/* Function    : writeIntItem						*/
/* Purpose     : Write data for an Integer ibcItem			*/
/* Inputs      : ibcItem pointer, data					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
writeIntItem( DM_Item dmitem, DM_Type dmtype, Nat32 dat )
{
    TypeUnion	udat;
    
    switch( dmtype )
    {
      case DM_CHAR:
      case DM_UCHAR:
	udat.c = dat;
	rdm_write_once( dmitem, (char *)&udat.c, sizeof(char) );
	return;

      case DM_INT16:
      case DM_MBOOL:
      case DM_NAT16:
	udat.nat16 = dat;
	rdm_write_once( dmitem, (char *)&udat.nat16, sizeof(Nat16) );
	return;
	    
      default:
	rdm_write_once( dmitem, (char *)&dat, sizeof(Nat32) );
	return;

    } /* switch */

} /* writeIntItem() */


/************************************************************************/
/* Function    : updateAsciiLabel					*/
/* Purpose     : Update a Label with ASCII data				*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
updateAsciiLabel( ibcItem *itm )
{
    rdm_read( itm->dmitem, ibcBuff, itm->dm_nels * sizeof(char) );

    ibcBuff[itm->dm_nels] = '\0';
    XmTextFieldSetString( itm->widget, ibcBuff );

} /* updateAsciiLabel() */


/************************************************************************/
/* Function    : updateIntLabel						*/
/* Purpose     : Update a Label with Integer data			*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
updateIntLabel( ibcItem *itm, MBool always )
{
    Reg Int32	new;
    
    new = readIntItem( itm->dmitem, itm->dmtype );

    if ( (new != itm->value) || always )
    {
	switch( itm->dmtype )
	{
	  case DM_NAT16:
	  case DM_NAT32:
	    sprintf( buff, "%u", new );
	    break;

	  default:
	    sprintf( buff, "%d", new );
	}
	XmTextFieldSetString( itm->widget, buff );
    }

    itm->value = new;

} /* updateIntLabel() */


/************************************************************************/
/* Function    : updateFltLabel						*/
/* Purpose     : Update a Label with Floating Point data		*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
updateFltLabel( ibcItem *itm )
{
    Flt32	val32;
    Flt64	val64;
    
    switch( itm->dmtype )
    {
      case DM_FLT64:
	rdm_read( itm->dmitem, (char *)&val64, sizeof(Flt64) );
	break;

      default:
	rdm_read( itm->dmitem, (char *)&val32, sizeof(Flt32) );
	val64 = (Flt64)val32;
	break;
    }

    if ( itm->parm1 < 0 )
	sprintf( buff, "%g", val64 );
    else
	sprintf( buff, "%.*f", itm->parm1, val64 );

    XmTextFieldSetString( itm->widget, buff );

} /* updateFltLabel() */


/************************************************************************/
/* Function    : updateEnumLabel					*/
/* Purpose     : Update a Label with Enumerated data			*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
updateEnumLabel( ibcItem *itm, MBool always )
{
    Reg Nat32	new;
    
    new = readIntItem( itm->dmitem, itm->dmtype );

    if ( ((new != itm->value) || always) && (itm->ptrparm != NULL) )
    {
	if ( new >= itm->parm1 )
	    new = itm->parm1 - 1;

	XmTextFieldSetString( itm->widget, *((char **)(itm->ptrparm) + new) );
    }

    itm->value = new;

} /* updateEnumLabel() */


/************************************************************************/
/* Function    : updateFixPtLabel					*/
/* Purpose     : Update a Label with Integer data displayed as fixed pt	*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
updateFixPtLabel( ibcItem *itm, MBool always )
{
    Reg Int32	new;
    Reg Flt32	val;

    new = readIntItem( itm->dmitem, itm->dmtype );

    if ( (new != itm->value) || always )
    {
	switch( itm->dmtype )
	{
	  case DM_NAT16:
	  case DM_NAT32:
	    val = (Flt32)((Nat32)new);
	    break;

	  default:
	    val = (Flt32)new;
	}

	val /= (Nat32)itm->parm2;
	sprintf( buff, "%.*f", itm->parm1, val );

	XmTextFieldSetString( itm->widget, buff );
    }

    itm->value = new;

} /* updateFixPtLabel() */


/************************************************************************/
/* Function    : updateGfLabel						*/
/* Purpose     : Update Ground Fault Current Label			*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/* Side Effects: Turns background of all GF currents to normal background*/
/*		 Turns background of *this* item to emphasis color	*/
/************************************************************************/
	Void
updateGfLabel( ibcItem *itm, MBool always )
{
    Reg Nat32	i;

    updateIntLabel( itm, always );

    if ( !always )
	for ( i = 0; i < NUM_GF_CURRENTS; i++ )
	    if ( i == itm->parm1 )
		XtVaSetValues( itm->widget, XmNbackground,
			       appdata.gf_current_bg, NULL );
	    else
		XtVaSetValues( ((Widget *)(itm->ptrparm))[i], XmNbackground,
			       gfCurrentColor, NULL );


} /* updateGfLabel() */


/************************************************************************/
/* Function    : updateAsciiTextField					*/
/* Purpose     : Update a TextField with ASCII data			*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
updateAsciiTextField( ibcItem *itm )
{
    textFUpdate = TRUE;
    rdm_read( itm->dmitem, buff, itm->dm_nels * sizeof(char) );
    buff[itm->dm_nels] = '\0';
    XmTextFieldSetString( itm->widget, buff );
    textFUpdate = FALSE;

    if ( XtIsManaged(itm->auxWid1) )
    {
	XtUnmanageChild( itm->auxWid1 );
	XtUnmanageChild( itm->auxWid2 );
    }

} /* updateAsciiTextField() */


/************************************************************************/
/* Function    : updateNumTextField					*/
/* Purpose     : Update a TextField with Numeric (int or float) data	*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
updateNumTextField( ibcItem *itm )
{
    textFUpdate = TRUE;
    rdm_read( itm->dmitem, ibcBuff, typeSizes[itm->dmtype] );
    printType( itm->dmtype, 1, ibcBuff, buff );
    XmTextFieldSetString( itm->widget, buff );
    textFUpdate = FALSE;

    if ( XtIsManaged(itm->auxWid1) )
    {
	XtUnmanageChild( itm->auxWid1 );
	XtUnmanageChild( itm->auxWid2 );
    }

} /* updateNumTextField() */


/************************************************************************/
/* Function    : updateMultIntTextField					*/
/* Purpose     : Update a Set of TextFields with Integer data		*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
updateMultIntTextField( ibcItem *itm )
{
    Reg ibcItem		*ip;
    Reg Int32		i, n;

    textFUpdate = TRUE;
    n = typeSizes[itm->dmtype];
    rdm_read( itm->dmitem, ibcBuff, itm->dm_nels * n );

    for ( i = 0; i < itm->dm_nels; i++ )
    {
	ip = *((ibcItem **)(itm->ptrparm) + i);
	printType( itm->dmtype, 1, ibcBuff + (ip->parm2 * n), buff );
	XmTextFieldSetString( ip->widget, buff );

	if ( XtIsManaged(ip->auxWid1) )
	{
	    XtUnmanageChild( ip->auxWid1 );
	    XtUnmanageChild( ip->auxWid2 );
	}
    }

    textFUpdate = FALSE;

} /* updateMultIntTextField() */


/************************************************************************/
/* Function    : updateFixPtTextField					*/
/* Purpose     : Update a TextField with Integer data displayed as fixed pt*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
updateFixPtTextField( ibcItem *itm )
{
    Reg Int32	new;
    Reg Flt32	val;

    textFUpdate = TRUE;
    new = readIntItem( itm->dmitem, itm->dmtype );

    switch( itm->dmtype )
    {
      case DM_NAT16:
      case DM_NAT32:
	val = (Flt32)((Nat32)new);
	break;

      default:
	val = (Flt32)new;
    }

    if ( itm->ptrparm != NULL)
	val /= (Nat32)itm->ptrparm;
    sprintf( buff, "%.*f", itm->parm2, val );
    XmTextFieldSetString( itm->widget, buff );
    itm->value = new;
    textFUpdate = FALSE;

    if ( XtIsManaged(itm->auxWid1) )
    {
	XtUnmanageChild( itm->auxWid1 );
	XtUnmanageChild( itm->auxWid2 );
    }

} /* updateFixPtTextField() */


/************************************************************************/
/* Function    : updateMotorToggleButton				*/
/* Purpose     : Update the state of a Motor Enable ToggleButton	*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
updateMotorToggleButton( ibcItem *itm, MBool always )
{
    motorEnableState	dmstate;

    rdm_read( itm->dmitem, (char *)&dmstate, sizeof(motorEnableState) );

    if ( (dmstate != itm->value) || always )
	switch( dmstate )
	{
	  case DISABLE_MOTOR:
	    XtVaSetValues( itm->widget, XcNonColor, ibcToggleOnColor,
			   XcNstate, XcOff, NULL );
	    break;

	  case ENABLE_MOTOR:
	    XtVaSetValues( itm->widget, XcNonColor, ibcToggleOnColor,
			   XcNstate, XcOn, NULL );
	    break;

	  default:
	    XtVaSetValues( itm->widget, XcNonColor, appdata.pwrerr_bg,
			   XcNstate, XcOn, NULL );
	    break;
	}

    itm->value = dmstate;

} /* updateMotorToggleButton() */


/************************************************************************/
/* Function    : updateMBoolToggleButton				*/
/* Purpose     : Update the state of a Boolean ToggleButton		*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
updateMBoolToggleButton( ibcItem *itm, MBool always )
{
    MBool	dmstate;

    rdm_read( itm->dmitem, (char *)&dmstate, sizeof(dmstate) );

    if ( (dmstate != itm->value) || always )
	XtVaSetValues( itm->widget, XcNstate, (dmstate ? XcOn : XcOff), NULL );

    itm->value = dmstate;

} /* updateMBoolToggleButton() */


/************************************************************************/
/* Function    : updateOptionMenu					*/
/* Purpose     : Update the state of an Option Menu			*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
updateOptionMenu( ibcItem *itm, MBool always )
{
    Nat32		new;
    Reg ibcMenuItem	*mp;
    Reg Nat32		i;

    new = readIntItem( itm->dmitem, itm->dmtype );

    if ( (new != itm->value) || always )
    {
	mp = (ibcMenuItem *)itm->ptrparm;
	for ( i = 0; i < itm->parm1; i++, mp++ )
	    if ( new == mp->value )
	    {
		XtVaSetValues( itm->widget, XmNmenuHistory, mp->widget, NULL );
		break;
	    }
    }

    itm->value = new;

} /* updateOptionMenu() */


/************************************************************************/
/* Function    : findIbcBoard						*/
/* Purpose     : Find the ibcBoardName for a given IBC Board address	*/
/* Inputs      : Word address						*/
/* Outputs     : ibcBoardName ptr					*/
/************************************************************************/
	ibcBoardName *
findIbcBoard( Word baddr )
{
    Reg Nat32		i;
    Reg ibcBoardName	*bnp;

    for ( i = 0, bnp = ibcBdNames; i < XtNumber(ibcBdNames); i++, bnp++ )
	if ( (baddr & ~bnp->boardMask) == bnp->boardAddr )
	    return( bnp );

    return( (ibcBoardName *)NULL );

} /* findIbcBoard() */


/************************************************************************/
/* Function    : updateIbcBoards					*/
/* Purpose     : Update a Label with ASCII data				*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
updateIbcBoards( ibcItem *itm )
{
    ibcBoard		bdData;
    Reg ibcBoardName	*bnp;
    Reg Nat32		i, n;
    Reg Word		baddr;
    XmString		str;

    rdm_read( itm->dmitem, (char *)&bdData, sizeof(ibcBoard) );

    for ( i = n = 0; i < bdData.numCards; i++ )
    {
	if ( i > 0 )
	{
	    if ( (i % IBC_BOARDS_PER_LINE) == 0 )
		n += sprintf( buff + n, "\n" );
	    else
		n += sprintf( buff + n, ",  " );
	}

	baddr = bdData.boardAddr[i];

	if ( (bnp = findIbcBoard(baddr)) == (ibcBoardName *)NULL )
	    n += sprintf( buff + n, "Unknown" );
	else
	    n += sprintf( buff + n, "%s %d", bnp->boardName,
			  (baddr - bnp->boardAddr) / bnp->boardRange );
    }

    str = XmStringCreateLtoR( buff, XmSTRING_DEFAULT_CHARSET );
    XtVaSetValues( itm->widget, XmNlabelString, str, NULL );
    XmStringFree( str );

} /* updateIbcBoards() */


/************************************************************************/
/* Function    : modifyTextField					*/
/* Purpose     : Callback for when ANY TextField is modified		*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
modifyTextField( Widget w, ibcItem *itm, XmTextVerifyCallbackStruct *tvp )
{
    Int32	len;

    if ( tvp->text->ptr == NULL )
	return;

    for ( len = 0; len < tvp->text->length; len++ )
	if ( !isprint(tvp->text->ptr[len]) )
	    tvp->doit = False;

    if ( !textFUpdate && tvp->doit && (!XtIsManaged(itm->auxWid1)) )
    {
	XtManageChild( itm->auxWid1 );
	XtManageChild( itm->auxWid2 );
    }

} /* modifyTextField() */


/************************************************************************/
/* Function    : modifyIntTextField					*/
/* Purpose     : Callback for when Integer TextField is modified	*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
modifyIntTextField( Widget w, ibcItem *itm, 
		    XmTextVerifyCallbackStruct *tvp )
{
    Int32	len;
    int		c;

    if ( tvp->text->ptr == NULL )
	return;

    for ( len = 0; len < tvp->text->length; len++ )
    {
	c = tvp->text->ptr[len];
	if ( !isdigit(c) && (c != '.') &&
	     ((c != '-') || (tvp->currInsert != 0) || (len != 0)) )
	    tvp->doit = False;
    }

    if ( !textFUpdate && tvp->doit && (!XtIsManaged(itm->auxWid1)) )
    {
	XtManageChild( itm->auxWid1 );
	XtManageChild( itm->auxWid2 );
    }

} /* modifyIntTextField() */


/************************************************************************/
/* Function    : ibcWriteEvent						*/
/* Purpose     : Callback for Dialog confirmation of Reset and NVRAM Buttons*/
/* Inputs      : Widget, client_data, call_data				*/
/* Outputs     : None							*/
/************************************************************************/
	Void
ibcWriteEvent( Widget w, ibcItem *itm, XmAnyCallbackStruct *cbp )
{
    rdm_write_once( itm->dmitem, buff, 0 );

} /* ibcWriteEvent() */


/************************************************************************/
/* Function    : activateButton						*/
/* Purpose     : Callback for Reset and NVRAM PushButtons		*/
/* Inputs      : Widget, client_data, call_data				*/
/* Outputs     : None							*/
/************************************************************************/
	Void
activateButton( Widget w, ibcItem *itm, XmAnyCallbackStruct *cbp )
{
    XmString	str;

    str = XmStringCreateLtoR( *((char **)(itm->ptrparm) + 1),
			      XmSTRING_DEFAULT_CHARSET ); 
    XtVaSetValues( ibcDialog, XmNmessageString, str, 
		   XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON, NULL );
    XmStringFree( str );

    XtRemoveAllCallbacks( ibcDialog, XmNokCallback );

    XtAddCallback( ibcDialog, XmNokCallback, 
		   (XtCallbackProc)ibcWriteEvent, itm );

    XtManageChild( ibcDialog );

} /* activateButton() */


/************************************************************************/
/* Function    : activateMotorToggleButton				*/
/* Purpose     : Activate callback for Motor Enable ToggleButton	*/
/* Inputs      : Widget, item pointer, call_data			*/
/* Outputs     : None							*/
/************************************************************************/
	Void
activateMotorToggleButton( Widget w, ibcItem *itm, XmAnyCallbackStruct *cbp )
{
    XcToggleState	state;
    motorEnableState	dmstate;
    DM_Item		reqItem;

    XcToggleGet( w, &state );
    dmstate = (state == XcOn) ? ENABLE_MOTOR : DISABLE_MOTOR;

    sprintf( buff, "%s%s", ibcSts.current->ptr1, MOTOR_ENABLE_REQ_DM );

    if ( (reqItem = rdm_lookup(buff, 0)) != NO_ITEM )
	rdm_write_once( reqItem, (char *)&dmstate, sizeof(motorEnableState) );

    updateMotorToggleButton( itm, TRUE );

} /* activateMotorToggleButton() */


/************************************************************************/
/* Function    : activateMBoolToggleButton				*/
/* Purpose     : Activate callback for Boolean ToggleButton		*/
/* Inputs      : Widget, item pointer, call_data			*/
/* Outputs     : None							*/
/************************************************************************/
	Void
activateMBoolToggleButton( Widget w, ibcItem *itm, XmAnyCallbackStruct *cbp )
{
    XcToggleState	state;
    MBool		dmstate;

    XcToggleGet( w, &state );
    dmstate = (state == XcOn) ? TRUE : FALSE;

    rdm_write_once( itm->dmitem, (char *)&dmstate, sizeof(dmstate) );

} /* activateMBoolToggleButton() */


/************************************************************************/
/* Function    : acceptTextField					*/
/* Purpose     : Callback for "OK" pushbutton or <RETURN> in TextField	*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
acceptTextField( Widget w, ibcItem *itm, XmAnyCallbackStruct *cbp )
{
    char	*p;

    p = XmTextFieldGetString( itm->widget );
    rdm_write_once( itm->dmitem, p, itm->dm_nels * sizeof(char) );
    XtFree( p );
    cancelTextField( w, itm, cbp );

} /* acceptTextField() */


/************************************************************************/
/* Function    : acceptIntTextField					*/
/* Purpose     : Callback for "OK" pushbutton or <RETURN> in TextField	*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
acceptIntTextField( Widget w, ibcItem *itm, XmAnyCallbackStruct *cbp )
{
    char	*p;
    Int32	i, j;

    p = XmTextFieldGetString( itm->widget );
    j = sscanf( p, "%d", &i );
    XtFree( p );

    if ( j == 1 )
    {
	writeIntItem( itm->dmitem, itm->dmtype, i );
	cancelTextField( w, itm, cbp );
    }
    else if ( appdata.ring_bell )
	XBell( XtDisplay(w), 100 );

} /* acceptIntTextField() */


/************************************************************************/
/* Function    : acceptFlt32TextField					*/
/* Purpose     : Callback for "OK" pushbutton or <RETURN> in TextField	*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
acceptFlt32TextField( Widget w, ibcItem *itm, XmAnyCallbackStruct *cbp )
{
    Reg char	*p;
    Reg Int32	conversions;
    Flt32	val32;

    p = XmTextFieldGetString( itm->widget );
    conversions = sscanf( p, "%g", &val32 );
    XtFree( p );

    if ( conversions == 1 )
    {
	rdm_write_once( itm->dmitem, (char *)&val32, sizeof(Flt32) );
	cancelTextField( w, itm, cbp );
    }
    else if ( appdata.ring_bell )
	XBell( XtDisplay(w), 100 );

} /* acceptFlt32TextField() */


/************************************************************************/
/* Function    : acceptFixPtTextField					*/
/* Purpose     : Callback for "OK" pushbutton or <RETURN> in TextField	*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
acceptFixPtTextField( Widget w, ibcItem *itm, XmAnyCallbackStruct *cbp )
{
    char	*p;
    Int32	j;
    Flt32	val;

    p = XmTextFieldGetString( itm->widget );
    j = sscanf( p, "%f", &val );
    XtFree( p );

    if ( j == 1 )
    {
	val *= (Flt32)((Nat32)itm->ptrparm);
	writeIntItem( itm->dmitem, itm->dmtype, (Nat32)val );
	cancelTextField( w, itm, cbp );
    }
    else if ( appdata.ring_bell )
	XBell( XtDisplay(w), 100 );

} /* acceptFixPtTextField() */


/************************************************************************/
/* Function    : acceptMultInt16TextField				*/
/* Purpose     : Callback for "OK" pushbutton or <RETURN> in TextField	*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
acceptMultInt16TextField( Widget w, ibcItem *itm, XmAnyCallbackStruct *cbp )
{
    Reg ibcItem	*ip;
    Reg char	*p;
    Int32	i, j;

    p = XmTextFieldGetString( itm->widget );
    j = sscanf( p, "%d", &i );
    XtFree( p );
    if ( (ip = (ibcItem *)(itm->ptrparm)) == NULLI )
	return;

    if ( (j == 1) && (i <= USHRT_MAX) && (i > SHRT_MIN) )
    {
	rdm_read( ip->dmitem, buff, ip->dm_nels * sizeof(Int16) );
	*((Int16 *)buff + itm->parm2) = (Int16)i;
	rdm_write_once( ip->dmitem, buff, ip->dm_nels * sizeof(Int16) );
	cancelTextField( w, itm, cbp );
    }
    else if ( appdata.ring_bell )
	XBell( XtDisplay(w), 100 );

} /* acceptMultInt16TextField() */


/************************************************************************/
/* Function    : activateOptionMenu					*/
/* Purpose     : Callback for Option Menu PushButton			*/
/* Inputs      : ibcItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
activateOptionMenu( Widget w, ibcItem *itm, XmAnyCallbackStruct *cbp )
{
    Reg Nat32		i;
    ibcMenuItem		*mp;

    for ( i = 0, mp = (ibcMenuItem *)itm->ptrparm; i < itm->parm1; i++, mp++ )
	if ( mp->widget == w )
	    writeIntItem( itm->dmitem, itm->dmtype, mp->value );

} /* activateOptionMenu() */


/************************************************************************/
/* Function    : ibcTimeoutProc						*/
/* Purpose     : Routine called to periodically update IBC screen	*/
/* Inputs      : IBC Item Descriptor pointer				*/
/* Outputs     : None							*/
/* Comment     : Typically called at 2 Hz.  Be quick!			*/
/************************************************************************/
	Void
ibcTimeoutProc( ibcItemDesc *idp, XtIntervalId *id )
{
    Reg Nat32		i, j;
    Reg ibcItemSet	*isp;
    Reg ibcItem		*ip;
    grp_set		changes;

    for ( i = 0; i < IBC_NGROUPS; i++ )
	changes.grp_bits[i] = (idp->grpId[i] == NO_GROUP) ? 0 :
				rdm_get_group_changes( idp->grpId[i] );

    for ( i = 0; i < IBC_NSETS; i++ )
	if ( (isp = idp->ibcSets[i]) != NULLIS )
	    for ( j = 0, ip = isp->set_items; j < isp->set_nitems; j++, ip++ )
	    {
		if ( (ip->grpBit >= 0) && GRP_ISSET(ip->grpBit, &changes) 
				&& ip->dmitem && ip->update )
		    (*ip->update)(ip, FALSE);
	    }

    idp->timeoutId = XtAppAddTimeOut(appcontext, *idp->timeout,
				     (XtTimerCallbackProc)ibcTimeoutProc, idp);

} /* ibcTimeoutProc() */


/************************************************************************/
/* Function    : getGroupBit						*/
/* Purpose     : Add an item to an array of DM_Groups, return bit number*/
/* Inputs      : Ptr to array of groups, index into array, DM_Item	*/
/* Outputs     : Group bit number, -1 if failed				*/
/************************************************************************/
     Int32
getGroupBit( DM_Group *grp, Nat32 *gindex, DM_Item item )
{
    DWord	gbit;
    Reg Nat32	i;

    while ( *gindex < IBC_NGROUPS )
    {
	switch ( rdm_group_add_item(grp[*gindex], item, &gbit) )
	{
	  case SUCCESS:
	    for ( i = 0; i < NGRPBITS; i++ )
		if ( gbit & (1 << i) )
		    return( *gindex * NGRPBITS + i );
	    return( -1 );

	  case EDM_GROUP_SIZE:
	    (*gindex)++;
	    break;

	  default:
	    return( -1 );
	}
    }

    return( -1 );

} /* getGroupBit() */


/************************************************************************/
/* Function    : ibcStartTimeout					*/
/* Purpose     : Start Timeout for IBC items				*/
/* Inputs      : ibcItemDesc ptr, Prefix for DM Item names		*/
/* Outputs     : None							*/
/************************************************************************/
    Void
ibcStartTimeout( Reg ibcItemDesc *idp, char *dmprefix )
{
    Reg ibcItemSet	*isp;
    Reg ibcItem		*ip;
    Reg Nat32		i, j, period;
    Nat32		grpnum;

    for ( i = 0; i < IBC_NGROUPS; i++ )
	idp->grpId[i] = rdm_create_group( dmprefix );

    grpnum = 0;

    for ( i = 0; i < IBC_NSETS; i++ )
	if ( (isp = idp->ibcSets[i]) != NULLIS )
	    for ( j = 0, ip = isp->set_items; j < isp->set_nitems; j++, ip++ )
	    {
		if ( ip->dmname != NULL )
		{
		    sprintf(ibcBuff, "%s%s", dmprefix, ip->dmname);
		    ip->dmitem = rdm_lookup( ibcBuff, 0 );
		}
		else
		    ip->dmitem = NO_ITEM;

		ip->grpBit = -1;
		period = 1000 * *idp->timeout;

		if ( ip->dmitem != NO_ITEM )
		{
		    if ( ip->upFlags & UP_CONSUME )
			rdm_start_consumer( ip->dmitem, period, NULL );
	
		    if ( (ip->upFlags & UP_CONSUME) || 
			(ip->upFlags & UP_ALREADY_CONSUME) )
			ip->grpBit = getGroupBit( idp->grpId, &grpnum,
						  ip->dmitem );
		}

		if ( ip->update )
		    (*ip->update)(ip, TRUE);
	    }

    idp->timeoutId = XtAppAddTimeOut(appcontext, *idp->timeout,
				     (XtTimerCallbackProc)ibcTimeoutProc, idp);

} /* ibcStartTimeout() */


/************************************************************************/
/* Function    : ibcStopTimeout						*/
/* Purpose     : Stop Timeout for IBC items				*/
/* Inputs      : ibcItemDesc ptr					*/
/* Outputs     : None							*/
/************************************************************************/
    Void
ibcStopTimeout( ibcItemDesc *idp )
{
    Reg Nat32		i, j;
    Reg ibcItemSet	*isp;
    Reg ibcItem		*ip;

    XtRemoveTimeOut( idp->timeoutId );

    for ( i = 0; i < IBC_NSETS; i++ )
	if ( (isp = idp->ibcSets[i]) != NULLIS )
	    for ( j = 0, ip = isp->set_items; j < isp->set_nitems; j++, ip++ )
	    {
		if ( (ip->upFlags & UP_CONSUME) && (ip->dmitem != NO_ITEM)
		     && !graphItemInUse(ip->dmitem) )
		    rdm_stop_consumer( ip->dmitem );
	    }

    for ( i = 0; i < IBC_NGROUPS; i++ )
	rdm_delete_group( idp->grpId[i] );

} /* ibcStopTimeout() */


/************************************************************************/
/* Function    : ibcSelect						*/
/* Purpose     : Callback to select a specific IBC			*/
/* Inputs      : Select Ptr						*/
/* Outputs     : None							*/
/************************************************************************/
    Void
ibcSelect( Select *sp )
{
    Reg ibcItemDesc	*idp;
    Reg ibcItemSet	*isp;
    Reg Nat32		i;

    idp = (ibcItemDesc *)(sp->ptr2);

    if ( idp != currentIbcItemDesc )
    {
	XtUnmanageChild( ibcRowColumn );

	for ( i = 0; i < IBC_NSETS; i++ )
	    if ( (isp = currentIbcItemDesc->ibcSets[i]) != NULLIS )
		XtUnmanageChild( isp->widget );

	for ( i = 0; i < IBC_NSETS; i++ )
	    if ( (isp = idp->ibcSets[i]) != NULLIS )
		XtManageChild( isp->widget );

	XtManageChild( ibcRowColumn );

	currentIbcItemDesc = idp;
    }

    ibcStartTimeout( idp, sp->ptr1 );

} /* ibcSelect() */


/************************************************************************/
/* Function    : ibcUnselect						*/
/* Purpose     : Callback to de-select a specific IBC			*/
/* Inputs      : Select Ptr						*/
/* Outputs     : None							*/
/* Comment     : Just remember ibcItemDesc in global variable, and	*/
/*		 unselect it in ibcSelect only if different		*/
/************************************************************************/
    Void
ibcUnselect( Select *sp )
{
    Reg ibcItemDesc	*idp;
    Reg ibcItemSet	*isp;
    Reg Nat32		i;

    idp = (ibcItemDesc *)(sp->ptr2);

    ibcStopTimeout( idp );

    if ( XtIsManaged(ibcDialog) )
	XtUnmanageChild( ibcDialog );

} /* ibcUnselect() */


/************************************************************************/
/* Function    : createIbcItems						*/
/* Purpose     : Create DM items described by ibcItemDesc		*/
/* Inputs      : ibcItemDesc ptr, Prefix for DM Item names		*/
/* Outputs     : None							*/
/************************************************************************/
    Void
createIbcItems( Reg ibcItemDesc *idp, char *dmprefix )
{
    Reg Nat32		i, j;
    Reg ibcItemSet	*isp;
    Reg ibcItem		*ip;
    Reg DM_Define	*dmDefineP;

    for ( i = 0; i < IBC_NSETS; i++ )
	if ( (isp = idp->ibcSets[i]) != NULLIS )
	    for ( j = 0, ip = isp->set_items; j < isp->set_nitems; j++, ip++ )
	    {
		if ( ip->dmname != NULL )
		{
		    sprintf(ibcBuff, "%s%s", dmprefix, ip->dmname);
		    if ( ip->dmtype < DM_COMPOUND )
			rdm_create( ibcBuff, 1, &ip->dmitem, ip->dmtype,
				    ip->dm_nels );
		    else
		    {
			dmDefineP = (DM_Define *)(ip->ptrparm);
			dmDefineP->itm_name = ibcBuff;
			rdm_create_items( dmDefineP );
		    }
		}
	    }

} /* createIbcItems() */


/************************************************************************/
/* Function    : copyIbcItemDesc					*/
/* Purpose     : Copy an ibcItemDesc, including all items and sets	*/
/* Inputs      : ibcItemDesc ptr					*/
/* Outputs     : Ptr to new ibcItemDesc					*/
/************************************************************************/
    ibcItemDesc *
copyIbcItemDesc( Reg ibcItemDesc *idp )
{
    Reg Nat32		i, nsets, nitems;
    Reg ibcItemSet	*isp, *newisp;
    Reg ibcItemDesc	*newidp;
    Reg ibcItem		*newip;

/* Count number of items and sets	*/

    for ( i = nsets = nitems = 0; i < IBC_NSETS; i++ )
	if ( (isp = idp->ibcSets[i]) != NULLIS )
	{
	    nsets++;
	    nitems += isp->set_nitems;
	}

/* Malloc space for the items and sets	*/

    newidp = (ibcItemDesc *)XtCalloc( 1, sizeof(ibcItemDesc) + 
				      (nsets * sizeof(ibcItemSet)) +
				      (nitems * sizeof(ibcItem)) );

    if ( newidp == NULLID )
	return( NULLID );

/* Copy old items and sets to new struct */

    bcopy( (char *)idp, (char *)newidp, sizeof(ibcItemDesc) );
    newisp = (ibcItemSet *)(newidp + 1);
    newip  = (ibcItem *)(newisp + nsets);

    for ( i = 0; i < IBC_NSETS; i++ )
	if ( (isp = idp->ibcSets[i]) != NULLIS )
	{
	    newidp->ibcSets[i] = newisp;
	    newisp->set_items = newip;
	    bcopy( (char *)(isp->set_items), newip,
		   isp->set_nitems * sizeof(ibcItem) );
	    newisp->set_nitems = isp->set_nitems;
	    newisp->widget = NULLW;
	    newisp++;
	    newip += isp->set_nitems;
	}
	else
	    newidp->ibcSets[i] = NULLIS;

    return( newidp );

} /* copyIbcItemDesc() */


/************************************************************************/
/* Function    : initIbc						*/
/* Purpose     : Initialize function for IBC screen			*/
/* Inputs      : None							*/
/* Outputs     : None							*/
/************************************************************************/
    Void
initIbc( Void )
{
    Reg Nat32		i;
    Reg Select		*sp;
    Reg ibcItemSet	*isp;

    /* Create all DM Items for all Item Descriptors	*/

    for ( i = 0; (sp = ibcSelects[i]) != (Select *)NULL; i++ )
	createIbcItems( (ibcItemDesc *)sp->ptr2, sp->ptr1 );


    /* Create all widgets for all IBC sets		*/

    for ( i = 0; (isp = ibcSets[i]) != NULLIS; i++ )
	createIbcGroup( ibcRowColumn, isp, IBC_WIDTH, 
		        INFO_LEFT_POS, INFO_RT_POS );

    /* Manage the container widgets for the first Descriptor	*/

    currentIbcItemDesc = ibcDescs[0];

    for ( i = 0; i < IBC_NSETS; i++ )
	if ( (isp = currentIbcItemDesc->ibcSets[i]) != NULLIS )
	    XtManageChild( isp->widget );

} /* initIbc() */
