/****************************************************************************/
/* Copyright 2010 MBARI.                                                    */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/

#include <p24fxxxx.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "actions.h"
#include "errors.h"
#include "parser.h"
#include "serial.h"
#include "spi.h"
#include "data_flash.h"
#include "ex_rtc.h"
#include "sys_timer.h"
#include "config.h"
#include "tasks.h"

#include "sys_defs.h"

extern int timeLapseMode;
extern int debugMode;
extern int timeLapseImageState;
extern int timeLapseVideoState;


static char msg_buff[64];
static ConfigData configData;

/****************************************************************************/
/*                               Root commands                              */
/****************************************************************************/
int actGetCmd(char* s)
{
    return prsParse(s, cmdsGet, ERR_NO_SUB_COMMAND);
}

int actSetCmd(char* s)
{
    return prsParse(s, cmdsSet, ERR_NO_SUB_COMMAND);
}

int actClrCmd(char* s)
{
    return prsParse(s, cmdsClr, ERR_NO_SUB_COMMAND);
}

int actTimeCmd(char* s)
{
    rtcTimeDateStr(msg_buff);
    serPutString(SER_CONSOLE, msg_buff);

    serPutString(SER_CONSOLE, "\r\n");
    
    return ERR_SUCCESS;
}

int actHelpCmd(char* s)
{
    serPutString(SER_CONSOLE, "HELP - display this menu\r\n");
    serPutString(SER_CONSOLE, "TIME - display current date and time\r\n");
    serPutString(SER_CONSOLE, "RESET - reset the controller\r\n");
    serPutString(SER_CONSOLE, "PARAM - show current config parameters\r\n");
    serPutString(SER_CONSOLE, "SAVE - save current config parameters\r\n");
    serPutString(SER_CONSOLE, "DEFAULT - restore config parameters to defaults\r\n");
    serPutString(SER_CONSOLE, "BATT - measure the battery voltage\r\n");
    serPutString(SER_CONSOLE, "LANC MODE - Ctrl-L to enter, Ctrl-X to exit\r\n");

    serPutString(SER_CONSOLE, "CAM PWR - turn camera power on or off\r\n");
    serPutString(SER_CONSOLE, "LED1 PWR - turn LED light 1 power on or off\r\n");
    serPutString(SER_CONSOLE, "LED2 PWR - turn LED light 2 power on or off\r\n");
    serPutString(SER_CONSOLE, "HDMI PWR - turn HDMI to NTSC converter power on or off\r\n");
    serPutString(SER_CONSOLE, "STROBE PWR - turn strobe power on or off\r\n");
    serPutString(SER_CONSOLE, "INST PWR - turn instrument power on or off\r\n");
    serPutString(SER_CONSOLE, "INST2 PWR - turn instrument(2) power on or off\r\n");
    
    serPutString(SER_CONSOLE, "GET IMAGE - trigger camera image capture\r\n");
    serPutString(SER_CONSOLE, "GET VIDEO - trigger camera video capture\r\n");
    serPutString(SER_CONSOLE, "GET TRIG1 - get state of trigger input 1\r\n");
    serPutString(SER_CONSOLE, "GET TRIG2 - get state of trigger input 2\r\n");

    serPutString(SER_CONSOLE, "SET TIME - set current time MM/DD/YY HH:MM:SS DAY\r\n");
    serPutString(SER_CONSOLE, "SET CAPTURE MODE - set capture mode [OFF|IMG|VID]\r\n");
    serPutString(SER_CONSOLE, "SET DEPLOY DELAY - set deployment delay in minutes\r\n");
    serPutString(SER_CONSOLE, "SET DEPLOY DURATION - set deployment duration in minutes\r\n");
    serPutString(SER_CONSOLE, "SET SAMPLE INTERVAL - set sample interval in minutes\r\n");
    serPutString(SER_CONSOLE, "SET VIDEO DURATION - set video duration in seconds\r\n");
    serPutString(SER_CONSOLE, "SET BATT LEVEL - set minimum operating batt level \r\n");

    return ERR_SUCCESS;
}

int actResetCmd(char* s)
{
    asm("reset");
    return ERR_SUCCESS;
}

