/******************************************************************************/
/* Copyright 1995 MBARI                                                       */
/******************************************************************************/
/* Summary  : Power Management Module for Tiburon                             */
/* Filename : power.c                                                         */
/* Author   : Janice Tarrant                                                  */
/* Project  : Tiburon                                                         */
/* Version  : Version 2.0                                                     */
/* Created  : 10/04/95                                                        */
/* Modified : 03/14/96                                                        */
/* Archived :                                                                 */
/******************************************************************************/
/* Modification History :                                                     */
/* $Header$
 * $Log$
 *
 */
/******************************************************************************/

#include <vxWorks.h>		/* VxWorks system declarations                */
#include <stdioLib.h>		/* VxWorks standard I/O library               */
#include <ioLib.h>		/* VxWorks I/O interface library              */
#include <math.h>		/* VxWorks floating point math library        */
#include <semLib.h>		/* VxWorks semaphore library                  */
#include <systime.h>		/* VxWorks system time declarations           */
#include <mbariTypes.h>	        /* MBARI style guide type declarations        */
#include <datamgr.h>          	/* data manager declarations                  */
#include <dm_errno.h>		/* data manager error number declarations     */
#include <thrusterDM.h>         /* thruster motor controller definitions      */

#include <powerTypes.h>	        /* Power Manager data type definitions        */
#include <powerDM.h>	        /* Power Manager data manager definitions     */
#include <powerAlloc.h>	        /* Power Manager power allocation             */
#include "power.h"		/* Power Manager Application definitions      */

                                        /* function prototypes                */
#if __STDC__
LOCAL Errno powerDMInit(powerDMItems *powerDmi, SEM_ID powerReqSem,
	                SEM_ID thrustersPwrConfSem[],
			powerDMGroups *powerGroups,
                        char staticPrwReq[NUM_STATIC_POWER][DM_ITEM_NAME_LEN]);
LOCAL void  setThrustersNames(FILE *fpw, MBool verifyFileOpen, char *tmpString2,
		              Int16 keyWordStart, powerDMNames *powerNames);
LOCAL void  setStaticPowerNames(FILE *fpw, MBool verifyFileOpen,
				char *tmpString2, Int16 keyWordStart,
				Int16 *numStaticPowerItems,
		                powerDMNames *powerNames);
LOCAL void  setSwitchedPowerNames(FILE *fpw, MBool verifyFileOpen,
				char *tmpString2, Int16 keyWordStart,
				Int16 *numSwitchPowerItems,
		                powerDMNames *powerNames);
LOCAL Errno powerConsumersGroup(powerDMItems *powerDmi,
				powerDMNames *powerNames, SEM_ID powerReqSem,
				SEM_ID thrustersPwrConfSem[],
		                powerDMGroups *powerGroups);
LOCAL Errno powerProviders(powerDMItems *powerDmi, powerDMNames *powerNames);
LOCAL Nat16 maxPower(DM_Item dmiMaxPwrAvail, DM_Item dmiThrustersPwr,
	              switchDivisions *divisions);
LOCAL void  powerStatic(DM_Item dmiPwrReq, DM_Item dmiPwrOk, Nat16 *pwrAlloc,
                        Nat16 *pwrAvail, switchDivisions *divisions,
                        char *loadName);
LOCAL void  powerThrusters(DM_Item dmiPwrReq, DM_Item dmiPwrAlloc,
                           DM_Item dmiPwrOk, Nat16 *pwrAlloc, Nat16 *pwrAvail);
LOCAL void  powerSwitch(DM_Item dmiPwrReq, DM_Item dmiPwrOk, Nat16 *pwrAlloc,
                        Nat16 *pwrAvail, switchDivisions *divisions,
                        thrustersVars *thrusters);
#endif

/******************************************************************************/
/* Function : powerTask                                                       */
/* Purpose  : Manages power allocation requests from the various vehicle      */
/*            subsystems and devices, and the thruster control system.        */
/* Inputs   : None.                                                           */
/* Outputs  : Returns ERROR on fatal error.                                   */
/******************************************************************************/
    STATUS
