/****************************************************************************/
/* Copyright 2011 MBARI.                                                    */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
#include <p24fxxxx.h>
#include <stdio.h>
#include <string.h>

#include "parser.h"
#include "errors.h"
#include "serial.h"
#include "spi.h"
#include "analog.h"
#include "data_flash.h"
#include "sys_timer.h"
#include "ex_rtc.h"
#include "config.h"
#include "tasks.h"

#include "sys_defs.h"

_CONFIG1(JTAGEN_OFF & GCP_OFF & GWRP_OFF & COE_OFF & FWDTEN_OFF & ICS_PGx1) 
_CONFIG2(IESO_OFF & FNOSC_PRI & FCKSM_CSDCMD & OSCIOFNC_ON & DISUVREG_OFF & POSCMOD_XT)
_CONFIG3(WPDIS_WPDIS)

#define MAX_CHARS   80  /* maximum command line entry length */

#define NO_LINE     0
#define GOT_LINE    1
#define LANC_MODE   2

static ConfigData configData;

void lancMode();
int getCommand(char* cmd);

int main(void)
{
    int ret_val;
    char cmd_buff[MAX_CHARS];
    char err_buff[32];
    char* cmd_ptr;

/* move peripheral setup to perhip.c */
    /* Configure select analog pins for digital */
    _PCFG0 = 1;  /* Set for digital  */ 
    _PCFG1 = 1;  /* Set for digital  */ 
    _PCFG2 = 1;  /* Set for CS2      */ 
    _PCFG3 = 1;  /* Set for digital  */  
    _PCFG4 = 1;  /* Set for digital  */ 
    _PCFG5 = 1;  /* Set for digital  */ 
    _PCFG6 = 1;  /* Set for digital  */ 
    _PCFG7 = 1;  /* Set for digital  */ 
    _PCFG8 = 1;  /* Set for digital  */ 
    _PCFG9 = 1;  /* Set for digital  */ 
    _PCFG10 = 0; /* Analog in 2      */ 
    _PCFG11 = 0; /* Battery voltage  */ 
    _PCFG12 = 1; /* LED 1 power bit  */
    _PCFG13 = 1; /* LED 2 power bit  */
    _PCFG14 = 1; /* Inst 2 power bit */
    _PCFG15 = 1; /* Set for digital  */

    /* wait for LANC chip to initialize */
    tmrInit();
    tmrDelayMs(500L);

    /*************************** Map Pins UART 1 ****************************/
    /* Assign U1RX To Pin RP17 */
    _U1RXR = 17;
    /* Assign U1TX (5) To Pin RP16 */
    _RP16R = 3;
    
    /*************************** Map Pins UART 2 ****************************/
    /* Assign U2RX To Pin RP11 */
    _U2RXR = 11;
    /* Assign U2TX (5) To Pin RP12 */
    _RP12R = 5;
    /* Setup pin RG6 as console xcvr control and enable */ 
    _TRISG6 = 0;
    _LATG6 = 1;

    /* Setup power switch outputs */
    
    /* Camera */
    _TRISF0 = 0;
    _LATF0 = 0;

    /* LED 1 */
    _TRISB12 = 0;
    _LATB12 = 0;
    
    /* LED 2 */
    _TRISB13 = 0;
    _LATB13 = 0;

    /* HDMI->NTSC */
    _TRISF1 = 0;
    _LATF1 = 0;

    /* Strobe */
    _TRISC13 = 0;
    _LATC13 = 0;

    /* Instrument 1 */
    _TRISC14 = 0;
    _LATC14 = 0;

    /* Instrument 2 */
    _TRISB14 = 0;
    _LATB14 = 0;
    
    /* Setup trigger inputs */
    _TRISD6 = 1;
    _TRISD7 = 1;
    
    /* map SPI bus pins */
    _RP4R = 7;  /* Make Pin RP4 SDO (MOSI)  */
    _SDI1R = 3; /* Make Pin RP3 SDI (MISO)  */
    _RP2R = 8;  /* Make Pin RP2 SCK         */
    
    /* init everything here */
    anaInit();
    serInit();
    spiInit();
    dmInit();
    rtcInit();

    /* show the sign-on banner */
    sprintf(cmd_buff, "\r\ntlCamera Controller %s, %s\r\n", __DATE__, __TIME__);
    serPutString(SER_CONSOLE, cmd_buff);

    sprintf(cmd_buff, "CVS tag \"%s\"\r\n", "$Name:  $");
    serPutString(SER_CONSOLE, cmd_buff);

    /* read the config struct */
    if ( cfgRead(&configData) != 0 )
    {
        /* set the defaults */
        cfgDefault();
        serPutString(SER_CONSOLE, "ERR: CONFIG READ FAILED, USING DEFAULT\r\n");

        /* reread the correct default config */
        cfgRead(&configData);
    }

    /* initialize all parameters */
    tskSetCaptureMode(configData.captureMode);
    tskSetStartDeploy(configData.startOfDeploy);
    tskSetLenDeploy(configData.lenOfDeploy);
    tskSetSampleInt(configData.sampleInterval);
    tskSetVidLen(configData.lenOfVideo);
    tskSetBattLevel(configData.battLevel);

    /* taskInit has to come after the parameters are initialized */
    tskInit();

    for (;;)
    {
        tskExecute(ALL_TASK);

        ret_val = getCommand(cmd_buff);

        /* check for lanc mode first */
        if ( ret_val == LANC_MODE )
        {
            lancMode();
            /* if you are exiting lanc mode you don't have a command */
            ret_val = NO_LINE;
        }

        /* if you didn't enter lanc mode check for command */
        if ( ret_val == NO_LINE )
        {
            ret_val = ERR_NO_LINE;
        }
        else
        {
            /* Skip white space here */
            cmd_ptr = prsSkip(cmd_buff, " \t");

            /* If the cmd from getCommand was empty then return here. */
            if ( !strlen(cmd_ptr) )
                ret_val = ERR_EMPTY_LINE;
            else
                ret_val = prsParse(cmd_ptr, cmdsRoot, ERR_NO_COMMAND);
        }

        /* display ERR code or RDY prompt */
        if ( ret_val != ERR_NO_LINE)
        {
            if ((ret_val != ERR_SUCCESS) && (ret_val != ERR_EMPTY_LINE))
            {
                sprintf(err_buff,"ERR %04d\r\n", ret_val);
                serPutString(SER_CONSOLE, err_buff);
            }

            serPutString(SER_CONSOLE, "RDY\r\n");
        }
    }
}

