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

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

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

static char msg_buff[64];
static ConfigData configData;

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

int actHelpCmd(char* s)
{

    /* Root Commands */
    serPutString(SER_CONSOLE, "HELP - display this menu\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "READ MEM - dump the memory contents\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "USED MEM - memory currently in use\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "ERASE MEM - erase the memory\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "TIME - display current date and time\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "STATUS - get system status\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "RESET - reset the controller\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "SAVE - save parameters to flash memory\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "PARAM - show current parameters\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "DEFAULT - restore parameters to defaults\r\n");
    taskExecute(ALL_TASK);

    serPutString(SER_CONSOLE, "CAM ON - turn on camera power\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "CAM OFF - turn off camera power\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "LIGHT ON - turn on light power\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "LIGHT OFF - turn off light power\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "DVR ON - turn on DVR power\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "DVR OFF - turn off DVR power\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "START DVR|REC ON - start recording\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "STOP DVR|REC OFF - stop recording\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "TRIG MODE ON - enable trigger mode\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "TRIG MODE OFF - disable trigger mode\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "TL MODE ON - enable time lapse mode\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "TL MODE OFF - disable  time lapse mode\r\n");
    taskExecute(ALL_TASK);

    /* Set Commands */
    serPutString(SER_CONSOLE, "SET START DELAY - set start delay in secs\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "SET STOP DELAY - set stop delay in secs\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "SET DEBOUNCE - set debounce time in ms\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "SET HOLD OFF - set hold off time in secs\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "SET WINDOW - set trigger window in secs\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "SET TL ON - set time lapse on time in secs\r\n");
    taskExecute(ALL_TASK);
    serPutString(SER_CONSOLE, "SET TL OFF - set time lapse off time in secs\r\n");
    taskExecute(ALL_TASK);
    
    serPutString(SER_CONSOLE, "SET TIME - set current time MM/DD/YY HH:MM:SS DAY\r\n");
    taskExecute(ALL_TASK);

    return ERR_SUCCESS;
}

#define READ_CHUNK  16
int actReadMemCmd(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;
            }
        }

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

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

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;
}

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

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

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

int actStatus(char* s)
{
    unsigned int triggers = tmrGetTriggerCount();
    unsigned long ticks = tmrGetTicks();


    /* convert ticks to seconds */
    ticks /= 100L;


    serPutString(SER_CONSOLE, "DVR POWER   : ");
    if ( digGetOutBit(DVR_PWR) )
        serPutString(SER_CONSOLE, "ON\r\n");
    else
        serPutString(SER_CONSOLE, "OFF\r\n");

    serPutString(SER_CONSOLE, "CAM POWER   : ");
    if ( digGetOutBit(CAM_PWR) )
        serPutString(SER_CONSOLE, "ON\r\n");
    else
        serPutString(SER_CONSOLE, "OFF\r\n");
    
    serPutString(SER_CONSOLE, "LIGHT POWER : ");
    if ( digGetOutBit(LIGHT_PWR) )
        serPutString(SER_CONSOLE, "ON\r\n");
    else
        serPutString(SER_CONSOLE, "OFF\r\n");
    
    serPutString(SER_CONSOLE, "RECORDING   : ");
    if ( digGetOutBit(DVR_REC) )
        serPutString(SER_CONSOLE, "ON\r\n");
    else
        serPutString(SER_CONSOLE, "OFF\r\n");

    serPutString(SER_CONSOLE, "TRIGGER MODE: ");
    if ( taskGetTrigMode() )
        serPutString(SER_CONSOLE, "ENABLED\r\n");
    else
        serPutString(SER_CONSOLE, "DISABLED\r\n");

    serPutString(SER_CONSOLE, "TIME LAPSE  : ");
    if ( taskGetTimLapseMode() )
        serPutString(SER_CONSOLE, "ENABLED\r\n");
    else
        serPutString(SER_CONSOLE, "DISABLED\r\n");
    
    sprintf(msg_buff, "TRIGGERS    : %u\r\n", triggers);
    serPutString(SER_CONSOLE, msg_buff);
    
    sprintf(msg_buff, "UPTIME      : %lu SECS\r\n", ticks);
    serPutString(SER_CONSOLE, msg_buff);

    serPutString(SER_CONSOLE, "TIME        : ");
    rtcTimeDateStr(msg_buff);
    serPutString(SER_CONSOLE, msg_buff);
    serPutString(SER_CONSOLE, "\r\n");
    
    return ERR_SUCCESS;
}

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

int actSaveCmd(char* s)
{
    configData.bootFlag = DEFAULT_BOOT_FLAG;

    configData.triggerMode = taskGetTrigMode();
    configData.timeLapseMode = taskGetTimLapseMode();

    configData.trigHoldoff = tmrGetTrigHoldOff();
    configData.trigDebounce = tmrGetTrigDebounce();
    
    configData.stopDelay = taskGetStopDelay();    
    configData.startDelay = taskGetStartDelay();

    configData.triggerWindow = taskGetTriggerWindow();

    configData.timeLapseOn = taskGetTimeLapseOn();
    configData.timeLapseOff = taskGetTimeLapseOff();

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

    return ERR_SUCCESS;
}

#define DEFAULT     "[DFLT]"
#define CHANGED     "      "
#define MODE_ON     "ON"
#define MODE_OFF    "OFF"

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

    char* default_str;
    char* mode_str;
    
    /* trigger mode */
    mode = taskGetTrigMode();
    
    if ( mode == TRIG_MODE_DEF )
        default_str = DEFAULT;
    else
        default_str = CHANGED;

    if ( mode )
        mode_str = MODE_ON;
    else
        mode_str = MODE_OFF;

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

    /* timelapse mode */
    mode = taskGetTimLapseMode();
    
    if ( mode == TIME_LAPSE_MODE_DEF )
        default_str = DEFAULT;
    else
        default_str = CHANGED;

    if ( mode )
        mode_str = MODE_ON;
    else
        mode_str = MODE_OFF;

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

    /* start delay */
    val = taskGetStartDelay(); 

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

    sprintf(msg_buff, "START DELAY     %s : %lu SEC\r\n", default_str, val);
    serPutString(SER_CONSOLE, msg_buff);

    /* stop delay */
    val = taskGetStopDelay(); 

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

    sprintf(msg_buff, "STOP DELAY      %s : %lu SEC\r\n", default_str, val);
    serPutString(SER_CONSOLE, msg_buff);

    /* trigger debounce */
    val = tmrGetTrigDebounce(); 

    if ( val == DEBOUNCE_LEVEL_DEF )
        default_str = DEFAULT;
    else
        default_str = CHANGED;
    
    sprintf(msg_buff, "TRIG DEBOUNCE   %s : %lu MS\r\n", default_str, val);
    serPutString(SER_CONSOLE, msg_buff);
    
    /* trigger holdoff */
    val = tmrGetTrigHoldOff(); 

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

    sprintf(msg_buff, "TRIG HOLD OFF   %s : %lu SEC\r\n", default_str, val);
    serPutString(SER_CONSOLE, msg_buff);
    
    /* trigger window */
    val = taskGetTriggerWindow(); 

    if ( val == TRIG_WINDOW_DEF )
        default_str = DEFAULT;
    else
        default_str = CHANGED;
    
    sprintf(msg_buff, "TRIG WINDOW     %s : %lu SEC\r\n", default_str, val);
    serPutString(SER_CONSOLE, msg_buff);

    /* time lapse on time */
    val = taskGetTimeLapseOn(); 

    if ( val == TIME_LAPSE_ON_DEF )
        default_str = DEFAULT;
    else
        default_str = CHANGED;
    
    sprintf(msg_buff, "TIME LAPSE ON   %s : %lu SEC\r\n", default_str, val);
    serPutString(SER_CONSOLE, msg_buff);
    
    /* time lapse off time */
    val = taskGetTimeLapseOff(); 

    if ( val == TIME_LAPSE_OFF_DEF )
        default_str = DEFAULT;
    else
        default_str = CHANGED;
    
    sprintf(msg_buff, "TIME LAPSE OFF  %s : %lu SEC\r\n", default_str, val);
    serPutString(SER_CONSOLE, msg_buff);
    
    return ERR_SUCCESS;
}

