/****************************************************************************/
/* Copyright 2010 MBARI.                                                    */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
#include <p24fxxxx.h>
#include <stdio.h>

#include "tasks.h"
#include "dig_io.h"
#include "serial.h"
#include "ex_rtc.h"
#include "data_flash.h"
#include "sys_timer.h"
#include "sys_defs.h"

/* start task states */
#define START_TASK_INIT 0
#define INITIAL_WAIT    1
#define DVR_POWER       2
#define CAM_POWER       3
#define REC_WAIT        4
#define RECORD_ON       5
#define LIGHTS_POWER    6
#define TASK_COMPLETED  7

/* internal delay times in milliseconds */
#define REC_DELAY           60000L
#define DEFAULT_DELAY       1000L

/* stop delay variable */
static Timer stopDelayTimer;
static unsigned long stopDelay = (STOP_DELAY_DEF * 1000L);

/* start delay variable */
static unsigned long startDelay = (START_DELAY_DEF * 1000L);
static int startTaskState = START_TASK_INIT;

/* trig window variables */
static Timer trigWindowTimer;
static int trigWindowMode = TRIG_MODE_DEF;
static int trigWindowActive = FALSE;
static unsigned long trigWindowTime = (TRIG_WINDOW_DEF * 1000L);

/* time lapse variables */
static Timer timeLapseTimer;
static int timeLapseMode = TIME_LAPSE_MODE_DEF;
static int timeLapseState = OFF;
static unsigned long timeLapseOn = (TIME_LAPSE_ON_DEF * 1000L);
static unsigned long timeLapseOff = (TIME_LAPSE_OFF_DEF * 1000L);

/* task prototypes for local tasks */
void startTask();
void stopTask();
void triggerTask();
void timeLapseTask();

void taskInit()
{
    tmrCreate(&trigWindowTimer);
    tmrStart(&trigWindowTimer);

    tmrCreate(&stopDelayTimer);
    tmrStart(&stopDelayTimer);
    
    tmrCreate(&timeLapseTimer);
    tmrStart(&timeLapseTimer);
}

void taskShowStates()
{
    char buff[64];
    unsigned long val;

    /* show start task state */
    serPutString(SER_CONSOLE, "startTaskState = ");

    switch ( startTaskState )
    {
        case START_TASK_INIT: serPutString(SER_CONSOLE, "TASK_INIT"); break;
        case INITIAL_WAIT: serPutString(SER_CONSOLE, "INITIAL_WAIT"); break;
        case DVR_POWER: serPutString(SER_CONSOLE, "DVR_POWER"); break;
        case CAM_POWER: serPutString(SER_CONSOLE, "CAM_POWER"); break;
        case REC_WAIT: serPutString(SER_CONSOLE, "REC_WAIT"); break;
        case RECORD_ON: serPutString(SER_CONSOLE, "RECORD_ON"); break;
        case LIGHTS_POWER: serPutString(SER_CONSOLE, "LIGHTS_POWER"); break;
        case TASK_COMPLETED: serPutString(SER_CONSOLE, "TASK_COMPLETED"); break;
        default: serPutString(SER_CONSOLE, "UNKNOWN"); break;
    }

    serPutString(SER_CONSOLE, "\r\n\r\n");


    /* show trig window states and times */
    val = tmrRead(&trigWindowTimer) / 1000;
    sprintf(buff, "trigWindowTimer = %lu SECS\r\n", val);
    serPutString(SER_CONSOLE, buff);

    if ( trigWindowMode )
        serPutString(SER_CONSOLE, "trigWindowMode = TRUE\r\n");
    else
        serPutString(SER_CONSOLE, "trigWindowMode = FALSE\r\n");

    
    if ( trigWindowActive )
        serPutString(SER_CONSOLE, "trigWindowActive = TRUE\r\n");
    else
        serPutString(SER_CONSOLE, "trigWindowActive = FALSE\r\n");

    serPutString(SER_CONSOLE, "\r\n");

    /* show time lapse states and times */
    val = tmrRead(&timeLapseTimer) / 1000;
    sprintf(buff, "timeLapseTimer = %lu SECS\r\n", val);
    serPutString(SER_CONSOLE, buff);

    if ( timeLapseMode )
        serPutString(SER_CONSOLE, "timeLapseMode = TRUE\r\n");
    else
        serPutString(SER_CONSOLE, "timeLapseMode = FALSE\r\n");

    
    if ( timeLapseState )
        serPutString(SER_CONSOLE, "timeLapseState = TRUE\r\n");
    else
        serPutString(SER_CONSOLE, "timeLapseState = FALSE\r\n");

    serPutString(SER_CONSOLE, "\r\n");
}

void taskExecute(unsigned int tasks)
{
    if ( tasks & TMR_TASK )
        tmrTask();

    if ( tasks & STOP_TASK )
        stopTask();
    
    if ( tasks & START_TASK )
        startTask();

    if ( tasks & TRIGGER_TASK )
        triggerTask();
    
    if ( tasks & TIME_LAPSE_TASK )
        timeLapseTask();
}