powerTask(Void)
{
    powerDMItems    powerDmi;		/* power data manager item handles    */
    powerDMGroups   powerGroups;	/* power data manager item groups     */
    Errno           status;		/* error code                         */
    SEM_ID          powerReqSem;  	/* power task wakeup semaphore        */
    DWord           genericGroupBits;	/* generic group changes bit vector   */
    DWord           thrustersGroupBits;	/* thrusters group changes bit vector */
    DWord           staticGroupBits;	/* static group changes bit vector    */
					/* switched group changes bit vectors */
    DWord           switchGroupBits[NUM_POWER_GROUPS];
    switchDivisions divisions;		/* switch load divisions power        */
    thrustersVars   thrusters;		/* thrusters power variables          */
					/* static power request item names    */
    char            staticPwrReq[NUM_STATIC_POWER][DM_ITEM_NAME_LEN];
    Nat16           powerAvailable =    /* power available for allocation     */
                    MAX_POWER;
					/* static items power allocated       */
    Nat16           staticPwrAlloc[NUM_STATIC_POWER];
					/* switched items power allocated     */
    Nat16           switchPwrAlloc[NUM_SWITCH_POWER];
    thrusterId      thruster;		/* thruster counter                   */
    Int16           item, numItems;	/* item counters                      */
    Int16           group, numGroups;	/* group counters                     */
					/* data manager items for debugging   */
					/* purposes only                      */
    DM_Time         sampleTime;		/* power update sample time           */
    Int32           numSemTake = 0;	/* number of sem takes                */
    Int32           numThrustReq = 0;	/* number of thruster power requests  */
    Int32           numSwitchReq = 0;	/* number of switched power requests  */
    Int32           numReq = 0;		/* number of requests serviced        */


/* initialize task wakeup semaphore                                           */
    if ((powerReqSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == NULL)
    {
	logMsg("Power Manager FAILURE : could not initialize wakeup semaphore\n");
	return(ERROR);
    }

/* create thrusters power confirmed semaphores                                */
    for (thruster = PORT_HORIZ; thruster <= STBD_VERT; thruster++)
        if ((thrusters.pwrConfSem[thruster] =
	     semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == NULL)
        {
	    logMsg("Power Manager FAILURE : could not create thruster confirmation semaphore\n");
	    return(ERROR);
        }

/* create data manager items, start consumers and providers and set up groups */
    if (powerDMInit(&powerDmi, powerReqSem, thrusters.pwrConfSem, &powerGroups,
		    staticPwrReq)
	== ERROR)
	return(ERROR);

/* initialize static and switchable power allocated                           */
    for (item = 0; item < powerDmi.numStatic; item++)
	staticPwrAlloc[item] = 0;
    for (item = 0; item < powerDmi.numSwitch; item++)
	switchPwrAlloc[item] = 0;

/* initialize switch load divisions cumulative power                          */
    divisions.dmiHotelPwr = powerDmi.hotelPwrAlloc;
    divisions.dmiLightsPwr = powerDmi.lightsPwrAlloc;
    divisions.dmiToolsPwr = powerDmi.toolsPwrAlloc;
    divisions.hotelPwrAlloc = 0;
    divisions.lightsPwrAlloc = 0;
    divisions.toolsPwrAlloc = 0;

/* initialize thrusters power variables                                       */
    thrusters.pwrAlloc = 0;
    thrusters.dmiPwrReq = powerDmi.thrustersPwrReq;
    thrusters.dmiPwrAlloc = powerDmi.thrustersPwrAlloc;
    thrusters.dmiPwrOk = powerDmi.thrustersPwrOk;
    thrusters.dmiPwrRed = powerDmi.thrustersPwrRed;
    thrusters.dmiMtrEnb[0] = powerDmi.thrusterPortHorizMtrEnb;
    thrusters.dmiMtrEnb[1] = powerDmi.thrusterStbdHorizMtrEnb;
    thrusters.dmiMtrEnb[2] = powerDmi.thrusterFwdLatMtrEnb;
    thrusters.dmiMtrEnb[3] = powerDmi.thrusterAftLatMtrEnb;
    thrusters.dmiMtrEnb[4] = powerDmi.thrusterPortVertMtrEnb;
    thrusters.dmiMtrEnb[5] = powerDmi.thrusterStbdVertMtrEnb;
    thrusters.group = powerGroups.thrusters;

    FOREVER
    {
/* wait for power request                                                     */
        semTake(powerReqSem, WAIT_FOREVER);

/* for debugging only                                                         */
	numSemTake++;
        gettimeofday(&sampleTime, (struct timezone *) NULL);
        status = dm_write(powerDmi.numSemTake, (Void *) &numSemTake,
			  sizeof(numSemTake), &sampleTime);

/* determine which subsystem or device is requesting power                    */
        genericGroupBits = dm_get_group_changes(powerGroups.generic);
        thrustersGroupBits = dm_get_group_changes(powerGroups.thrusters);
        staticGroupBits = dm_get_group_changes(powerGroups.staticLoad);
        for (group = 0; group < powerGroups.numSwitch; group++)
            switchGroupBits[group] =
	    dm_get_group_changes(powerGroups.switchLoad[group]);

/* check for change in max power available                                    */
	if (genericGroupBits & powerGroups.genericBit)
	    powerAvailable = maxPower(powerDmi.maxPwrAvail,
				      powerDmi.thrustersPwrAlloc, &divisions);

/* service static loads                                                       */
        for (item = 0; item < powerDmi.numStatic; item++)
            if (staticGroupBits & powerGroups.staticBit[item])
	        powerStatic(powerDmi.staticPwrReq[item],
			    powerDmi.staticPwrOk[item],
		            &staticPwrAlloc[item], &powerAvailable, &divisions,
		            staticPwrReq[item]);

/* service control system thrusters power request                             */
        if (thrustersGroupBits & powerGroups.thrustersBit)
	{
	    powerThrusters(powerDmi.thrustersPwrReq, powerDmi.thrustersPwrAlloc,
		           powerDmi.thrustersPwrOk, &thrusters.pwrAlloc,
		           &powerAvailable);

/* for debugging only                                                         */
	    numThrustReq++;
            status = dm_write(powerDmi.numThrustReq, (Void *) &numThrustReq,
			      sizeof(numThrustReq), &sampleTime);
	}

/* service switched loads                                                     */
        numItems = 0;
        numGroups = 0;
        for (item = 0; item < powerDmi.numSwitch; item++)
        {
	    numItems++;
	    if (numItems > GROUP_MAX)
	    {
	        numItems = 1;
	        numGroups++;
	    }
            if (switchGroupBits[numGroups] & powerGroups.switchBit[item])
	    {
	        powerSwitch(powerDmi.switchPwrReq[item],
			    powerDmi.switchPwrOk[item], &switchPwrAlloc[item],
			    &powerAvailable, &divisions, &thrusters);

	 	numSwitchReq++;
                status = dm_write(powerDmi.numSwitchReq,
				  (Void *) &numSwitchReq, sizeof(numSwitchReq),
				  &sampleTime);
	    }
        }

/* for debugging only                                                         */
	numReq++;
        status = dm_write(powerDmi.numReq, (Void *) &numReq, sizeof(numReq),
			  &sampleTime);

    } /* FOREVER */

    return;

} /* powerTask */


/******************************************************************************/
/* Function : powerDMInit                                                     */
/* Purpose  : Creates data manager items, starts consumers and providers and  */
/*            sets up groups.                                                 */
/* Inputs   : Power data manager items, power request and confirm semaphores, */
/*            power groups and static power request names.                    */
/* Outputs  : Returns data manager error code.                                */
/******************************************************************************/
    LOCAL Errno
powerDMInit(powerDMItems *powerDmi, SEM_ID powerReqSem,
	    SEM_ID thrustersPwrConfSem[], powerDMGroups *powerGroups,
            char staticPwrReq[NUM_STATIC_POWER][DM_ITEM_NAME_LEN])
{
    powerDMNames powerNames;		/* power data manager item names      */

    FILE         *fpr;			/* data manager power items file      */
    FILE         *fpw;			/* verified data mgr power items file */
    char         tmpString[FILE_LINE_LEN];	/* temporary strings          */
    char         tmpString1[DM_ITEM_NAME_LEN];
    char         tmpString2[DM_ITEM_NAME_LEN];
    char         tmpString3[DM_ITEM_NAME_LEN];
    char         tmpString4[DM_ITEM_NAME_LEN];
    char         *motorDMPrefix[] =	/* data manager motor item name prefix*/
    { PORT_HORIZ_THRUSTER_DM,  STBD_HORIZ_THRUSTER_DM, 
      FWD_LATERAL_THRUSTER_DM, AFT_LATERAL_THRUSTER_DM,
      PORT_VERT_THRUSTER_DM,   STBD_VERT_THRUSTER_DM };
    char         *motorDMName;		/* data manager motor item name       */
					/* motor enable item name             */
    char         motorEnableName[NUM_THRUSTERS][DM_ITEM_NAME_LEN];
    thrusterId   thruster;		/* thruster initialization counter    */
    MBool        verifyFileOpen = FALSE;/* verify dm items file open flag     */
    Int16        numStrings;            /* number of strings read in          */
    Int16        keyWordStart;		/* position of keyword start          */
    Int16        item;			/* data manager item counter          */
    Errno        status;		/* data manager error code            */
					/* data manager initialization values */
    dmInit       dmInitNat[] =
    { { HOTEL_PWR_ALLOC_DM, 	&powerDmi->hotelPwrAlloc },
      { LIGHTS_PWR_ALLOC_DM, 	&powerDmi->lightsPwrAlloc },
      { TOOLS_PWR_ALLOC_DM, 	&powerDmi->toolsPwrAlloc },
      { THRUSTERS_PWR_ALLOC_DM, &powerDmi->thrustersPwrAlloc },
      { NULL, NO_ITEM } };
    dmInit       dmInitBool[] =
    { { THRUSTERS_PWR_RED_DM,            &powerDmi->thrustersPwrRed },
      { THRUSTER_PORT_HORIZ_PWR_CONF_DM, &powerDmi->thrusterPortHorizPwrConf },
      { THRUSTER_STBD_HORIZ_PWR_CONF_DM, &powerDmi->thrusterStbdHorizPwrConf },
      { THRUSTER_FWD_LAT_PWR_CONF_DM,    &powerDmi->thrusterFwdLatPwrConf },
      { THRUSTER_AFT_LAT_PWR_CONF_DM,    &powerDmi->thrusterAftLatPwrConf },
      { THRUSTER_PORT_VERT_PWR_CONF_DM,  &powerDmi->thrusterPortVertPwrConf },
      { THRUSTER_STBD_VERT_PWR_CONF_DM,  &powerDmi->thrusterStbdVertPwrConf },
      { NULL, NO_ITEM } };
    dmInit       dmInitEnum[] =
    { { motorEnableName[PORT_HORIZ],  &powerDmi->thrusterPortHorizMtrEnb },
      { motorEnableName[STBD_HORIZ],  &powerDmi->thrusterStbdHorizMtrEnb },
      { motorEnableName[FWD_LATERAL], &powerDmi->thrusterFwdLatMtrEnb },
      { motorEnableName[AFT_LATERAL], &powerDmi->thrusterAftLatMtrEnb },
      { motorEnableName[PORT_VERT],   &powerDmi->thrusterPortVertMtrEnb },
      { motorEnableName[STBD_VERT],   &powerDmi->thrusterStbdVertMtrEnb },
      { NULL, NO_ITEM } };

/* open the data manager power item names file                                */
    if ((fpr = fopen(POWER_DM_FILENAME, "r")) == NULL)
    {
	logMsg("Power Manager FAILURE: Could not open file %s\n",
	       POWER_DM_FILENAME);
	return(ERROR);
    }

/* open the verification data manager power item names file                   */
    if (VERIFY_POWER_DM)
    {
        if ((fpw = fopen(VERIFY_POWER_DM_FILENAME, "w")) == NULL)
	    logMsg("Power Manager WARNING: Could not open file %s\n",
	           VERIFY_POWER_DM_FILENAME);
	verifyFileOpen = TRUE;
    }

/* read the power request and power ok data manager item names                */
/* separate the thrusters, static loads and switched power items              */
    powerDmi->numStatic = -1;
    powerDmi->numSwitch = -1;
    while (fgets(tmpString, FILE_LINE_LEN, fpr) != NULL)
    {
	numStrings = sscanf(tmpString, "%s %s %s", tmpString1, tmpString2,
                            tmpString3);
	if ((numStrings == 3) && (strcmp(tmpString1, "#define") == 0))
	{
	    memset(tmpString4, 0, (size_t) DM_ITEM_NAME_LEN);
	    strncpy(tmpString4, tmpString3+1, (size_t) strlen(tmpString3)-2);
	    keyWordStart = strlen(tmpString4) - strlen(POWER_REQ_KEYWORD);
	    if (strcmp(tmpString4+keyWordStart, POWER_REQ_KEYWORD) == 0)
	    {
						/* thrusters power items      */
		if (strcmp(tmpString4, THRUSTERS_KEYWORD) == 0)
		    setThrustersNames(fpw, verifyFileOpen, tmpString4,
				      keyWordStart, &powerNames);
						/* static power items         */
		else if (strcmp(tmpString4, VME_240V_BUS_KEYWORD) == 0)
		    setStaticPowerNames(fpw, verifyFileOpen, tmpString4,
				        keyWordStart, &powerDmi->numStatic,
					&powerNames);
		else if (strcmp(tmpString4, VME_48V_BUS_KEYWORD) == 0)
		    setStaticPowerNames(fpw, verifyFileOpen, tmpString4,
				        keyWordStart, &powerDmi->numStatic,
					&powerNames);
		else if (strcmp(tmpString4, POWER_CAN_KEYWORD) == 0)
		    setStaticPowerNames(fpw, verifyFileOpen, tmpString4,
				        keyWordStart, &powerDmi->numStatic,
					&powerNames);
						/* switched power items       */
		else
		    setSwitchedPowerNames(fpw, verifyFileOpen, tmpString4,
				          keyWordStart, &powerDmi->numSwitch,
					  &powerNames);
	    }
	}
    }
    powerDmi->numStatic++;
    powerDmi->numSwitch++;
    if (powerDmi->numSwitch > NUM_SWITCH_POWER)
    {
	logMsg("Power Manager FAILURE: Exceeded maximum number of items\n");
	return(ERROR);
    }
    fclose(fpr);
    if (verifyFileOpen)
	fclose(fpw);

/* copy the static power request item names                                   */
    for (item = 0; item < powerDmi->numStatic; item++)
	strcpy(staticPwrReq[item], powerNames.staticPwrReq[item]);

/* create motor enable data manager item name                                 */
    motorDMName = MOTOR_ENABLE_STATUS_DM;
    for (thruster = PORT_HORIZ; thruster <= STBD_VERT; thruster++)
    {
	strcpy(motorEnableName[thruster], motorDMPrefix[thruster]);
	strcat(motorEnableName[thruster], motorDMName);
    }

/* create data manager items                                                  */
						/* thrusters power items      */
    status = dm_create(powerNames.thrustersPwrReq, 1,
		       &powerDmi->thrustersPwrReq, DM_NAT16, 1, DM_ENDT);
    if (checkCreate(status, powerNames.thrustersPwrReq, FALSE) == ERROR)
	    return(ERROR);
    status = dm_create(powerNames.thrustersPwrOk, 1,
		       &powerDmi->thrustersPwrOk, DM_MBOOL, 1, DM_ENDT);
    if (checkCreate(status, powerNames.thrustersPwrOk, FALSE) == ERROR)
	    return(ERROR);
						/* static power items         */
    for (item = 0; item < powerDmi->numStatic; item++)
    {
	status = dm_create(powerNames.staticPwrReq[item], 1,
			   &powerDmi->staticPwrReq[item], DM_NAT16, 1,
			   DM_ENUM, 1, DM_ENUM, 1, DM_ENDT);
	if (checkCreate(status, powerNames.staticPwrReq[item], FALSE)
	    == ERROR)
	    return(ERROR);
	status = dm_create(powerNames.staticPwrOk[item], 1,
			   &powerDmi->staticPwrOk[item], DM_MBOOL, 1,
			   DM_ENDT);
	if (checkCreate(status, powerNames.staticPwrOk[item], FALSE)
	    == ERROR)
	    return(ERROR);
    }
						/* switchable power items     */
    for (item = 0; item < powerDmi->numSwitch; item++)
    {
	status = dm_create(powerNames.switchPwrReq[item], 1,
			   &powerDmi->switchPwrReq[item], DM_NAT16, 1,
			   DM_ENUM, 1, DM_ENUM, 1, DM_ENDT);
	if (checkCreate(status, powerNames.switchPwrReq[item], FALSE)
	    == ERROR)
	    return(ERROR);
	status = dm_create(powerNames.switchPwrOk[item], 1,
			   &powerDmi->switchPwrOk[item], DM_MBOOL, 1,
			   DM_ENDT);
	if (checkCreate(status, powerNames.switchPwrOk[item], FALSE)
	    == ERROR)
	    return(ERROR);
    }
						/* natural number items       */
    for (item = 0; dmInitNat[item].item != NO_ITEM; item++)
    {
	status = dm_create(dmInitNat[item].name, 1, dmInitNat[item].item,
			   DM_NAT16, 1, DM_ENDT);
	if (checkCreate(status, dmInitNat[item].name, FALSE) == ERROR)
	    return(ERROR);
    }
						/* boolean items              */
    for (item = 0; dmInitBool[item].item != NO_ITEM; item++)
    {
	status = dm_create(dmInitBool[item].name, 1, dmInitBool[item].item,
			   DM_MBOOL, 1, DM_ENDT);
	if (checkCreate(status, dmInitBool[item].name, FALSE) == ERROR)
	    return(ERROR);
    }
						/* enumerated type items      */
    for (item = 0; dmInitEnum[item].item != NO_ITEM; item++)
    {
	status = dm_create(dmInitEnum[item].name, 1, dmInitEnum[item].item,
			   DM_ENUM, 1, DM_ENDT);
	if (checkCreate(status, dmInitEnum[item].name, FALSE) == ERROR)
	    return(ERROR);
    }

/* create max power available                                                 */
    status = dm_create(MAX_PWR_AVAIL_DM, 1, &powerDmi->maxPwrAvail, DM_NAT16, 1,
                       DM_ENDT);
    if (checkCreate(status, MAX_PWR_AVAIL_DM, FALSE) == ERROR)
	return(ERROR);

/* for debugging purposes only                                                */
    status = dm_create(NUM_SEMTAKE_DM, 1, &powerDmi->numSemTake, DM_INT32, 1,
		       DM_ENDT);
    if (checkCreate(status, NUM_SEMTAKE_DM, FALSE) == ERROR)
	    return(ERROR);
    status = dm_create(NUM_THRUST_REQ_DM, 1, &powerDmi->numThrustReq, DM_INT32,
		       1, DM_ENDT);
    if (checkCreate(status, NUM_THRUST_REQ_DM, FALSE) == ERROR)
	    return(ERROR);
    status = dm_create(NUM_SWITCH_REQ_DM, 1, &powerDmi->numSwitchReq, DM_INT32,
		       1, DM_ENDT);
    if (checkCreate(status, NUM_SWITCH_REQ_DM, FALSE) == ERROR)
	    return(ERROR);
    status = dm_create(NUM_REQ_DM, 1, &powerDmi->numReq, DM_INT32, 1, DM_ENDT);
    if (checkCreate(status, NUM_REQ_DM, FALSE) == ERROR)
	    return(ERROR);

/* start consumers and create data manager groups for power requests          */
    if (powerConsumersGroup(powerDmi, &powerNames, powerReqSem,
			    thrustersPwrConfSem, powerGroups) == ERROR)
	return(ERROR);

/* start providers for power confirmations                                    */
    if (powerProviders(powerDmi, &powerNames) == ERROR)
	return(ERROR);
    return(OK);

} /* powerDMInit */


/******************************************************************************/
/* Function : setThrustersNames                                               */
/* Purpose  : Sets the thrusters power request and power ok data manager item */
/*            names.                                                          */
/* Inputs   : Verification file pointer and flag, input string, keyword start */
/*            position and power data manager item names.                     */
/* Outputs  : None.                                                           */
/******************************************************************************/
    LOCAL void
setThrustersNames(FILE *fpw, MBool verifyFileOpen, char *string,
		  Int16 keyWordStart, powerDMNames *powerNames)
{

    memset(powerNames->thrustersPwrReq, 0, (size_t) DM_ITEM_NAME_LEN);
    memset(powerNames->thrustersPwrOk, 0, (size_t) DM_ITEM_NAME_LEN);
    strcpy(powerNames->thrustersPwrReq, string);
    strncpy(powerNames->thrustersPwrOk, string, (size_t) keyWordStart);
    strcat(powerNames->thrustersPwrOk, POWER_OK_KEYWORD);
    if (verifyFileOpen)
        fprintf(fpw, "%s  %s\n", powerNames->thrustersPwrReq,
                powerNames->thrustersPwrOk);

}  /* setThrustersNames */


/******************************************************************************/
/* Function : setStaticPowerNames                                             */
/* Purpose  : Sets the static power request and power ok data manager item    */
/*            names.                                                          */
/* Inputs   : Verification file pointer and flag, input string, keyword start */
/*            position, number of static power items and power data manager   */
/*            item names.                                                     */
/* Outputs  : None.                                                           */
/******************************************************************************/
    LOCAL void
setStaticPowerNames(FILE *fpw, MBool verifyFileOpen, char *string,
		    Int16 keyWordStart, Int16 *numStaticPowerItems,
		    powerDMNames *powerNames)
{

    (*numStaticPowerItems)++;
    memset(powerNames->staticPwrReq[*numStaticPowerItems], 0,
           (size_t) DM_ITEM_NAME_LEN);
    memset(powerNames->staticPwrOk[*numStaticPowerItems], 0,
           (size_t) DM_ITEM_NAME_LEN);
    strcpy(powerNames->staticPwrReq[*numStaticPowerItems], string);
    strncpy(powerNames->staticPwrOk[*numStaticPowerItems], string,
	    (size_t) keyWordStart);
    strcat(powerNames->staticPwrOk[*numStaticPowerItems], POWER_OK_KEYWORD);
    if (verifyFileOpen)
        fprintf(fpw, "%s  %s\n",
		powerNames->staticPwrReq[*numStaticPowerItems],
                powerNames->staticPwrOk[*numStaticPowerItems]);

}  /* setStaticPowerNames */


/******************************************************************************/
/* Function : setSwitchedPowerNames                                           */
/* Purpose  : Sets the switched power request and power ok data manager item  */
/*            names.                                                          */
/* Inputs   : Verification file pointer and flag, input string, keyword start */
/*            position, number of switched power items and power data manager */
/*            item names.                                                     */
/* Outputs  : None.                                                           */
/******************************************************************************/
    LOCAL void
setSwitchedPowerNames(FILE *fpw, MBool verifyFileOpen, char *string,
		      Int16 keyWordStart, Int16 *numSwitchPowerItems,
		      powerDMNames *powerNames)
{

    (*numSwitchPowerItems)++;
    memset(powerNames->switchPwrReq[*numSwitchPowerItems], 0,
           (size_t) DM_ITEM_NAME_LEN);
    memset(powerNames->switchPwrOk[*numSwitchPowerItems], 0,
           (size_t) DM_ITEM_NAME_LEN);
    strcpy(powerNames->switchPwrReq[*numSwitchPowerItems], string);
    strncpy(powerNames->switchPwrOk[*numSwitchPowerItems], string,
	    (size_t) keyWordStart);
    strcat(powerNames->switchPwrOk[*numSwitchPowerItems], POWER_OK_KEYWORD);
    if (verifyFileOpen)
        fprintf(fpw, "%s  %s\n",
		powerNames->switchPwrReq[*numSwitchPowerItems],
                powerNames->switchPwrOk[*numSwitchPowerItems]);

}  /* setSwitchedPowerNames */


/******************************************************************************/
/* Function : powerConsumersGroup                                             */
/* Purpose  : Starts power data manager consumers, creates power data manager */
/*            groups and checks status.                                       */
/* Inputs   : Power data manager items structure pointer, wakeup semaphore,   */
/*            thrusters' power confirmed semaphore, power data manager group  */
/*            pointers, power group id bits pointer.                          */
/* Outputs  : Returns OK or ERROR.                                            */
/******************************************************************************/
    LOCAL Errno
powerConsumersGroup(powerDMItems *powerDmi, powerDMNames *powerNames,
		    SEM_ID powerReqSem, SEM_ID thrustersPwrConfSem[],
		    powerDMGroups *powerGroups)
{
    Errno status;			/* error code                         */
    Int16 item, numItems;		/* data manager item counter          */
    Int16 group, numGroups;		/* data manager group counter         */

/* start max power available consumer item and check status                   */
    status = dm_start_consumer(powerDmi->maxPwrAvail, DM_STATIC,
			       powerReqSem);
    if (checkConsumer(status, MAX_PWR_AVAIL_DM, FALSE) == ERROR)
	return(ERROR);

/* start power allocation consumer items                                      */
    status = dm_start_consumer(powerDmi->thrustersPwrAlloc, DM_STATIC, SEM_NULL);
    if (checkConsumer(status, "Thrusters power allocated", FALSE) == ERROR)
	return(ERROR);
    status = dm_start_consumer(powerDmi->hotelPwrAlloc, DM_STATIC, SEM_NULL);
    if (checkConsumer(status, "Hotel power allocated", FALSE) == ERROR)
	return(ERROR);
    status = dm_start_consumer(powerDmi->lightsPwrAlloc, DM_STATIC, SEM_NULL);
    if (checkConsumer(status, "Lights power allocated", FALSE) == ERROR)
	return(ERROR);
    status = dm_start_consumer(powerDmi->toolsPwrAlloc, DM_STATIC, SEM_NULL);
    if (checkConsumer(status, "Tools power allocated", FALSE) == ERROR)
	return(ERROR);

/* start power request consumer items and check status                        */
					/* thrusters power                    */
    status = dm_start_consumer(powerDmi->thrustersPwrReq, DM_STATIC,
			       powerReqSem);
    if (checkConsumer(status, powerNames->thrustersPwrReq, FALSE) == ERROR)
	return(ERROR);
					/* static power                       */
    for (item = 0; item < powerDmi->numStatic; item++)
    {
        status = dm_start_consumer(powerDmi->staticPwrReq[item], DM_STATIC,
				   powerReqSem);
        if (checkConsumer(status, powerNames->staticPwrReq[item], FALSE)
	    == ERROR)
	    return(ERROR);
    }
					/* switchable power                   */
    for (item = 0; item < powerDmi->numSwitch; item++)
    {
        status = dm_start_consumer(powerDmi->switchPwrReq[item], DM_STATIC,
				   powerReqSem);
        if (checkConsumer(status, powerNames->switchPwrReq[item], FALSE)
	    == ERROR)
	    return(ERROR);
    }

/* start thrusters power confirmed items and check status                     */
    status = dm_start_consumer(powerDmi->thrusterPortHorizPwrConf, DM_STATIC,
			       thrustersPwrConfSem[PORT_HORIZ]);
    if (checkConsumer(status,
	"Power Manager - port horizontal thruster power confirmed", FALSE)
	== ERROR)
	return(ERROR);
    status = dm_start_consumer(powerDmi->thrusterStbdHorizPwrConf, DM_STATIC,
			       thrustersPwrConfSem[STBD_HORIZ]);
    if (checkConsumer(status,
	"Power Manager - starboard horizontal thruster power confirmed", FALSE)
	== ERROR)
	return(ERROR);
    status = dm_start_consumer(powerDmi->thrusterFwdLatPwrConf, DM_STATIC,
			       thrustersPwrConfSem[FWD_LATERAL]);
    if (checkConsumer(status,
	"Power Manager - forward lateral thruster power confirmed", FALSE)
	== ERROR)
	return(ERROR);
    status = dm_start_consumer(powerDmi->thrusterAftLatPwrConf, DM_STATIC,
			       thrustersPwrConfSem[AFT_LATERAL]);
    if (checkConsumer(status,
	"Power Manager - aft lateral thruster power confirmed", FALSE) == ERROR)
	return(ERROR);
    status = dm_start_consumer(powerDmi->thrusterPortVertPwrConf, DM_STATIC,
			       thrustersPwrConfSem[PORT_VERT]);
    if (checkConsumer(status,
	"Power Manager - port vertical thruster power confirmed", FALSE)
	== ERROR)
	return(ERROR);
    status = dm_start_consumer(powerDmi->thrusterStbdVertPwrConf, DM_STATIC,
			       thrustersPwrConfSem[STBD_VERT]);
    if (checkConsumer(status,
	"Power Manager - starboard vertical thruster power confirmed", FALSE)
	== ERROR)
	return(ERROR);

/* start thrusters motor power enabled items and check status                 */
    status = dm_start_consumer(powerDmi->thrusterPortHorizMtrEnb, DM_STATIC,
			       SEM_NULL);
    if (checkConsumer(status,
	"Power Manager - port horizontal motor power enabled", FALSE) == ERROR)
	return(ERROR);
    status = dm_start_consumer(powerDmi->thrusterStbdHorizMtrEnb, DM_STATIC,
			       SEM_NULL);
    if (checkConsumer(status,
	"Power Manager - starboard horizontal motor power enabled", FALSE)
	== ERROR)
	return(ERROR);
    status = dm_start_consumer(powerDmi->thrusterFwdLatMtrEnb, DM_STATIC,
			       SEM_NULL);
    if (checkConsumer(status,
	"Power Manager - forward lateral motor power enabled", FALSE) == ERROR)
	return(ERROR);
    status = dm_start_consumer(powerDmi->thrusterAftLatMtrEnb, DM_STATIC,
			       SEM_NULL);
    if (checkConsumer(status,
	"Power Manager - aft lateral motor power enabled", FALSE) == ERROR)
	return(ERROR);
    status = dm_start_consumer(powerDmi->thrusterPortVertMtrEnb, DM_STATIC,
			       SEM_NULL);
    if (checkConsumer(status,
	"Power Manager - port vertical motor power enabled", FALSE) == ERROR)
	return(ERROR);
    status = dm_start_consumer(powerDmi->thrusterStbdVertMtrEnb, DM_STATIC,
			       SEM_NULL);
    if (checkConsumer(status,
        "Power Manager - starboard vertical motor power enabled", FALSE)
	== ERROR)
	return(ERROR);

/* create data manager groups                                                 */
    powerGroups->numSwitch = (Int16) (powerDmi->numSwitch / GROUP_MAX + 1);
    if (powerGroups->numSwitch > NUM_POWER_GROUPS)
    {
	logMsg("Power Manager FAILURE: Exceeded maximum number of power groups\n");
	return(ERROR);
    }
    powerGroups->generic = dm_create_group();
    powerGroups->thrusters = dm_create_group();
    powerGroups->staticLoad = dm_create_group();
    for (group = 0; group < powerGroups->numSwitch; group++)
        powerGroups->switchLoad[group] = dm_create_group();

/* add the max power available item to the generic group                      */
    status = dm_group_add_item(powerGroups->generic, powerDmi->maxPwrAvail,
			       &powerGroups->genericBit);
    if (checkGroup(status, "Power Manager - max power available") == ERROR)
	return(ERROR);

/* add the thrusters power request item to the thrusters group                */
    status = dm_group_add_item(powerGroups->thrusters,
			       powerDmi->thrustersPwrReq,
			       &powerGroups->thrustersBit);
    if (checkGroup(status, "Power Manager - thrusters power request") == ERROR)
	return(ERROR);

/* add the static load power requests to their group                          */
    for (item = 0; item < powerDmi->numStatic; item++)
    {
	status = dm_group_add_item(powerGroups->staticLoad,
				   powerDmi->staticPwrReq[item],
				   &powerGroups->staticBit[item]);
        if (checkGroup(status, powerNames->staticPwrReq[item]) == ERROR)
	    return(ERROR);
    }

/* add the switched load power requests to their group                        */
    numItems = 0;
    numGroups = 0;
    for (item = 0; item < powerDmi->numSwitch; item++)
    {
	numItems++;
	if (numItems > GROUP_MAX)
	{
	    numItems = 1;
	    numGroups++;
	}
	status = dm_group_add_item(powerGroups->switchLoad[numGroups],
				   powerDmi->switchPwrReq[item],
				   &powerGroups->switchBit[item]);
        if (checkGroup(status, powerNames->switchPwrReq[item]) == ERROR)
	    return(ERROR);
    }

    return(OK);

} /* powerConsumersGroup */


/******************************************************************************/
/* Function : powerProviders                                                  */
/* Purpose  : Starts power data manager providers and checks status.          */
/* Inputs   : Number of power items, power data manager items and power ok    */
/*            item names.                                                     */
/* Outputs  : Returns OK or ERROR.                                            */
/******************************************************************************/
    LOCAL Errno
powerProviders(powerDMItems *powerDmi, powerDMNames *powerNames)
{
    Errno   status;			/* error code                         */
    MBool   pwrRed = FALSE;		/* power reduced flag                 */
    MBool   pwrOk = FALSE;		/* power ok flag                      */
    Nat16   pwrAlloc = 0;		/* power allocated                    */
    Nat16   maxPwrAvail = MAX_POWER;	/* max power available               */
    Int16   item;			/* data manager item counter          */
    DM_Time sampleTime;			/* power update sample time           */

/* start provider items and check status                                      */
    status = dm_start_provider(powerDmi->maxPwrAvail, DM_STATIC);
    if (checkProvider(status, "Power Manager - maximum power available")
	== ERROR)
        return(ERROR);
    status = dm_start_provider(powerDmi->hotelPwrAlloc, DM_STATIC);
    if (checkProvider(status, "Power Manager - hotel power allocated")
	== ERROR)
        return(ERROR);
    status = dm_start_provider(powerDmi->lightsPwrAlloc, DM_STATIC);
    if (checkProvider(status, "Power Manager - lights power allocated")
	== ERROR)
        return(ERROR);
    status = dm_start_provider(powerDmi->toolsPwrAlloc, DM_STATIC);
    if (checkProvider(status, "Power Manager - tools power allocated")
	== ERROR)
        return(ERROR);
    status = dm_start_provider(powerDmi->thrustersPwrAlloc, DM_STATIC);
    if (checkProvider(status, "Power Manager - thrusters power allocated")
	== ERROR)
        return(ERROR);
    status = dm_start_provider(powerDmi->thrustersPwrRed, DM_STATIC);
    if (checkProvider(status, "Power Manager - thrusters power reduced")
	== ERROR)
        return(ERROR);
    status = dm_start_provider(powerDmi->thrustersPwrOk, DM_STATIC);
    if (checkProvider(status, "Power Manager - thrusters power ok") == ERROR)
        return(ERROR);
    for (item = 0; item < powerDmi->numStatic; item++)
    {
        status = dm_start_provider(powerDmi->staticPwrOk[item], DM_STATIC);
        if (checkProvider(status, powerNames->staticPwrOk[item]) == ERROR)
	    return(ERROR);
    }
    for (item = 0; item < powerDmi->numSwitch; item++)
    {
        status = dm_start_provider(powerDmi->switchPwrOk[item], DM_STATIC);
        if (checkProvider(status, powerNames->switchPwrOk[item]) == ERROR)
	    return(ERROR);
    }

/* for debugging purposes only                                                */
    status = dm_start_provider(powerDmi->numSemTake, DM_STATIC);
    if (checkProvider(status, "Power Manager - number sem takes") == ERROR)
        return(ERROR);
    status = dm_start_provider(powerDmi->numThrustReq, DM_STATIC);
    if (checkProvider(status, "Power Manager - number thrust requests")
	== ERROR)
        return(ERROR);
    status = dm_start_provider(powerDmi->numSwitchReq, DM_STATIC);
    if (checkProvider(status, "Power Manager - number switch requests")
	== ERROR)
        return(ERROR);
    status = dm_start_provider(powerDmi->numReq, DM_STATIC);
    if (checkProvider(status, "Power Manager - number requests")
	== ERROR)
        return(ERROR);

/* initialize power allocated to zero                                         */
    gettimeofday(&sampleTime, (struct timezone *) NULL);
    status = dm_write(powerDmi->maxPwrAvail, (Void *) &maxPwrAvail,
                      sizeof(maxPwrAvail), &sampleTime);
    if (checkWrite(status, "Power Manager - maximum power available") == ERROR)
        return(ERROR);
    status = dm_write(powerDmi->hotelPwrAlloc, (Void *) &pwrAlloc,
                      sizeof(pwrAlloc), &sampleTime);
    if (checkWrite(status, "Power Manager - hotel power allocated") == ERROR)
        return(ERROR);
    status = dm_write(powerDmi->lightsPwrAlloc, (Void *) &pwrAlloc,
                      sizeof(pwrAlloc), &sampleTime);
    if (checkWrite(status, "Power Manager - lights power allocated") == ERROR)
        return(ERROR);
    status = dm_write(powerDmi->toolsPwrAlloc, (Void *) &pwrAlloc,
                      sizeof(pwrAlloc), &sampleTime);
    if (checkWrite(status, "Power Manager - tools power allocated") == ERROR)
        return(ERROR);
    status = dm_write(powerDmi->thrustersPwrAlloc, (Void *) &pwrAlloc,
                      sizeof(pwrAlloc), &sampleTime);
    if (checkWrite(status, "Power Manager - thrusters power allocated")
	== ERROR)
        return(ERROR);

/* initialize thrusters power reduced and power ok flags to FALSE             */
    status = dm_write(powerDmi->thrustersPwrRed, (Void *) &pwrRed,
                      sizeof(pwrRed), &sampleTime);
    if (checkWrite(status, "Power Manager - thrusters power reduced")
	== ERROR)
        return(ERROR);
    status = dm_write(powerDmi->thrustersPwrOk, (Void *) &pwrOk, sizeof(pwrOk),
                      &sampleTime);
    if (checkWrite(status, "Power Manager - thrusters power ok") == ERROR)
        return(ERROR);
    for (item = 0; item < powerDmi->numStatic; item++)
    {
        status = dm_write(powerDmi->staticPwrOk[item], (Void *) &pwrOk,
                          sizeof(pwrOk), &sampleTime);
        if (checkWrite(status, powerNames->staticPwrOk[item]) == ERROR)
	    return(ERROR);
    }

#if 0
    for (item = 0; item < powerDmi->numSwitch; item++)
    {
        status = dm_write(powerDmi->switchPwrOk[item], (Void *) &pwrOk,
                          sizeof(pwrOk), &sampleTime);
        if (checkWrite(status, powerNames->switchPwrOk[item]) == ERROR)
	    return(ERROR);
    }
#endif

    return(OK);

} /* powerProviders */


/******************************************************************************/
/* Function : maxPower                                                        */
/* Purpose  : Changes the max power available for allocation.                 */
/* Inputs   : Static load power request and power OK data manager items,      */
/*            power allocated, power available, switch load divisions         */
/*            cumulative power pointer, load name.                            */
/* Outputs  : Max power availble.                                             */
/******************************************************************************/
    Nat16
maxPower(DM_Item dmiMaxPwrAvail, DM_Item dmiThrustersPwr,
	 switchDivisions *divisions)
{
    Nat16   maxPwrAvail;		/* max power available                */
    Nat16   thrustersPwrAlloc;		/* thrusters power allocated          */
    Nat16   hotelPwrAlloc;		/* hotel power allocated              */
    Nat16   lightsPwrAlloc;		/* lights power allocated             */
    Nat16   toolsPwrAlloc;		/* tools power allocated              */
    Int16   powerAvailable;		/* power available for allocation     */
    Errno   status;			/* dm error code                      */
    DM_Time sampleTime;			/* dm item sample time                */

/* get max power available                                                    */
    dm_read(dmiMaxPwrAvail, (Void *) &maxPwrAvail, sizeof(maxPwrAvail),
	    (DM_Time *) NULL);

/* get power already allocated                                                */
    dm_read(dmiThrustersPwr, (Void *) &thrustersPwrAlloc,
	    sizeof(thrustersPwrAlloc), (DM_Time *) NULL);
    dm_read(divisions->dmiHotelPwr, (Void *) &hotelPwrAlloc,
	    sizeof(hotelPwrAlloc), (DM_Time *) NULL);
    dm_read(divisions->dmiLightsPwr, (Void *) &lightsPwrAlloc,
	    sizeof(lightsPwrAlloc), (DM_Time *) NULL);
    dm_read(divisions->dmiToolsPwr, (Void *) &toolsPwrAlloc,
	    sizeof(toolsPwrAlloc), (DM_Time *) NULL);

/* determine the power available                                              */
    powerAvailable = maxPwrAvail - thrustersPwrAlloc - hotelPwrAlloc -
		     lightsPwrAlloc - toolsPwrAlloc;
    if (powerAvailable < 0)
    {
	logMsg("Power Manager WARNING : max power setting too low, reset to default value\n");
	maxPwrAvail = MAX_POWER;
	gettimeofday(&sampleTime, (struct timezone *) NULL);
	status = dm_write(dmiMaxPwrAvail, (Void *) &maxPwrAvail,
			  sizeof(maxPwrAvail), &sampleTime);
	checkWrite(status, MAX_PWR_AVAIL_DM);
    	return(maxPwrAvail - thrustersPwrAlloc - hotelPwrAlloc -
	       lightsPwrAlloc - toolsPwrAlloc);
    }
    else
	return((Nat16) powerAvailable);

} /* maxPower */


/******************************************************************************/
/* Function : powerStatic                                                     */
/* Purpose  : Allocates available power for vehicle static loads.             */
/* Inputs   : Static load power request and power OK data manager items,      */
/*            power allocated, power available, switch load divisions         */
/*            cumulative power pointer, load name.                            */
/* Outputs  : None.                                                           */
/******************************************************************************/
    void
powerStatic(DM_Item dmiPwrReq, DM_Item dmiPwrOk, Nat16 *pwrAlloc,
	    Nat16 *pwrAvail, switchDivisions *divisions, char *loadName)
{

    powerRequest pwrReq;		/* power request and system bus       */
    MBool        pwrOk;			/* power request OK                   */
    DM_Time      sampleTime;		/* power update sample time           */

/* get power requested                                                        */
    dm_read(dmiPwrReq, (Void *) &pwrReq, sizeof(pwrReq), (DM_Time *) NULL);

    if (pwrReq.power == 0)		/* switch power off                   */
    {
	*pwrAvail += *pwrAlloc;
	switch (pwrReq.division)     /* reset load divisions cumulative power */
	{
	    case HOTEL:
		divisions->hotelPwrAlloc -= *pwrAlloc;
		break;
	    case LIGHTS:
		divisions->lightsPwrAlloc -= *pwrAlloc;
		break;
	    case TOOLS:
		divisions->toolsPwrAlloc -= *pwrAlloc;
		break;
	}
	*pwrAlloc = 0;
	pwrOk = TRUE;
    }
    else				/* switch power on                    */
    {					/* factor in bus efficiency           */
	if (pwrReq.bus == A240)
	    *pwrAlloc = (Nat16) (pwrReq.power / BUS_240A_EFF);
	else if (pwrReq.bus == B240)
	    *pwrAlloc = (Nat16) (pwrReq.power / BUS_240B_EFF);
	else if (pwrReq.bus == A48)
	    *pwrAlloc = (Nat16) (pwrReq.power / BUS_48A_EFF);
	else if (pwrReq.bus == B48)
	    *pwrAlloc = (Nat16) (pwrReq.power / BUS_48B_EFF);

	if (*pwrAlloc <= *pwrAvail)	/* power is available                 */
	{
	    *pwrAvail -= *pwrAlloc;
	    switch (pwrReq.division) /* reset load divisions cumulative power */
	    {
	        case HOTEL:
		    divisions->hotelPwrAlloc += *pwrAlloc;
		    break;
	        case LIGHTS:
		    divisions->lightsPwrAlloc += *pwrAlloc;
		    break;
	        case TOOLS:
		    divisions->toolsPwrAlloc += *pwrAlloc;
		    break;
	    }
	    pwrOk = TRUE;
	}
	else				/* power not available                */
	{
	    *pwrAlloc = 0;
	    pwrOk = FALSE;
	    logMsg("Power Manager WARNING : %s\nnot enough power for static load\n", loadName);
	}
    } /* else switch power on */

/* update static load power OK and load divisions cumulative power            */
    gettimeofday(&sampleTime, (struct timezone *) NULL);
    dm_write(dmiPwrOk, (Void *) &pwrOk, sizeof(pwrOk), &sampleTime);
    switch (pwrReq.division)
    {
	case HOTEL:
    	    dm_write(divisions->dmiHotelPwr,
		     (Void *) &(divisions->hotelPwrAlloc),
		     sizeof(divisions->hotelPwrAlloc), &sampleTime);
	    break;
	case LIGHTS:
    	    dm_write(divisions->dmiLightsPwr,
		     (Void *) &(divisions->lightsPwrAlloc),
		     sizeof(divisions->lightsPwrAlloc), &sampleTime);
	    break;
	case TOOLS:
    	    dm_write(divisions->dmiToolsPwr,
		     (Void *) &(divisions->toolsPwrAlloc),
		     sizeof(divisions->toolsPwrAlloc), &sampleTime);
	    break;
    }

} /* powerStatic */


/******************************************************************************/
/* Function : powerThrusters                                                  */
/* Purpose  : Allocates available power for thruster control.                 */
/* Inputs   : Thrusters' power request, power allocated and power OK data     */
/*            manager items, thrusters' power allocated and power available.  */
/* Outputs  : None.                                                           */
/******************************************************************************/
    void
powerThrusters(DM_Item dmiPwrReq, DM_Item dmiPwrAlloc, DM_Item dmiPwrOk,
	       Nat16 *pwrAlloc, Nat16 *pwrAvail)
{

    Nat16   pwrReq;			/* power requested by control system  */
    MBool   pwrOk;			/* power request OK                   */
    Nat16   dpower;			/* delta power                        */
    DM_Time sampleTime;			/* power update sample time           */

/* get power requested                                                        */
    dm_read(dmiPwrReq, (Void *) &pwrReq, sizeof(pwrReq), (DM_Time *) NULL);

    if (pwrReq <= *pwrAlloc)   /* requested less power than already allocated */
    {
	dpower = *pwrAlloc - pwrReq;
	*pwrAvail += dpower;
	*pwrAlloc = pwrReq;
	pwrOk = TRUE;
    }
    else		       /* requested more power than already allocated */
    {
	
	if ((dpower = (pwrReq - *pwrAlloc)) <= *pwrAvail)  /* total power     */
	{						   /* requested is    */
	    *pwrAvail -= dpower;			   /* available       */
	    *pwrAlloc = pwrReq;
	    pwrOk = TRUE;
	}
	else			     /* partial power requested  is available */
	{
	    *pwrAlloc += *pwrAvail;
	    *pwrAvail = 0;
	    pwrOk = FALSE;
	}
    }

/* update power allocated and power OK                                        */
    gettimeofday(&sampleTime, (struct timezone *) NULL);
    dm_write(dmiPwrAlloc, (Void *) pwrAlloc, sizeof(*pwrAlloc), &sampleTime);
    dm_write(dmiPwrOk, (Void *) &pwrOk, sizeof(pwrOk), &sampleTime);

} /* powerThrusters */


/******************************************************************************/
/* Function : powerSwitch                                                     */
/* Purpose  : Allocates available power for vehicle subsystem or device.      */
/* Inputs   : Subsystem or device's power request and power OK data manager   */
/*            items; subsystem or device's power allocated; power available;  */
/*            switch load divisions cumulative power pointer; and thrusters'  */
/*            power variables structure pointer.                              */
/* Outputs  : None.                                                           */
/******************************************************************************/
    void
powerSwitch(DM_Item dmiPwrReq, DM_Item dmiPwrOk, Nat16 *pwrAlloc,
	    Nat16 *pwrAvail, switchDivisions *divisions,
	    thrustersVars *thrusters)
{

    powerRequest     pwrReq;		/* power request and system bus       */
    MBool            pwrOk;		/* power request OK                   */
    Nat16            dpower;		/* delta power                        */
    MBool            thrustersPwrOk;	/* thrusters power request OK         */
    MBool            thrustersPwrRed;	/* thrusters power reduced            */
    thrusterId       thruster;		/* thruster motor counter             */
    motorEnableState motorEnable[NUM_THRUSTERS];/* motor enabled flag         */
    DM_Time          sampleTime;	/* power update sample time           */

/* get power requested                                                        */
    dm_read(dmiPwrReq, (Void *) &pwrReq, sizeof(pwrReq), (DM_Time *) NULL);

    if (pwrReq.power == 0)		/* switch power off                   */
    {
	*pwrAvail += *pwrAlloc;
	switch (pwrReq.division)     /* reset load divisions cumulative power */
	{
	    case HOTEL:
		divisions->hotelPwrAlloc -= *pwrAlloc;
		break;
	    case LIGHTS:
		divisions->lightsPwrAlloc -= *pwrAlloc;
		break;
	    case TOOLS:
		divisions->toolsPwrAlloc -= *pwrAlloc;
		break;
	}
	*pwrAlloc = 0;
	pwrOk = TRUE;
    }
    else				/* switch power on                    */
    {					/* factor in bus efficiency           */
	if (pwrReq.bus == A240)
	    *pwrAlloc = (Nat16) (pwrReq.power / BUS_240A_EFF);
	else if (pwrReq.bus == B240)
	    *pwrAlloc = (Nat16) (pwrReq.power / BUS_240B_EFF);
	else if (pwrReq.bus == A48)
	    *pwrAlloc = (Nat16) (pwrReq.power / BUS_48A_EFF);
	else if (pwrReq.bus == B48)
	    *pwrAlloc = (Nat16) (pwrReq.power / BUS_48B_EFF);

	if (*pwrAlloc <= *pwrAvail)	/* power is available                 */
	{
	    *pwrAvail -= *pwrAlloc;
	    pwrOk = TRUE;
	} /* if */
					/* power available from thrusters     */
	else if ((dpower = (*pwrAlloc - *pwrAvail)) <= thrusters->pwrAlloc)
	{
	    thrusters->pwrAlloc -= dpower;
	    *pwrAvail = 0;
	    thrustersPwrRed = TRUE;
	    thrustersPwrOk = FALSE;

/* update power allocated to thrusters                                        */
	    gettimeofday(&sampleTime, (struct timezone *) NULL);
	    dm_write(thrusters->dmiPwrRed, (Void *) &thrustersPwrRed,
		     sizeof(thrustersPwrRed), &sampleTime);
	    dm_write(thrusters->dmiPwrAlloc, (Void *) &thrusters->pwrAlloc,
		     sizeof(thrusters->pwrAlloc), &sampleTime);

/* determine which thrusters are enabled                                      */
	    for (thruster = PORT_HORIZ; thruster <= STBD_VERT; thruster++)
	    {
		dm_read(thrusters->dmiMtrEnb[thruster],
			(Void *) &motorEnable[thruster],
			sizeof(motorEnable[thruster]), (DM_Time *) NULL);

/* wait for new thrust to be effected for all enabled thrusters               */
		if (motorEnable[thruster] == ENABLE_MOTOR)
	    	    semTake(thrusters->pwrConfSem[thruster], WAIT_FOREVER);
	    }
	    pwrOk = TRUE;

/* update thrusters power request OK                                          */
	    dm_write(thrusters->dmiPwrOk, (Void *) &thrustersPwrOk,
		     sizeof(thrustersPwrOk), &sampleTime);

/* update thrusters power reduction flag                                      */
	    thrustersPwrRed = FALSE;
	    dm_write(thrusters->dmiPwrRed, (Void *) &thrustersPwrRed,
		     sizeof(thrustersPwrRed), &sampleTime);

   	}

	else				/* not enough power available         */
	{
	    *pwrAlloc = 0;
	    pwrOk = FALSE;
	} /* else */

/* reset load divisions cumulative power                                      */
	switch (pwrReq.division)
	{
	    case HOTEL:
	        divisions->hotelPwrAlloc += *pwrAlloc;
		break;

	    case LIGHTS:
		divisions->lightsPwrAlloc += *pwrAlloc;
		break;

	    case TOOLS:
	        divisions->toolsPwrAlloc += *pwrAlloc;
		break;

	    } /* switch */
    } /* else switch power on */

/* update subsystem or device power OK and load division cumulative power     */
    gettimeofday(&sampleTime, (struct timezone *) NULL);
    dm_write(dmiPwrOk, (Void *) &pwrOk, sizeof(pwrOk), &sampleTime);
    switch (pwrReq.division)
    {
        case HOTEL:
    	    dm_write(divisions->dmiHotelPwr,
		     (Void *) &(divisions->hotelPwrAlloc),
		     sizeof(divisions->hotelPwrAlloc), &sampleTime);
	    break;
	case LIGHTS:
    	    dm_write(divisions->dmiLightsPwr,
		     (Void *) &(divisions->lightsPwrAlloc),
		     sizeof(divisions->lightsPwrAlloc), &sampleTime);
	    break;
	case TOOLS:
    	    dm_write(divisions->dmiToolsPwr,
		     (Void *) &(divisions->toolsPwrAlloc),
		     sizeof(divisions->toolsPwrAlloc), &sampleTime);
	    break;
    }
} /* powerSwitch */