int actDefaultCmd(char* s)
{
    taskSetTrigMode(TRIG_MODE_DEF);
    taskSetTimLapseMode(TIME_LAPSE_MODE_DEF);

    tmrSetTrigHoldOff(HOLDOFF_LEVEL_DEF);
    tmrSetTrigDebounce(DEBOUNCE_LEVEL_DEF);
    
    taskSetStopDelay(STOP_DELAY_DEF);    
    taskSetStartDelay(START_DELAY_DEF);

    taskSetTriggerWindow(TRIG_WINDOW_DEF);

    taskSetTimeLapseOn(TIME_LAPSE_ON_DEF);
    taskSetTimeLapseOff(TIME_LAPSE_OFF_DEF);

    return ERR_SUCCESS;
}

int actCameraOnCmd(char* s)
{
    serPutString(SER_CONSOLE, "CAMERA POWER ON\r\n");
    digSetOutBit(CAM_PWR, ON);
    			
    return ERR_SUCCESS;
}

int actCameraOffCmd(char* s)
{
    serPutString(SER_CONSOLE, "CAMERA POWER OFF\r\n");
    digSetOutBit(CAM_PWR, OFF);

    return ERR_SUCCESS;
}

int actLightOnCmd(char* s)
{
    serPutString(SER_CONSOLE, "LIGHT ON\r\n");
    digSetOutBit(LIGHT_PWR, ON);
        
    return ERR_SUCCESS;
}