void taskSetStartDelay(unsigned long delay)
{
    startDelay = delay;

    /* check bounds */
    if ( startDelay < START_DELAY_MIN )
        startDelay = START_DELAY_MIN;

    if ( startDelay > START_DELAY_MAX )
        startDelay = START_DELAY_MAX;

    /* conver delay to milliseconds */
    startDelay *= 1000L;
}

unsigned long taskGetStartDelay()
{
    return (startDelay / 1000L);
}

void taskSetStopDelay(unsigned long delay)
{
    stopDelay = delay;

    /* check bounds */
    if ( stopDelay < STOP_DELAY_MIN )
        stopDelay = STOP_DELAY_MIN;

    if ( stopDelay > STOP_DELAY_MAX )
        stopDelay = STOP_DELAY_MAX;

    /* conver delay to milliseconds */
    stopDelay *= 1000L;
}

unsigned long taskGetStopDelay()
{
    return (stopDelay / 1000L);
}

void taskSetTimeLapseOn(unsigned long delay)
{
    timeLapseOn = delay;

    /* check bounds */
    if ( timeLapseOn < TIME_LAPSE_ON_MIN )
        timeLapseOn = TIME_LAPSE_ON_MIN;

    if ( timeLapseOn > TIME_LAPSE_ON_MAX )
        timeLapseOn = TIME_LAPSE_ON_MAX;

    /* convert delay to milliseconds */
    timeLapseOn *= 1000L;
}

unsigned long taskGetTimeLapseOn()
{
    return (timeLapseOn / 1000L);
}

void taskSetTimeLapseOff(unsigned long delay)
{
    timeLapseOff = delay;

    /* check bounds */
    if ( timeLapseOff < TIME_LAPSE_OFF_MIN )
        timeLapseOff = TIME_LAPSE_OFF_MIN;

    if ( timeLapseOff > TIME_LAPSE_OFF_MAX )
        timeLapseOff = TIME_LAPSE_OFF_MAX;

    /* conver delay to milliseconds */
    timeLapseOff *= 1000L;
}

unsigned long taskGetTimeLapseOff()
{
    return (timeLapseOff / 1000L);
}

int taskSetTrigMode(int mode)
{
    if ( mode )
    {
        trigWindowMode = TRUE;
        /* end trigger window if active */
        tmrClear(&trigWindowTimer);
        trigWindowActive = FALSE;
        /* Stop DVR and power down light */
        if (startTaskState == TASK_COMPLETED)
        {
            digSetOutBit(DVR_REC, OFF);
            digSetOutBit(LIGHT_PWR, OFF);
        }
    }
    else
    {
        trigWindowMode = FALSE;
        /* end trigger window if active */
        tmrClear(&trigWindowTimer);
        trigWindowActive = FALSE;
        /* Start DVR and power up light */
        if (startTaskState == TASK_COMPLETED)
        {
            digSetOutBit(DVR_REC, ON);
            digSetOutBit(LIGHT_PWR, ON);
        }
    }

    return TRUE;
}

int taskGetTrigMode()
{
    return trigWindowMode;
}

int taskSetTimLapseMode(int mode)
{
    if ( mode )
    {
        timeLapseMode = TRUE;
        /* end trigger window if active */
        tmrClear(&timeLapseTimer);
        timeLapseState = ON;
        /* Start DVR and power up light */
        if (startTaskState == TASK_COMPLETED)
        {
            digSetOutBit(DVR_REC, ON);
            digSetOutBit(LIGHT_PWR, ON);
        }
    }
    else
    {
        timeLapseMode = FALSE;
        timeLapseState = OFF;

    }

    return TRUE;
}

int taskGetTimLapseMode()
{
    return timeLapseMode;
}

void taskSetTriggerWindow(unsigned long window)
{
    trigWindowTime = window;
    
    /* check bounds */
    if ( trigWindowTime < TRIG_WINDOW_MIN )
        trigWindowTime = TRIG_WINDOW_MIN;

    if ( trigWindowTime > TRIG_WINDOW_MAX )
        trigWindowTime = TRIG_WINDOW_MAX;

    /* conver delay to milliseconds */
    trigWindowTime *= 1000L;
}

unsigned long taskGetTriggerWindow()
{
    return (unsigned long)(trigWindowTime / 1000L);
}


/* pseudo tasks below */