int actSaveCmd(char* s)
{
    configData.bootFlag = DEFAULT_BOOT_FLAG;
    configData.captureMode = tskGetCaptureMode();
    configData.startOfDeploy = tskGetStartDeploy();
    configData.lenOfDeploy = tskGetLenDeploy();
    configData.sampleInterval = tskGetSampleInt();
    configData.lenOfVideo = tskGetVidLen();
    configData.battLevel = tskGetBattLevel();

    /* write the config to flash memory */
    cfgWrite(&configData);

    return ERR_SUCCESS;
}

#define DEFAULT     "[DFLT]"
#define CHANGED     "      "

int actParamCmd(char* s)
{
    int mode;
    unsigned long val;

    char* default_str;
    char* mode_str;
    
    /* capture mode */
    mode = tskGetCaptureMode();
    
    if ( mode == CAPTURE_MODE_DEF )
        default_str = DEFAULT;
    else
        default_str = CHANGED;

    if ( mode == CAPTURE_MODE_OFF )
        mode_str = "OFF";
    else if ( mode == CAPTURE_MODE_IMG )
        mode_str = "IMG";
    else if ( mode == CAPTURE_MODE_VID )
        mode_str = "VID";
    else
        mode_str = "???";

    sprintf(msg_buff, "CAPTURE MODE    %s : %s\r\n", default_str, mode_str);
    serPutString(SER_CONSOLE, msg_buff);

    /* start deploy */
    val = tskGetStartDeploy(); 

    if ( val == START_DEPLOY_DEF )
        default_str = DEFAULT;
    else
        default_str = CHANGED;

    sprintf(msg_buff, "DEPLOY DELAY    %s : %lu MIN\r\n", default_str, val);
    serPutString(SER_CONSOLE, msg_buff);
    
    /* deploy length */
    val = tskGetLenDeploy(); 

    if ( val == LEN_DEPLOY_DEF )
        default_str = DEFAULT;
    else
        default_str = CHANGED;

    sprintf(msg_buff, "DEPLOY DURATION %s : %lu MIN\r\n", default_str, val);
    serPutString(SER_CONSOLE, msg_buff);

    /* sample interval */
    val = tskGetSampleInt(); 

    if ( val == SAMPLE_INT_DEF )
        default_str = DEFAULT;
    else
        default_str = CHANGED;

    sprintf(msg_buff, "SAMPLE INTERVAL %s : %lu MIN\r\n", default_str, val);
    serPutString(SER_CONSOLE, msg_buff);
    
    /* video length */
    val = tskGetVidLen(); 

    if ( val == VIDEO_LEN_DEF )
        default_str = DEFAULT;
    else
        default_str = CHANGED;

    sprintf(msg_buff, "VIDEO DURATION  %s : %lu SEC\r\n", default_str, val);
    serPutString(SER_CONSOLE, msg_buff);
    
    /* batt level */
    val = tskGetBattLevel(); 

    if ( val == BATT_LEVEL_DEF )
        default_str = DEFAULT;
    else
        default_str = CHANGED;

    sprintf(msg_buff, "BATT LEVEL      %s : %lu mV\r\n", default_str, val);
    serPutString(SER_CONSOLE, msg_buff);
    
    return ERR_SUCCESS;
}

int actDefaultCmd(char* s)
{
    tskSetCaptureMode(CAPTURE_MODE_DEF);
    tskSetStartDeploy(START_DEPLOY_DEF);
    tskSetLenDeploy(LEN_DEPLOY_DEF);
    tskSetSampleInt(SAMPLE_INT_DEF);
    tskSetVidLen(VIDEO_LEN_DEF);
    tskSetBattLevel(BATT_LEVEL_DEF);

    return ERR_SUCCESS;
}

int actBattCmd(char* s)
{
    sprintf(msg_buff, "BATTERY VOLT : %u mV\r\n", tskBattVolt());
    serPutString(SER_CONSOLE, msg_buff);
    
    return ERR_SUCCESS;
}

int actStatCmd(char* s)
{
    tskShowStatus();
    
    return ERR_SUCCESS;
}

int actCamPwrCmd(char* s)
{
    if ( prsNameMatch(s, "ON") )
    {
        serPutString(SER_CONSOLE, "CAM PWR ON\r\n");
        _LATF0 = 1;
    }
    else
    {
        serPutString(SER_CONSOLE, "CAM PWR OFF\r\n");
        _LATF0 = 0;
    }

    return ERR_SUCCESS;
}

