/****************************************************************************/
/* Copyright 1995 to 1996 MBARI                                             */
/****************************************************************************/
/* Summary  : System Hour Log Functions for vxWorks                         */
/* Filename : hourLog.c                                                     */
/* Author   : Andrew Pearce                                                 */
/* Project  : Tiburon                                                       */
/* Version  : Version 1.0                                                   */
/* Created  : 10/12/94                                                      */
/* Modified : 04/25/95                                                      */
/* 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 "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 "datamgr.h"                /* Data Manager declarations            */
#include "dm_errno.h"               /* Data Manager error declarations      */

#include "sio32.h"                  /* SIO32 Protocol Declarations          */
#include "sio32Server.h"            /* Sio32 server communication services  */
#include "sio32Client.h"            /* Sio32 client communication services  */

#include "microDm.h"                /* Microcontroller Data Manager Items   */
#include "powerDM.h"                /* Power System Data Manager Items      */
#include "powerTypes.h"             /* Power management Data Types          */
#include "vmeIbc.h"                 /* VME Can IBC Definitions              */

#include "thrusterDM.h"             /* Thruster Data Manager Item Names     */
#include "vbSystem.h"               /* VB System Data Manager Item Names    */
#include "ersDcon.h"                /* Emergency Recovery Data Manager Items*/
#include "lightingDcon.h"           /* Lighting Dcon Data Manager Items     */
#include "sensorsDm.h"              /* Sensors DM Prefix                    */

#include "tiburon.h"                /* Tiburon definitions                  */
#include "hourLog.h"                /* Application specific definitions     */

#define HOUR_LOG_DM_RATE HOUR_LOG_UPDATE_RATE * 60 * USECS_PER_SEC

MLocal FILE  *logFile;              /* Data Logging File Handle             */

/****************************************************************************/
/* Function    : updateElapsedTime                                          */
/* Purpose     : Update elapsed time DM item based on switch status DM item */
/* Inputs      : DM Items for power switch and elased time, log period,     */
/*               elased time pointer and description string for log file    */
/* Outputs     : NONE, but DM Item and log file are modified                */
/****************************************************************************/
    MLocal Void
updateElapsedTime( DM_Item pwrSwitchDm, DM_Item hourLogDm,
    Flt32 logPeriod, Flt32 *hourLog, const char* desc )
{
    switchStatus pwrSwitch = SWITCH_ON; /* Power Switch Status              */

    if ( (pwrSwitchDm == NO_ITEM) ||    /* Check Device Power Switch State  */
         (dm_read(pwrSwitchDm, (char *) &pwrSwitch, sizeof(pwrSwitch),
            (DM_Time *)NULL) == SUCCESS) )
    {
        if (pwrSwitch == SWITCH_ON)     /* Check switch state               */
        {                               /* Power is on so increment hours   */
            *hourLog += logPeriod;      /* and update elapsed hour DM Item  */
            writeDmItem(hourLogDm, hourLog, sizeof(Flt32));
        } /* if */
    } /* if */
                                        /* Write elapsed time to log file   */
    fprintf(logFile, "%s %.2f hours\n", desc, *hourLog);
} /* updateElapsedTime() */

/****************************************************************************/
/* Function    : updateSubmergedTime                                        */
/* Purpose     : Update in water time DM item based on in water DM item     */
/* Inputs      : DM Items for in-water status and elased time, log period,  */
/*               elased time pointer and description string for log file    */
/* Outputs     : NONE, but DM Item and log file are modified                */
/****************************************************************************/
    MLocal Void
updateSubmergedTime( DM_Item inWaterDm, DM_Item hourLogDm,
    Flt32 logPeriod, Flt32 *hourLog, const char* desc )
{
    MBool inWater;                      /* Vehicle In Water Status          */

    if (dm_read(inWaterDm, (char *) &inWater, sizeof(inWater),
        (DM_Time *) NULL) == SUCCESS)
    {
        if (inWater == TRUE)
        {                               /* and update elapsed hour DM Item  */
            *hourLog += logPeriod;
            writeDmItem(hourLogDm, hourLog, sizeof(Flt32));
        } /* if */
    } /* if */
                                        /* Write elapsed time to log file   */
    fprintf(logFile, "%s %.2f hours\n", desc, *hourLog );
} /* updateSubmergedTime() */

    MLocal Void