void startTask()
{
    static Timer start_timer;

    /* if you're done, bail out */
    if ( startTaskState == TASK_COMPLETED)
        return;

    /* task init */
    if ( startTaskState == START_TASK_INIT )
    {
        tmrCreate(&start_timer);
        tmrStart(&start_timer);
        startTaskState = INITIAL_WAIT; 
    }

    /* wait state */
    if ( startTaskState == INITIAL_WAIT )
    {
        if ( tmrRead(&start_timer) < startDelay ) 
            return;
        
        /* clear time and jump to next state */
        tmrClear(&start_timer);
        startTaskState = DVR_POWER; 
    }

    /* power up DVR */
    if ( startTaskState == DVR_POWER )
    {
        /* turn on DVR power */
        digSetOutBit(DVR_PWR, ON);
        startTaskState = CAM_POWER; 
    }

    /* power up Camera */
    if ( startTaskState == CAM_POWER )
    {
        if ( tmrRead(&start_timer) < DEFAULT_DELAY ) 
            return;
        
        /* turn on Camera power */
        digSetOutBit(CAM_PWR, ON);
        
        /* clear time and jump to next state */
        tmrClear(&start_timer);
        startTaskState = REC_WAIT; 
    }

    /* wait a minute */
    if ( startTaskState == REC_WAIT )
    {
        if ( tmrRead(&start_timer) < REC_DELAY ) 
            return;
        
        /* clear time and jump to next state */
        tmrClear(&start_timer);
        startTaskState = RECORD_ON; 
    }

    /* end here if in trigger mode */
    if ( trigWindowMode )
    {
        /* clear time and goto end state */
        tmrClear(&start_timer);
        startTaskState = TASK_COMPLETED; 
        return;
    }

    /* start record */
    if ( startTaskState == RECORD_ON )
    {
        if ( tmrRead(&start_timer) < DEFAULT_DELAY ) 
            return;
        
        /* start recording */
        digSetOutBit(DVR_REC, ON);
        
        /* clear time and jump to next state */
        tmrClear(&start_timer);
        startTaskState = LIGHTS_POWER; 
    }

    /* power up lights lights */
    if ( startTaskState == LIGHTS_POWER )
    {
        if ( tmrRead(&start_timer) < DEFAULT_DELAY ) 
            return;
        
        /* turn on lights */
        digSetOutBit(LIGHT_PWR, ON);
        
        /* clear time and jump to next state */
        tmrClear(&start_timer);
        startTaskState = TASK_COMPLETED; 
    }

    return;
}

void stopTask()
{
    /* if the stop time has expired, shut everthing down */
    if ( (tmrRead(&stopDelayTimer) < stopDelay) || (stopDelay == 0) )
            return;

    /* disable trigger mode manually */
    trigWindowMode = FALSE;
    trigWindowActive = FALSE;
    tmrClear(&trigWindowTimer);

    /* disable time lapse mode */
    timeLapseMode = FALSE;

    /* stop recording */
    digSetOutBit(DVR_REC, OFF);

    /* wait a half a second after stop record */
    tmrDelayMs(500);

    /* shut everthing else down */
    digSetOutBit(DVR_PWR, OFF);
    tmrDelayMs(100);
    digSetOutBit(CAM_PWR, OFF);
    tmrDelayMs(100);
    digSetOutBit(LIGHT_PWR, OFF);
    tmrDelayMs(100);

    /* stop and clear the timer so you don't keep going through this loop */
    tmrStop(&stopDelayTimer);
    tmrClear(&stopDelayTimer);

    return;
}
void triggerTask()
{
    char buff[64];
    char tm_str[32];
    unsigned int trig_count;
    static unsigned int old_trigger_count = 0;

    trig_count = tmrGetTriggerCount(); 

    if ( trig_count > old_trigger_count )
    {
        old_trigger_count = trig_count;

        /* if in trigger mode, check trigger window */
        if ( trigWindowMode && (startTaskState == TASK_COMPLETED) )
        {
            trigWindowActive = TRUE;
            tmrClear(&trigWindowTimer);

            /* Sart DVR and power up light */
            digSetOutBit(DVR_REC, ON);
            digSetOutBit(LIGHT_PWR, ON);
        }

        /* grab the time stamp */
        rtcTimeStampStr(tm_str);
        sprintf(buff, "GOT TRIGGER %u AT %s\r\n", trig_count, tm_str);
        serPutString(SER_CONSOLE, buff);
        dmPutString(buff);
    }

    /* See if the trigger window has expired if you're in trigger mode */
    if ( trigWindowMode && (startTaskState == TASK_COMPLETED) )
    {
        if ( trigWindowActive )
        {
            if ( tmrRead(&trigWindowTimer) > trigWindowTime )
            {
                trigWindowActive = FALSE;

                /* Stop DVR and power down light if time lapse state is off */
                if ( !timeLapseState )
                {
                    digSetOutBit(DVR_REC, OFF);
                    digSetOutBit(LIGHT_PWR, OFF);
                }
            }
        }
    }
}

void timeLapseTask()
{
    if ( timeLapseMode && (startTaskState == TASK_COMPLETED) )
    {
        if ( timeLapseState )
        {
            if ( tmrRead(&timeLapseTimer) > timeLapseOn )
            {
                /* change state to off and shut off DVR and light */
                timeLapseState = OFF;
                tmrClear(&timeLapseTimer);
                
                /* do not shutoff lights and camera in trigger window */
                if ( !trigWindowActive )
                {
                    digSetOutBit(DVR_REC, OFF);
                    digSetOutBit(LIGHT_PWR, OFF);
                }
            }
        }
        else
        {
            if ( tmrRead(&timeLapseTimer) > timeLapseOff )
            {
                /* change state to on and turn on DVR and light */
                timeLapseState = ON;
                tmrClear(&timeLapseTimer);
                digSetOutBit(DVR_REC, ON);
                digSetOutBit(LIGHT_PWR, ON);
            }
        }
    }

    return;
}