int actLed1Cmd(char* s)
{
    if ( prsNameMatch(s, "ON") )
    {
        serPutString(SER_CONSOLE, "LED1 PWR ON\r\n");
        _LATB12 = 1;
    }
    else
    {
        serPutString(SER_CONSOLE, "LED1 PWR OFF\r\n");
        _LATB12 = 0;
    }

    return ERR_SUCCESS;
}

int actLed2Cmd(char* s)
{
    if ( prsNameMatch(s, "ON") )
    {
        serPutString(SER_CONSOLE, "LED2 PWR ON\r\n");
        _LATB13 = 1;
    }
    else
    {
        serPutString(SER_CONSOLE, "LED2 PWR OFF\r\n");
        _LATB13 = 0;
    }

    return ERR_SUCCESS;
}

int actVidPwrCmd(char* s)
{
    if ( prsNameMatch(s, "ON") )
    {
        serPutString(SER_CONSOLE, "HDMI PWR ON\r\n");
        _LATF1 = 1;
    }
    else
    {
        serPutString(SER_CONSOLE, "HDMI PWR OFF\r\n");
        _LATF1 = 0;
    }

    return ERR_SUCCESS;
}

int actStrobeCmd(char* s)
{
    if ( prsNameMatch(s, "ON") )
    {
        serPutString(SER_CONSOLE, "STROBE PWR ON\r\n");
        _LATC13 = 1;
    }
    else
    {
        serPutString(SER_CONSOLE, "STROBE PWR OFF\r\n");
        _LATC13 = 0;
    }

    return ERR_SUCCESS;
}

int actInst1Cmd(char* s)
{
    if ( prsNameMatch(s, "ON") )
    {
        serPutString(SER_CONSOLE, "INST PWR ON\r\n");
        _LATC14 = 1;
    }
    else
    {
        serPutString(SER_CONSOLE, "INST PWR OFF\r\n");
        _LATC14 = 0;
    }

    return ERR_SUCCESS;
}
    
int actInst2Cmd(char* s)
{
    if ( prsNameMatch(s, "ON") )
    {
        serPutString(SER_CONSOLE, "INST2 PWR ON\r\n");
        _LATB14 = 1;
    }
    else
    {
        serPutString(SER_CONSOLE, "INST2 PWR OFF\r\n");
        _LATB14 = 0;
    }

    return ERR_SUCCESS;
}

int actDebugCmd(char* s)
{
    if ( prsNameMatch(s, "ON") )
    {
        debugMode = 1;
        serPutString(SER_CONSOLE, "DEBUG MODE IS ON\r\n");
        return ERR_SUCCESS;
    }

    if ( prsNameMatch(s, "OFF") )
    {
        debugMode = 0;
        serPutString(SER_CONSOLE, "DEBUG MODE IS OFF\r\n");
        return ERR_SUCCESS;
    }

    serPutString(SER_CONSOLE, "DEBUG MODE IS ");
    
    if ( debugMode )
        serPutString(SER_CONSOLE, "ON");
    else
        serPutString(SER_CONSOLE, "OFF");

    serPutString(SER_CONSOLE, "\r\n");
    
    return ERR_SUCCESS;

}

/* debug command(s) below */
int actHelloKittyCmd(char* s)
{

#if 0
/* hidden help */
int actHelloKittyCmd(char* s, int show_help)
    
    if ( show_help )
        return ERR_SUCCESS;
#endif


    serPutString(SER_CONSOLE, "MEOW\r\n");
    return ERR_SUCCESS;
}

int actMemEraseCmd(char* s)
{
    dmErase();
    
    return ERR_SUCCESS;
}

int actMemWriteCmd(char* s)
{
    dmPutString(s);    
    dmPutString("\r\n");    
    
    return ERR_SUCCESS;
}

#define READ_CHUNK  16
int actMemReadCmd(char* s)
{
    int i;
    int read_complete = FALSE;
    unsigned long read_ptr = 0;

    while (!read_complete)
    {
        /* read a chunk of bytes */
        dmRead(read_ptr, msg_buff, READ_CHUNK);
        read_ptr += READ_CHUNK; 
        
        i = 0;
        while ( i < READ_CHUNK )
        {
            if ( msg_buff[i] & 0x80 )
            {
                read_complete = TRUE;
                i = READ_CHUNK;
            }
            else
            {
                if ( serPutByte(SER_CONSOLE, (unsigned char)msg_buff[i]) )
                    ++i;
            }
        }
    }

    serPutString(SER_CONSOLE, "\r\n");
        
    return ERR_SUCCESS;
}