int actLightOffCmd(char* s)
{
    serPutString(SER_CONSOLE, "LIGHT OFF\r\n");
    digSetOutBit(LIGHT_PWR, OFF);
    			
    return ERR_SUCCESS;
}

int actDvrOnCmd(char* s)
{
    serPutString(SER_CONSOLE, "DVR POWER ON\r\n");
    digSetOutBit(DVR_PWR, ON);
    			
    return ERR_SUCCESS;
}

int actDvrOffCmd(char* s)
{
    serPutString(SER_CONSOLE, "DVR POWER OFF\r\n");
    digSetOutBit(DVR_PWR, OFF);
    
    return ERR_SUCCESS;
}

int actDvrStartCmd(char* s)
{
    serPutString(SER_CONSOLE, "RECORD ON\r\n");
    digSetOutBit(DVR_REC, ON);

    return ERR_SUCCESS;
}

int actDvrStopCmd(char* s)
{
    serPutString(SER_CONSOLE, "RECORD OFF\r\n");
    digSetOutBit(DVR_REC, OFF);

    return ERR_SUCCESS;
}

int actTrigModeOnCmd(char* s)
{
    /* Enable trigger mode */
    if ( taskSetTrigMode(TRUE) )
    {
        serPutString(SER_CONSOLE, "TRIG MODE ON\r\n");
        return ERR_SUCCESS;
    }

    serPutString(SER_CONSOLE, "ERR: DVR START TASK NOT COMPLETE\r\n");
    
    return ERR_SUCCESS;
}

int actTrigModeOffCmd(char* s)
{
    
    /* Disable trigger mode */
    if ( taskSetTrigMode(FALSE) )
    {
        serPutString(SER_CONSOLE, "TRIG MODE OFF\r\n");
        return ERR_SUCCESS;
    }
    
    serPutString(SER_CONSOLE, "ERR: DVR START TASK NOT COMPLETE\r\n");

    return ERR_SUCCESS;
}

int actTimeLapseModeOnCmd(char* s)
{
    /* Enable trigger mode */
    if ( taskSetTimLapseMode(TRUE) )
    {
        serPutString(SER_CONSOLE, "TL MODE ON\r\n");
        return ERR_SUCCESS;
    }

    serPutString(SER_CONSOLE, "ERR: ERROR ENABLING TL MODE\r\n");
    
    return ERR_SUCCESS;
}

int actTimeLapseModeOffCmd(char* s)
{
    /* Enable trigger mode */
    if ( taskSetTimLapseMode(FALSE) )
    {
        serPutString(SER_CONSOLE, "TL MODE OFF\r\n");
        return ERR_SUCCESS;
    }

    serPutString(SER_CONSOLE, "ERR: ERROR DISABLING TL MODE\r\n");
    
    return ERR_SUCCESS;
}

/* debug command(s) below */                
int actTest1Cmd(char* s)
{
    serPutString(SER_CONSOLE, "TEST1\r\n");
    taskShowStates();

    return ERR_SUCCESS;
}

int actTest2Cmd(char* s)
{
    serPutString(SER_CONSOLE, "TEST2\r\n");
    return ERR_SUCCESS;
}


int actTest3Cmd(char* s)
{
    serPutString(SER_CONSOLE, "TEST3\r\n");
    return ERR_SUCCESS;
}

int actTest4Cmd(char* s)
{
    serPutString(SER_CONSOLE, "TEST4\r\n");
    return ERR_SUCCESS;
}

int actHelloKittyCmd(char* s)
{
    serPutString(SER_CONSOLE, "MEOW\r\n");
    return ERR_SUCCESS;
}

/****************************************************************************/
/*                               Set commands                               */
/****************************************************************************/
int actSetStartDelay(char* s)
{
    long delay = atol(s);

    taskSetStartDelay(delay);

    return ERR_SUCCESS;
}

int actSetStopDelay(char* s)
{
    long delay = atol(s);

    taskSetStopDelay(delay);

    return ERR_SUCCESS;
}

int actSetDebounce(char* s)
{
    long debounce = atol(s);

    tmrSetTrigDebounce((unsigned long)debounce);
    
    return ERR_SUCCESS;
}

int actSetHoldOff(char* s)
{
    long hold_off = atol(s);

    tmrSetTrigHoldOff((unsigned long)hold_off);

    return ERR_SUCCESS;
}

int actSetTrigWindow(char* s)
{
    long window = atol(s);

    taskSetTriggerWindow(window);

    return ERR_SUCCESS;
}

int actSetTimeLapseOn(char* s)
{
    long delay = atol(s);

    taskSetTimeLapseOn(delay);

    return ERR_SUCCESS;
}

int actSetTimeLapseOff(char* s)
{
    long delay = atol(s);

    taskSetTimeLapseOff(delay);

    return ERR_SUCCESS;
}

int actSetTime(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;
}