void lancMode()
{
    unsigned char b;
    int lanc_mode = TRUE;

    /* flush everything */
    serRxFlush(SER_SPARE);
    serRxFlush(SER_CONSOLE);

    serTxFlush(SER_SPARE);
    serTxFlush(SER_CONSOLE);

    serPutString(SER_CONSOLE, "LANC MODE ENABLED\r\n");

    while ( lanc_mode )
    {
        /* if you're in lan c mode keep the timers 
        updated, but don't run other tasks */
        tskExecute(TMR_TASK);

        /* if you get a lanc byte send it to the console */
        if ( serGetByte(SER_SPARE, &b) )
            serPutByte(SER_CONSOLE, b);

        /* if you get a console byte send it to the lanc bus */
        if ( serGetByte(SER_CONSOLE, &b) )
        {
            /* got Ctrl-X, exit LANC pass through */
            if ( b == 0x18 )
                lanc_mode = FALSE;
            else
                serPutByte(SER_SPARE, b);

            /* reset lanc session timer */
/* Need to add timer here */
        }

        /* if lanc session timer expires exit LANC mode */
/* Need to add timer here */

    }
    /* flush everything */
    serRxFlush(SER_SPARE);
    serRxFlush(SER_CONSOLE);

    serTxFlush(SER_SPARE);
    serTxFlush(SER_CONSOLE);

    serPutString(SER_CONSOLE, "LANC MODE DISABLED\r\n");

    return;
}

#define ECHO_MODE   1
int getCommand(char* cmd)
{
    static int char_count = 0;
    static char line[MAX_CHARS] = "";
    const unsigned char terminator = '\r';
    int got_line;
    unsigned char b;
    int i;
    
    got_line = NO_LINE;

    if ( serGetByte(SER_CONSOLE, &b) )
    {
        /* got Ctrl-L, enter LANC pass through */
        if ( b == 0x0C )
        {
            /* dump current line */
            line[char_count] = '\0';
            char_count = 0;
            return LANC_MODE;
        }

        if ( ECHO_MODE )
        {
            serPutByte(SER_CONSOLE, b);
            if (b == '\r') serPutByte(SER_CONSOLE, '\n');
        }

        if ( b != terminator )
        {
            if ( (b != '\b') && (char_count < MAX_CHARS) )
                line[char_count++] = b;
            else if ( char_count > 0 )
                --char_count;

            cmd[0] = '\0';
        } 
        else
        {
            got_line = GOT_LINE;
            line[char_count] = '\0';
            for (i = 0; i <= char_count; i++)
                cmd[i] = line[i];
            char_count = 0;
        }
    }

    return got_line;
}