#if 0
int actUsedMemCmd(char* s)
{
    int i;
    int read_complete = FALSE;
    unsigned long read_ptr = 0;
    long byte_count = 0;

    while (!read_complete)
    {
        /* read a chunk of bytes */
        dmRead(read_ptr, msg_buff, READ_CHUNK);
        read_ptr += READ_CHUNK; 
        
        i = 0;
        while ( i < READ_CHUNK )
        {
            if ( msg_buff[i] & 0x80 )
            {
                read_complete = TRUE;
                i = READ_CHUNK;
            }
            else
            {
                ++byte_count;
                ++i;
            }
        }

        /* make sure you ping all the tasks */
        taskExecute(ALL_TASK);
    }

    sprintf(msg_buff, "MEMORY USED %ld bytes\r\n", byte_count);
    serPutString(SER_CONSOLE, msg_buff);
        
    return ERR_SUCCESS;
}
#endif

int actTest1Cmd(char* s)
{
    time_t t1, t2;
    struct tm *currtime;
    double midnight;
   
    time(&t1);
    currtime = localtime(&t1);

    currtime->tm_sec = 0;
    currtime->tm_min = 0;
    currtime->tm_hour = 0;
    currtime->tm_mday++;
    
    t2 = mktime(currtime);

    midnight = difftime(t1, t2);

    sprintf(msg_buff, "There are %f seconds until midnight.\r\n", midnight);
    serPutString(SER_CONSOLE, msg_buff);

    return ERR_SUCCESS;
}

int actTest2Cmd(char* s)
{
    int d, m, y, doy;

    sscanf(s, "%d %d %d", &d, &m, &y);

    doy = rtcDmyToDoy(d, m, y);

    sprintf(msg_buff, "rtcDmyToDoy(%d, %d, %d) = %d\r\n", d, m, y,  doy);
    serPutString(SER_CONSOLE, msg_buff);
    
    return ERR_SUCCESS;
}

int actTest3Cmd(char* s)
{
    return ERR_SUCCESS;
}

int actTest4Cmd(char* s)
{
    return ERR_SUCCESS;
}

/****************************************************************************/
/*                               Get commands                               */
/****************************************************************************/
int actGetImgCmd(char* s)
{
    if ( tskStartImageCapture() )
        return ERR_SUCCESS;
    
    if ( !tskImageCaptureReady() )
        serPutString(SER_CONSOLE, "ERR: IMAGE CAPTURE BUSY\r\n");

    if ( !tskVideoCaptureReady() )
        serPutString(SER_CONSOLE, "ERR: VIDEO CAPTURE BUSY\r\n");
    
    return ERR_SUCCESS;
}

int actGetVidCmd(char* s)
{
    if ( tskStartVideoCapture() )
        return ERR_SUCCESS;
    
    if ( !tskImageCaptureReady() )
        serPutString(SER_CONSOLE, "ERR: IMAGE CAPTURE BUSY\r\n");

    if ( !tskVideoCaptureReady() )
        serPutString(SER_CONSOLE, "ERR: VIDEO CAPTURE BUSY\r\n");
    
    return ERR_SUCCESS;
}

int actGetTrig1Cmd(char* s)
{
    serPutString(SER_CONSOLE, "TRIGGER 1: ");
    
    if ( _RD7 )
        serPutString(SER_CONSOLE, "ON\r\n");
    else
        serPutString(SER_CONSOLE, "OFF\r\n");
    
    return ERR_SUCCESS;
}

int actGetTrig2Cmd(char* s)
{
    serPutString(SER_CONSOLE, "TRIGGER 2: ");
    
    if ( _RD6 )
        serPutString(SER_CONSOLE, "ON\r\n");
    else
        serPutString(SER_CONSOLE, "OFF\r\n");


    return ERR_SUCCESS;
}