updateCycleCount( DM_Item lightSwitchDm, DM_Item lightCycleCountDm,
    switchStatus *lightState, Int32 *lightCycleCount, const char* desc )
{
    switchStatus pwrSwitch;             /* Power Switch Status              */

                                        /* Check Device Power Switch State  */
    if (dm_read(lightSwitchDm, (char *) &pwrSwitch, sizeof(pwrSwitch),
            (DM_Time *)NULL) == SUCCESS)
    {
        if (pwrSwitch != *lightState)   /* Check if switch state has changed*/
        {                               /* Yes so increment cycle counter   */
            *lightCycleCount++;
            writeDmItem(lightCycleCountDm, lightCycleCount, sizeof(Int32));
        } /* if */

        *lightState = pwrSwitch;        /* Save light switch state          */
    } /* if */
                                        /* Write elapsed time to log file   */
    fprintf(logFile, "%s %6d cycles\n", desc, *lightCycleCount);
} /* updateCycleCount() */

/****************************************************************************/
/* Function    : hourLogTask                                                */
/* Purpose     : Calculates powered-up times for ROV, Gyro and thrusters    */
/* Inputs      : NONE                                                       */
/* Outputs     : NONE, but DM Item and log file are modified                */
/****************************************************************************/
   STATUS
hourLogTask( Void )
{
    SEM_ID  wakeupSem;              /* Used wake up this task periodically  */

    time_t timeNow, startTime;      /* Time from real-time clock            */
    struct tm *bootTime;            /* Vehicle boot/reboot time             */
    char   *bootTimeString;         /* Boot timt string in ASCII            */
    char   itemPrefix[32];          /* Data Manager Item Prefix Name        */
    char   tempBuf[80];             /* Scratch buffer for fgets             */

    Int16 light;                    /* counter for light items              */
    Int32 updateTicks;              /* Update rate in ticks                 */
    Flt32 resolution;               /* Elapsed time resolution (hours)      */

                                    /* Total elapsed times for sub-systes   */
    Flt32 vehicleHourLog,   submergedHourLog, gyroHourLog, vbMotorHourLog;
    Flt32 portHorizHourLog, stbdHorizHourLog, portVertHourLog;
    Flt32 stbdVertHourLog,  fwdLatHourLog,    aftLatHourLog;
    Flt32 backupLightHourLog;

    Flt32 lightHourLog[NUM_LIGHTS]      = {0.0};
    Int32 lightCycleCount[NUM_LIGHTS]   = {0};
    switchStatus lightState[NUM_LIGHTS] = {SWITCH_OFF};

    struct                          /* Data manager Item Handles            */
    {
        DM_Item gyroHourLog;        /* Gyro compass Hour Log                */
        DM_Item vehicleHourLog;     /* Vehicle Powered Up Hour Log          */
        DM_Item submergedHourLog;   /* Vehicle Submerged Hour Log           */

        DM_Item portHorizHourLog;   /* Port Horizontal Thruster Hour Log    */
        DM_Item stbdHorizHourLog;   /* Port Horizontal Thruster Hour Log    */
        DM_Item portVertHourLog;    /* Port Vertical Thruster Hour Log      */
        DM_Item stbdVertHourLog;    /* Stbd Vertical Thruster Hour Log      */
        DM_Item fwdLatHourLog;      /* Forward Lateral Thruster Hour Log    */
        DM_Item aftLatHourLog;      /* Port Horizontal Thruster Hour Log    */

        DM_Item vbMotorHourLog;     /* Variable Bouyancy Motor Hour Log     */
        DM_Item backupLightHourLog; /* Backup Light Hour Log                */
        DM_Item lightHourLog[NUM_LIGHTS];     /* Light Hour Logs            */
        DM_Item lightCycleCount[NUM_LIGHTS];  /* Light Cycle Count          */

        DM_Item vehicleInWater;     /* Vehicle Submerged Status Flag        */
        DM_Item gyroPwrSwitch;      /* Gyro compass Power Switch            */
        DM_Item portHorizPwrSwitch; /* Port Horizontal Power Switch         */
        DM_Item stbdHorizPwrSwitch; /* Stbd Horizontal Power Switch         */
        DM_Item portVertPwrSwitch;  /* Port Horizontal Power Switch         */
        DM_Item stbdVertPwrSwitch;  /* Stbd Horizontal Power Switch         */
        DM_Item fwdLatPwrSwitch;    /* Forward Lateral Power Switch         */
        DM_Item aftLatPwrSwitch;    /* Aft Lateral Power Switch             */
        DM_Item vbMotorPwrSwitch;   /* VB System Power Switch               */

        DM_Item backupLightSwitch;  /* Backup Light Power Switch            */
        DM_Item lightSwitch[NUM_LIGHTS];/* Light Power Switches             */
    } dmItems;


    dmItemList hourLogDmInit[] =    /* Data Manager Item Table for init     */

      { { &dmItems.gyroPwrSwitch,        "Gyro Power Switch",
                GYRO_SWITCH_STATUS_DM,                DM_ENUM, 1 },

        { &dmItems.portHorizPwrSwitch,   "Port Horiz Thruster Power Switch",
                THRUSTER_PORT_HORIZ_SWITCH_STATUS_DM, DM_ENUM, 1 },

        { &dmItems.stbdHorizPwrSwitch,   "Stbd Horiz Thruster Power Switch",
                THRUSTER_STBD_HORIZ_SWITCH_STATUS_DM, DM_ENUM, 1 },

        { &dmItems.portVertPwrSwitch,    "Port Vert Thruster Power Switch",
                THRUSTER_PORT_VERT_SWITCH_STATUS_DM,  DM_ENUM, 1 },

        { &dmItems.stbdVertPwrSwitch,    "Stbd Vert Thruster Power Switch",
                THRUSTER_STBD_VERT_SWITCH_STATUS_DM,  DM_ENUM, 1 },

        { &dmItems.fwdLatPwrSwitch,    "Forward Lateral Thruster Power Switch",
                THRUSTER_FWD_LAT_SWITCH_STATUS_DM,    DM_ENUM, 1 },

        { &dmItems.aftLatPwrSwitch,      "Aft Lateral Thruster Power Switch",
                THRUSTER_AFT_LAT_SWITCH_STATUS_DM,    DM_ENUM, 1 },

        { &dmItems.vbMotorPwrSwitch,     "V.B. System Motor Power Switch",
                VB_MOTOR_SWITCH_STATUS_DM,            DM_ENUM, 1 },

        { &dmItems.backupLightSwitch,    "Backup Light Power Switch",
                BACKUP_LIGHT_SWITCH_STATUS_DM,        DM_ENUM, 1 },

        { &dmItems.lightSwitch[0],       "Light 0 Power Switch",
                LIGHT_0_SWITCH_STATUS_DM,             DM_ENUM, 1 },

        { &dmItems.lightSwitch[1],       "Light 1 Power Switch",
                LIGHT_1_SWITCH_STATUS_DM,             DM_ENUM, 1 },

        { &dmItems.lightSwitch[2],       "Light 2 Power Switch",
                LIGHT_2_SWITCH_STATUS_DM,             DM_ENUM, 1 },

        { &dmItems.lightSwitch[3],       "Light 3 Power Switch",
                LIGHT_3_SWITCH_STATUS_DM,             DM_ENUM, 1 },

        { &dmItems.lightSwitch[4],       "Light 4 Power Switch",
                LIGHT_4_SWITCH_STATUS_DM,             DM_ENUM, 1 },

        { &dmItems.lightSwitch[5],       "Light 5 Power Switch",
                LIGHT_5_SWITCH_STATUS_DM,             DM_ENUM, 1 },

        { NO_ITEM, NULL, NULL, DM_ENDT, 0 } };

                                    /* Set hour log task priority            */
    taskPrioritySet(taskIdSelf(), HOUR_LOG_PRIORITY);

    timeNow = time ( (time_t *) 0); /* Read real-time clock for boot time    */
    bootTime = gmtime (&timeNow);
    bootTimeString = asctime(bootTime);

                                    /* Create wakeup semaphore               */
    if ((wakeupSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == NULL )
    {
        logMsg("Hour Log Task: Error creating semaphore\n");
        return;
    } /* if */
                                    /* Clear Data Manager Item handles       */
    bzero(&dmItems, sizeof(dmItems));

                                    /* Initialize DMgr Items from table      */
    if (initMicroDmItemList( hourLogDmInit, "", "Hour Log" )
        != OK)
        return(ERROR);              /* Error occurred so print message & exit*/

    dmItems.vehicleInWater =
        initMicroDmItem(TIBURON_DM_PREFIX, TIBURON_IN_WATER_DM, DM_MBOOL, 1);

    dmItems.vehicleHourLog =
        initMicroDmItem(TIBURON_DM_PREFIX, TIBURON_POWER_ON_HOUR_LOG_DM,
        DM_FLT32, 1);

    dmItems.submergedHourLog =
        initMicroDmItem(TIBURON_DM_PREFIX, TIBURON_IN_WATER_HOUR_LOG_DM,
        DM_FLT32, 1);

    dmItems.gyroHourLog =
        initMicroDmItem(SENSOR_DM_PREFIX, GYRO_HOUR_LOG_DM, DM_FLT32, 1);



    dmItems.portHorizHourLog =
        initMicroDmItem(PORT_HORIZ_THRUSTER_DM, HOUR_LOG_DM, DM_FLT32, 1);

    dmItems.stbdHorizHourLog =
        initMicroDmItem(STBD_HORIZ_THRUSTER_DM, HOUR_LOG_DM, DM_FLT32, 1);

    dmItems.portVertHourLog =
        initMicroDmItem(PORT_VERT_THRUSTER_DM, HOUR_LOG_DM, DM_FLT32, 1);

    dmItems.stbdVertHourLog =
        initMicroDmItem(STBD_VERT_THRUSTER_DM, HOUR_LOG_DM, DM_FLT32, 1);

    dmItems.fwdLatHourLog =
        initMicroDmItem(FWD_LATERAL_THRUSTER_DM, HOUR_LOG_DM, DM_FLT32, 1);

    dmItems.aftLatHourLog =
        initMicroDmItem(AFT_LATERAL_THRUSTER_DM, HOUR_LOG_DM, DM_FLT32, 1);

    dmItems.vbMotorHourLog =
        initMicroDmItem(VB_MOTOR_DM_PREFIX, HOUR_LOG_DM, DM_FLT32, 1);

    dmItems.backupLightHourLog = initMicroDmItem(TIBURON_DM_PREFIX,
        BACKUP_LIGHT_HOUR_LOG_DM, DM_FLT32, 1);

                                    /* This task a provider of hour logs    */
    dm_start_provider(dmItems.vehicleHourLog,     HOUR_LOG_DM_RATE);
    dm_start_provider(dmItems.submergedHourLog,   HOUR_LOG_DM_RATE);
    dm_start_provider(dmItems.gyroHourLog,        HOUR_LOG_DM_RATE);
    dm_start_provider(dmItems.portHorizHourLog,   HOUR_LOG_DM_RATE);
    dm_start_provider(dmItems.stbdHorizHourLog,   HOUR_LOG_DM_RATE);
    dm_start_provider(dmItems.portVertHourLog,    HOUR_LOG_DM_RATE);
    dm_start_provider(dmItems.stbdVertHourLog,    HOUR_LOG_DM_RATE);
    dm_start_provider(dmItems.fwdLatHourLog,      HOUR_LOG_DM_RATE);
    dm_start_provider(dmItems.aftLatHourLog,      HOUR_LOG_DM_RATE);
    dm_start_provider(dmItems.vbMotorHourLog,     HOUR_LOG_DM_RATE);
    dm_start_provider(dmItems.backupLightHourLog, HOUR_LOG_DM_RATE);

                                   /* This task is a consumer of switch states*/
    dm_start_consumer(dmItems.gyroPwrSwitch,      DM_STATIC, wakeupSem);
    dm_start_consumer(dmItems.vehicleInWater,     DM_STATIC, wakeupSem);
    dm_start_consumer(dmItems.portHorizPwrSwitch, DM_STATIC, wakeupSem);
    dm_start_consumer(dmItems.stbdHorizPwrSwitch, DM_STATIC, wakeupSem);
    dm_start_consumer(dmItems.portVertPwrSwitch,  DM_STATIC, wakeupSem);
    dm_start_consumer(dmItems.stbdVertPwrSwitch,  DM_STATIC, wakeupSem);
    dm_start_consumer(dmItems.fwdLatPwrSwitch,    DM_STATIC, wakeupSem);
    dm_start_consumer(dmItems.aftLatPwrSwitch,    DM_STATIC, wakeupSem);
    dm_start_consumer(dmItems.vbMotorPwrSwitch,   DM_STATIC, wakeupSem);
    dm_start_consumer(dmItems.backupLightSwitch,  DM_STATIC, wakeupSem);


    for (light = 0; light < NUM_LIGHTS; light++)
    {
        sprintf(itemPrefix, "%sLIGHT%d.", LIGHTING_IBC_DM_PREFIX, light);

        dmItems.lightHourLog[light] =
            initMicroDmItem(itemPrefix, HOUR_LOG_DM, DM_FLT32, 1);

        dmItems.lightCycleCount[light] =
            initMicroDmItem(itemPrefix, CYCLE_LOG_DM, DM_INT32, 1);

        dm_start_provider(dmItems.lightHourLog[light], HOUR_LOG_DM_RATE);
        dm_start_consumer(dmItems.lightSwitch[light],  DM_STATIC, wakeupSem);
    } /* for */

    logMsg("Hour logging interval: %d minutes\n", HOUR_LOG_UPDATE_RATE);

                                   /* Zero elapsed all time values           */
    vehicleHourLog   = submergedHourLog = gyroHourLog =
    portHorizHourLog = stbdHorizHourLog = portVertHourLog =
    stbdVertHourLog  = fwdLatHourLog    = aftLatHourLog =
    vbMotorHourLog   = backupLightHourLog = 0.0;

    if ( (logFile = fopen(ELAPSED_HOUR_LOG, "r")) != NULL )
    {                             /* Load initial values from log file       */
        fgets(tempBuf, 80, logFile);
        fscanf(logFile, "%*s%*s%*s%f%*s\n",       &vehicleHourLog);
        fscanf(logFile, "%*s%*s%*s%f%*s\n",       &submergedHourLog);
        fscanf(logFile, "%*s%*s%*s%f%*s\n",       &gyroHourLog);
        fscanf(logFile, "%*s%*s%*s%*s%*s%f%*s\n", &portHorizHourLog);
        fscanf(logFile, "%*s%*s%*s%*s%*s%f%*s\n", &stbdHorizHourLog);
        fscanf(logFile, "%*s%*s%*s%*s%*s%f%*s\n", &portVertHourLog);
        fscanf(logFile, "%*s%*s%*s%*s%*s%f%*s\n", &stbdVertHourLog);
        fscanf(logFile, "%*s%*s%*s%*s%*s%f%*s\n", &fwdLatHourLog);
        fscanf(logFile, "%*s%*s%*s%*s%*s%f%*s\n", &aftLatHourLog);
        fscanf(logFile, "%*s%*s%*s%*s%*s%f%*s\n", &vbMotorHourLog);
        fscanf(logFile, "%*s%*s%*s%*s%f%*s\n",    &backupLightHourLog);

        for (light = 0; light < NUM_LIGHTS; light++)
            fscanf(logFile, "%*s%*s%*s%f%*s\n", &lightHourLog[light]);


        for (light = 0; light < NUM_LIGHTS; light++)
            fscanf(logFile, "%*s%*s%*s%d%*s\n", &lightCycleCount[light]);

        fclose(logFile);
    } /* if */
                                    /* Convert rate from minutes to ticks    */
    updateTicks = HOUR_LOG_UPDATE_RATE * 60 * sysClkRateGet();

    startTime = time ( (time_t *) 0); /* Read real-time clock in seconds     */

    FOREVER
    {                               /* Pend until either a sem timeout or    */
                                    /* a Data Manager Item is written        */
        semTake(wakeupSem, updateTicks);

                                        /* calculate elapsed time            */
        timeNow = time ( (time_t *) 0); /* Read real-time clock in seconds   */
        resolution = ((Flt32) (timeNow - startTime)) / (60 * 60);
        startTime = timeNow;

        if ( (logFile = fopen(ELAPSED_HOUR_LOG, "w")) == NULL )
        {
            logMsg( "Cannot open Elapsed Time file %s\n", ELAPSED_HOUR_LOG );
            return (ERROR);        /* DM automatically cleans up on task exit*/
        } /* if */

        fprintf(logFile, "Vehicle reboot at %s", bootTimeString);

        updateElapsedTime(NO_ITEM, dmItems.vehicleHourLog,
            resolution, &vehicleHourLog, "Vehicle on time");

        updateSubmergedTime(dmItems.vehicleInWater, dmItems.submergedHourLog,
            resolution, &submergedHourLog, "Vehicle Submerged Time");

        updateElapsedTime(dmItems.gyroPwrSwitch, dmItems.gyroHourLog,
            resolution, &gyroHourLog, "Gyro on time");

        updateElapsedTime(dmItems.portHorizPwrSwitch, dmItems.portHorizHourLog,
            resolution, &portHorizHourLog, "Port Horiz Thruster on time");

        updateElapsedTime(dmItems.stbdHorizPwrSwitch, dmItems.stbdHorizHourLog,
            resolution, &stbdHorizHourLog, "Stbd Horiz Thruster on time");

        updateElapsedTime(dmItems.portVertPwrSwitch,  dmItems.portVertHourLog,
            resolution, &portVertHourLog,  "Port Vert Thruster on time");

        updateElapsedTime(dmItems.stbdVertPwrSwitch,  dmItems.stbdVertHourLog,
            resolution, &stbdVertHourLog,  "Stbd Vert Thruster on time");

        updateElapsedTime(dmItems.fwdLatPwrSwitch,    dmItems.fwdLatHourLog,
            resolution, &fwdLatHourLog,  "Fwd Lateral Thruster on time");

        updateElapsedTime(dmItems.aftLatPwrSwitch,    dmItems.aftLatHourLog,
            resolution, &aftLatHourLog,  "Aft Lateral Thruster on time");

        updateElapsedTime(dmItems.vbMotorPwrSwitch,   dmItems.vbMotorHourLog,
            resolution, &vbMotorHourLog, "VB System Motor on time");

        updateElapsedTime(dmItems.backupLightSwitch,
            dmItems.backupLightHourLog, resolution, &backupLightHourLog,
            "Backup Light on time");

        for (light = 0; light < NUM_LIGHTS; light++)
        {
            sprintf(tempBuf, "Light %d on time", light);
            updateElapsedTime(dmItems.lightSwitch[light],
                dmItems.lightHourLog[light], resolution, &lightHourLog[light],
                tempBuf);

        } /* for */

        for (light = 0; light < NUM_LIGHTS; light++)
        {
            sprintf(tempBuf, "Light %d", light);
            updateCycleCount(dmItems.lightSwitch[light],
                          dmItems.lightCycleCount[light],
                          &lightState[light], &lightCycleCount[light], tempBuf);
        } /* for */

        fclose(logFile);
    } /* FOREVER */
} /* hourLogTask() */




