/****************************************************************************/
/* Copyright 1995 to 1996 MBARI                                             */
/****************************************************************************/
/* Summary  : Idle CPU Monitor Task for vxWorks                             */
/* Filename : idleCpu.c                                                     */
/* Author   : Andrew Pearce                                                 */
/* Project  : Tiburon                                                       */
/* Version  : Version 1.0                                                   */
/* Created  : 10/12/94                                                      */
/* Modified : 04/04/96                                                      */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/* $Header:
 * $Log:
 */
/****************************************************************************/

#include <vxWorks.h>                /* vxWorks system declarations          */
#include <semLib.h>                 /* vxWorks semaphore functions          */
#include <stdioLib.h>               /* vxWorks standard I/O functions       */
#include <msgQLib.h>                /* vxWorks Message Queue Library        */
#include <private/kernelLibP.h>     /* vxWorks kernel structures            */

#include "mbariTypes.h"             /* MBARI style guide type declarations  */
#include "mbariConst.h"             /* Miscellaneous constants              */

#include "rovPriority.h"            /* MBARI Rov Application Priorities     */
#include "usrTime.h"                /* MBARI time and date functions        */
#include "microdef.h"               /* MBARI Micro Alarm Type definition    */

#include "datamgr.h"                /* Data Manager declarations            */
#include "dm_errno.h"               /* Data Manager error declarations      */

#include "idleCpu.h"                /* Application specific declarations    */

/* local variables */

LOCAL UINT idleCpuIncTicks;             /* all ticks since last report */
LOCAL UINT idleCpuIdleIncTicks;         /* idle ticks since last report*/

LOCAL int  auxClkTicksPerSecond;
LOCAL int  idleCpuTaskId = ERROR;

/*******************************************************************************
*
* idleCpuClkInt - interrupt service routine
*
* This routine is called at each tick of the auxiliary clock.  When at
* interrupt level the interrupt tick count is incremented.  If there is no
* active task then the idle tick count is incremented, otherwise increment
* the active task's tick counter.
*/

    MLocal Void
idleCpuClkInt ()
{
    if (kernelIsIdle)                   /* we interrupted idle state       */
        idleCpuIdleIncTicks++;

    idleCpuIncTicks++;                  /* Increment total number of ticks */
} /* idleCpuClkInt() */

/*******************************************************************************
*
* idleCpuClkStart - start collecting task activity data
*
* This routine begins data collection by enabling the auxiliary clock
* interrupts.  Data from previous collections is cleared.
*
* RETURNS:
* OK, or
* ERROR if CPU has no auxiliary clock, or if
* task create/delete hooks cannot be installed.
*
* SEE ALSO: sysAuxClkConnect(2)
*/

    MLocal STATUS
idleCpuClkStart(Int32 intsPerSec)               /* timer interrupt frequency, */
{
    if (intsPerSec == 0)
        intsPerSec = 101;

    idleCpuIncTicks = idleCpuIdleIncTicks = 0;

    /* initialize tick counters of tasks already running */

    if (sysAuxClkConnect (idleCpuClkInt, 0) != OK)
    {
        printf ("No auxiliary clock on CPU.\n");
        return (ERROR);
    } /* if */

    auxClkTicksPerSecond = sysAuxClkRateGet();

    sysAuxClkRateSet (intsPerSec);
    sysAuxClkEnable ();

    return (OK);
} /* idleCpuClkStart() */

/*******************************************************************************
*
* spyStop - stop spying and reporting
*
* This routine calls spyClkStop(2).  If periodic reporting by spyTask(2)
* is active, it is terminated.
*/

   Void
idleCpuStop( Void )
{
    sysAuxClkRateSet (auxClkTicksPerSecond);
    sysAuxClkDisable ();

    if (idleCpuTaskId != ERROR)
    {
        taskDelete (idleCpuTaskId);
        idleCpuTaskId = ERROR;
    } /* if */
} /* idleCpuStop() */

/****************************************************************************/
/* Function    : idleCpuTask                                                */
/* Purpose     : Calculates amount of CPU Idle Time (based on vxWorks spy)  */
/* Inputs      : Data Manager Item Name up update                           */
/* Outputs     : NONE, but DM Item is modified                              */
/****************************************************************************/
   STATUS
idleCpuTask( const char *idleCpuItemName, const char *idleCpuAlarmName )
{
    DM_Item idleCpuPercentDm;       /* CPU Idle Time Data Manager Item      */
    DM_Item idleCpuAlarmDm;         /* CPU Idle Alarm Data Manager Item     */

    Int16      idleCpuPercent;
    microAlarm idleCpuAlarm, lastIdleCpuAlarm;

    Int32   freq = 3;               /* reporting frequency, in seconds      */
    Int32   ticksPerSec = 101;      /* interrupt clock frequency            */
    Int32   delay = freq * sysClkRateGet ();

                                    /* Set this task priority               */
    taskPrioritySet(taskIdSelf(), IDLE_CPU_TASK_PRIORITY);

    idleCpuPercent = 0;
    idleCpuAlarm = lastIdleCpuAlarm = MICRO_ALARM_OK;

    idleCpuPercentDm = initMicroDmItem("", idleCpuItemName,  DM_INT16, 1);
    idleCpuAlarmDm   = initMicroDmItem("", idleCpuAlarmName, DM_ENUM,  1);

    dm_start_provider(idleCpuPercentDm, freq * USECS_PER_SEC);
    dm_start_provider(idleCpuAlarmDm,   DM_STATIC);

    writeDmItem(idleCpuPercentDm, &idleCpuPercent, sizeof(idleCpuPercent));
    writeDmItem(idleCpuAlarmDm,   &idleCpuAlarm,   sizeof(idleCpuAlarm));

    if (idleCpuClkStart (ticksPerSec) != OK)
        return (ERROR);

    idleCpuTaskId = taskIdSelf();

    FOREVER
    {
        taskDelay (delay);
        if (idleCpuIncTicks != 0)
        {
            idleCpuPercent = (idleCpuIdleIncTicks * 100) / idleCpuIncTicks;
            idleCpuIncTicks = idleCpuIdleIncTicks = 0;

            if (idleCpuPercent <= IDLE_CPU_ALARM_LEVEL)
                idleCpuAlarm = MICRO_ALARM;

            else if (idleCpuPercent <= IDLE_CPU_WARN_LEVEL)
                idleCpuAlarm = MICRO_WARNING;

            else
                idleCpuAlarm = MICRO_ALARM_OK;

            writeDmItem(idleCpuPercentDm, &idleCpuPercent,
                sizeof(idleCpuPercent));

            if (idleCpuAlarm != lastIdleCpuAlarm)
            {
                lastIdleCpuAlarm = idleCpuAlarm;
                writeDmItem(idleCpuAlarmDm, &idleCpuAlarm,
                    sizeof(idleCpuAlarm));
            } /* if */

        } /* if */
    } /* FOREVER */
} /* idleCpuTask() */