/****************************************************************************/
/*                               Set commands                               */
/****************************************************************************/
int actSetTimeCmd(char* s)
{
    int n;
    RtcTime rtc;

    rtc.seconds = 0;
    rtc.minutes = 0;
    rtc.hours = 0;
    rtc.day = 0;
    rtc.date = 0;
    rtc.month = 0;
    rtc.year = 0;

    n = sscanf(s, "%d/%d/%d %d:%d:%d %d", &rtc.month, &rtc.date, &rtc.year, 
               &rtc.hours, &rtc.minutes, &rtc.seconds, &rtc.day);

    if ( n < 7 )
    {
        serPutString(SER_CONSOLE, "ERR: BAD FORMAT\r\n");
        serPutString(SER_CONSOLE, "USAGE: MM/DD/YY HH:MM:SS DAY (");
        serPutString(SER_CONSOLE, "DAY = 1->Sun, 2->Mon, ... , 7->Sat)\r\n");
        return ERR_SUCCESS;
    }

    /* range check month */
    if ( (rtc.month < 1) || (rtc.month > 12) )
    {
        serPutString(SER_CONSOLE, "ERR: MONTH OUT OF RANGE (1 - 12)\r\n");
        return ERR_SUCCESS;
    }

    /* range check date */
    if ( (rtc.date < 1) || (rtc.date > 31) )
    {
        serPutString(SER_CONSOLE, "ERR: DAY OUT OF RANGE (1 - 31)\r\n");
        return ERR_SUCCESS;
    }

    /* range check year */
    if ( (rtc.year < 11) || (rtc.year > 99) )
    {
        serPutString(SER_CONSOLE, "ERR: YEAR OUT OF RANGE  (11 - 99)\r\n");
        return ERR_SUCCESS;
    }

    /* range check hour */
    if ( (rtc.hours < 0) || (rtc.hours > 23) )
    {
        serPutString(SER_CONSOLE, "ERR: HOURS OUT OF RANGE  (1 - 24)\r\n");
        return ERR_SUCCESS;
    }
    
    /* range check minutes */
    if ( (rtc.minutes < 0) || (rtc.minutes > 59) )
    {
        serPutString(SER_CONSOLE, "ERR: MINUTES OUT OF RANGE  (0 - 59)\r\n");
        return ERR_SUCCESS;
    }

    /* range check seconds */
    if ( (rtc.seconds < 0) || (rtc.seconds > 59) )
    {
        serPutString(SER_CONSOLE, "ERR: SECONDS OUT OF RANGE  (0 - 59)\r\n");
        return ERR_SUCCESS;
    }

    /* range check day */
    if ( (rtc.day < 1) || (rtc.day > 7) )
    {
        serPutString(SER_CONSOLE, "ERR: DAY OUT OF RANGE  (1 - 7)\r\n");
        return ERR_SUCCESS;
    }

    /* set the time */
    rtcSet(&rtc);

    /* show the user what you set the time to */
    rtcTimeDateStr(msg_buff);
    serPutString(SER_CONSOLE, "TIME SET TO: ");
    serPutString(SER_CONSOLE, msg_buff);
    serPutString(SER_CONSOLE, "\r\n");
    
    return ERR_SUCCESS;
}

int actSetCaptureModeCmd(char* s)
{
    if ( prsNameMatch(s, "OFF") )
         tskSetCaptureMode(CAPTURE_MODE_OFF);

    if ( prsNameMatch(s, "IMG") )
         tskSetCaptureMode(CAPTURE_MODE_IMG);
    
    if ( prsNameMatch(s, "VID") )
         tskSetCaptureMode(CAPTURE_MODE_VID);
    
    return ERR_SUCCESS;
}

int actSetStartDeployCmd(char* s)
{
    long val = atol(s);

    tskSetStartDeploy((unsigned long)val);
    
    return ERR_SUCCESS;
}

int actSetLenDeployCmd(char* s)
{
    long val = atol(s);

    tskSetLenDeploy((unsigned long)val);
    
    return ERR_SUCCESS;
}

int actSetSampleIntCmd(char* s)
{
    long val = atol(s);

    tskSetSampleInt((unsigned long)val);
    
    return ERR_SUCCESS;
}

int actSetVidLenCmd(char* s)
{
    long val = atol(s);

    tskSetVidLen((unsigned long)val);
    
    return ERR_SUCCESS;
}

int actSetBattLevelCmd(char* s)
{
    long val = atol(s);

    tskSetBattLevel((unsigned long)val);
    
    return ERR_SUCCESS;
}

/****************************************************************************/
/*                              Clear commands                              */
/****************************************************************************/
int actClrStubCmd(char* s)
{
    sprintf(msg_buff, "actClrStubCmd(%s)\r\n", s);
    serPutString(SER_CONSOLE, msg_buff);
    
    return ERR_SUCCESS;
}

