/*
 * David Muller; Germán Alfaro
 * davehmuller@gmail.com; alfaro.germanevera@gmail.com
 * Thom Maughan, tm@mbari.org
 *
 *  *
 * TODO:
 *  - change API to specify uart4
 *  - cleanup statemachine, simplify
 */


#include "system.h"
#include "uart4.h"
#include "ctd_base.h"
#include "ctd_aand5860.h"
#include "ctd_sbe37.h"
#include "uartstdio.h"
#include "user_io.h"
#include "board_util.h"

// driver model:
// base functions tied to hardware are named after silk screen, ex. ctd_base
// instrument specific functions are named for the manufacturer, ex. aanderaa_conductivity, shortened aand_cond.c and are built on hardware specific functions
// note, the hardware specific functions are built from TI Tivaware which is flexible to enable porting to different UARTs and peripheral mapping - this flex is left as is, but can be confusing if you don't know why the added flex is there




extern unsigned long Timer_10ms(bool reset);

extern unsigned char uart4_prn_buf[];

struct ctdDriver ctd;   // struct defd in ctd_base.h

/*
 * ASCII characters.
 */
#define SPACE 0x20
#define OPENBRACE 0x7b
#define TAB 0x09


// init backplane call, note hardcoded baud rate.
void ctd_init(void)
{
    uart4_init();

    uart4_setup(CTD_BAUD, 16000000);

    uart4_echo_set(0);   // Disable echo to Conductivity sensor (ctd)  //#define CTD_BAUD     9600  defd in ctd_base.h

}

/*
 * Apply power to the Condo and prepare uart4 and driver state vars.
 * Assumes ctd_init is called.
 */
void ctd_open(void)
{
    //ctd_init();       // Moved from init.c

#if BOARD_MPHOX >= 1        // was BOARD_MFET >= 2  || BOARD_MPHOX >= 1
    // turn on Vbat supply on J8 MPHOX
    //ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_0, 0xFF);    // J8 CTDpwr PD0 Power on
    pwr_ctd_on();       //defd in board_util.c
#endif

    ctd.state = 0;
    ctd.bufIndx = 0;

}

void ctd_close(void)
{

#if BOARD_MPHOX >= 1
    //ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_0, 0x00);    // J8 CTDpowr PD0 Power off
    pwr_ctd_off();
#endif

}

unsigned char ctd_getc(void)
{
    unsigned char c;

    c = uart4_rx_byte();
    return c;
}

void ctd_putc(unsigned char c)
{
    uart4_tx_byte(c);
}

int ctd_rxBytesAvail(void)
{
    return(uart4_rx_bytes_avail());
}

void ctd_flushRx(void)
{
    uart4_rx_bufr_flush();
}

void ctd_flushTx(bool discardFlg)
{
    uart4_tx_bufr_flush(true);   // true says discard
}


int ctd_write(const char *pcBuf, uint32_t ui32Len)
{
    return(uart4_write(pcBuf, ui32Len));
}

void ctd_buf_print(void)
{
    uprintf("%s", uart4_prn_buf);
}

int ctd_buf_size(void)
{
    return(UART4_RX_BUFFER_SIZE);
}

int ctd_buf_putc(unsigned char inChar)
{
    uart4_prn_buf[ctd.bufIndx] = inChar;
    ctd.bufIndx++;
    if(ctd.bufIndx >= ctd_buf_size())
    {
        uprintf("\r\nDEBUG: error in ctd driver bufIndx exceeds buf size, ctd.c\r\n");

        ctd.bufIndx = ctd_buf_size() - 1;
        if(sys_data.diag > 0) uprintf("\r\nDEBUG: error in ctd driver bufIndx exceeds buf size, ctd.c\r\n");
        wait_consoleTx();
        return(0);      // return of zero is buffer overflow error
    }
    return(1);
}





#ifdef CAPTUREDFROMTERATERM
SBE 37-SI
ts
  23.3971,  0.00007,    0.127,   0.0113, 29 Apr 2021, 15:51:19
<Executed/>
#endif




uint32_t ctd_waitRx(uint32_t maxWait_10msTick)
{
    uint32_t start_10msTick;
    //uint32_t end_10msTick;
    uint32_t now_10msTick;

    // maxWaitMsec = 0, wait indefinitely
    // return wait in msec
    start_10msTick = Timer_10ms(false);
    while(1)
    {
        if( ctd_rxBytesAvail() )
        {
            now_10msTick = Timer_10ms(false);
            return(now_10msTick-start_10msTick);
        }
        ROM_SysCtlDelay(MICROSECOND*500);       // throttle the loop
        now_10msTick = Timer_10ms(false);
        if(maxWait_10msTick > 0)
        {
            if((now_10msTick - start_10msTick) >= maxWait_10msTick)
            {
                return(maxWait_10msTick);
            }
        }
        if(start_10msTick > now_10msTick)
        {
            uprintf("DEBUG: ctd_waitRx 10msTick timer rolled over\r\n");
            return(0);
        }
    }

}



#ifdef OLDCODE

int ctd_stateMachine(int ctdState)
{

    unsigned int tick1, tick2;
    unsigned char inChar;
    int debugFlag = 0;
    uint32_t wait_ms;

    // example usage:
    //ctdState = 1;
    //ctdState = ctd_stateMachine(ctdState);     //pass in 1 to start the state machine, hereafter pass retVal
    //call statemachine repeatedly until ctdState == 0

    //open (ctd power on)
    //   time = 260 msec
    //SBE 37-SI
    //ts
    //   time = 2630+160 msec
    //  28.8567,  0.00008,   -0.141,   0.0132, 03 May 2021, 17:06:57
    //<Executed/>

    ctd.state = ctdState;    // for debugging, ctd.state not used at this time.

#ifdef NOCODE
#define COMMA 0x2C
//#define TAB   '\t'  //0x09   //CTRL-I
#define ST_CTD_NADA             0
#define ST_CTD_INIT             1
#define ST_CTD_SBE_PWR_RESP     2
#define ST_CTD_SBE_GET_DATA     3
#define ST_CTD_AAND_PWR_RESP    4
#define ST_CTD_GET_AAND_DATA    5
#endif

    switch(ctdState)
    {
        case ST_CTD_NADA:       //0:
            // do nothing, caller needs to pass in state=1 to start things
            //if(debugFlag == 1) ctd.old_tick10ms = Timer_10ms(false); // DEBUG
            return(ST_CTD_NADA);

        case ST_CTD_INIT:       //1:
            ctd_init();  // moved from init(), Look at adding this to ctd_open
            ctd_open();   // power on ctd Vbat supply, init vars

            ROM_SysCtlDelay(MILLISECOND*1);  // power stable for 1mec (was 20msec)

            ctd_flushRx();
            ctd_flushTx(true);   // true says discard

            ctd.old_tick10ms = Timer_10ms(false);

            // The new seabird does not send "SBE 37-SI" 31 Mar 2022
            // New 16 Feb 2022, use CTD type instead of autodetect (solves problem printing data header)
            ctd.type = 0;
            if((sys_data.data_cfg[CFG_CTD]) == INST_SBE37_MICROCAT)         // 1
            {
                ctd.type = INST_SBE37_MICROCAT;
                ctd.state = ST_CTD_SBE_PWR_RESP;
                return(ST_CTD_SBE_PWR_RESP);
            }

            if((sys_data.data_cfg[CFG_CTD]) == INST_AANDERAA_5860)  // 2 Aanderaa
            {
                ctd.type = INST_AANDERAA_5860;
                if(debugFlag == 1) uprintf( "ST_CTD_INIT->ST_CTD_PWR_RESP, cfg=%u type=%u\r\n", sys_data.data_cfg[CFG_CTD],ctd.type );   // DEBUG
                ctd.state = ST_CTD_AAND_PWR_RESP;
                return(ST_CTD_AAND_PWR_RESP);
            }

            uprintf("Error: sys_data.data_cfg[CFG_CTD] = %u, no driver for this CTD type, Config -> Data Fields\r\n", sys_data.data_cfg[CFG_CTD]);
            ctd.state = ST_CTD_NADA;
            return(ST_CTD_NADA);        // something is wrong so return to init state

        case ST_CTD_SBE_PWR_RESP:
            // wait 900msec (600,700,1000 msec works for old CTD firmware, new CTD firmware requires 900msec)
            // Then send wakeup key (0x0d) for new CTD firmware
            // Wait at least 20msec
            // Then send 'ts' <CR>
            // Wait 7msec for ts char echo
            // flush rx buf
            // go to next state to get data
            //ROM_SysCtlDelay(MILLISECOND*900);       //600,700,1000 msec works for old CTD, new CTD requires 900msec

            // TODO, handle SBE config'd and Aanderaa connected

            ctd.new_tick10ms = Timer_10ms(false);
#define SBE37OLDNEW_DELAYBEFORE_TS_MS   (900/10)        // 900msec counted by 10msec period timer
            if((ctd.new_tick10ms - ctd.old_tick10ms) >= SBE37OLDNEW_DELAYBEFORE_TS_MS)  // wait at least 900msec (90*10ms) for both old/new firmware to be ready for ts command
            {

                ctd_putc(0x0d);  // CR=13  NEW CTD powers up and goes to sleep, needs a CR (any key) to wake
#define SBE37NEW_WAKEDELAY_MS   20
                ROM_SysCtlDelay(MILLISECOND*SBE37NEW_WAKEDELAY_MS);   //5,10,15,17,18(too fast), 19(sometimes), works: 20,50,100   RECOMMEND 25 to have margin (tbd)
                ctd_putc('t');  //
                ctd_putc('s');  //
                ctd_putc(0x0d);  // CR=13
                //ctd_putc(0x0a);  // LF=10  NOT NEEDED
#define SBE37OLD_ECHODELAY_MS   20
                ROM_SysCtlDelay(MILLISECOND*SBE37OLD_ECHODELAY_MS);   // wait 7msec for ts echo (after removing debug, old broke (not work 7,10  work 20)

                ctd_flushRx();   // flush the ts echo response

                ctd.old_tick10ms = Timer_10ms(false);
                ctd.state = ST_CTD_SBE_GET_DATA;
                return(ST_CTD_SBE_GET_DATA);
            }

            ctd.state = ST_CTD_SBE_PWR_RESP;
            return(ST_CTD_SBE_PWR_RESP);

        case ST_CTD_SBE_GET_DATA:            //  23.5074,  0.00006,   -0.157,   0.0113, 03 May 2021, 12:34:29
            if( ctd_rxBytesAvail() )      // bytes from CTD
            {
                inChar = ctd_getc();
                if(debugFlag == 1) uprintf( "st6[%02x] %c ", inChar,inChar );   // DEBUG
                //uprintf( "[%02x] %c ", inChar,inChar );

                if(inChar == COMMA)  //',')   // COMMA substituted with TAB (0x09)
                {
                    inChar = TAB;
                }
                if(inChar == 0x0d)
                {
                    inChar = 0;     // CR-LF, terminate string at CR char
                }
                if((inChar == '<') || (inChar == 0x0a))  //<Executed/>
                {
                    // ctd.buf contains 0 terminated sample string, response to ts
                    //if(debugFlag == 1) uprintf("st7: ctd.buf is %s\r\n", ctd.buf);  //DEBUG

                    ctd_close();  // Close CTD, power off
                    ctd_microCat_parseData();

                    if(debugFlag == 1) uprintf("CTD: %s\r\n", ctd.buf);        // DEBUG
                    wait_consoleTx();

                    ctd.state = ST_CTD_NADA;
                    return(ST_CTD_NADA);  // Success, driver is done

                }



                ctd.buf[ctd.bufIndx] = inChar;
                ctd.bufIndx++;
                if(ctd.bufIndx >= ctd_buf_size())       //CTD_BUFFER_SIZE)
                {
                    ctd.bufIndx = ctd_buf_size()-1;
                    if(sys_data.diag > 0) uprintf("\r\nST7: error in ctd driver bufIndx exceeds buf size, ctd.c\r\n");
                    sprintf((char *)&ctd.buf[0], "ST7: error in ctd driver bufIndx exceeds buf size, ctd.c");
                    wait_consoleTx();
                    ctd_close();  // Close CTD, power off

                    ctd.type = 0;
                    ctd.state = -1;
                    return(ST_CTD_NADA);
                }


            }

            //timeoout waiting for response, might have Aanderaa connected with SBE config'd
            ctd.new_tick10ms = Timer_10ms(false);
            if((ctd.new_tick10ms - ctd.old_tick10ms) >= 350)  // 5000msec = 500*10msec   5 seconds is maybe a bit much.  Changed to 3500 seconds
            {
                sprintf((char *)&ctd.buf[0], "CTD not responding with SBE37 data, check connection, make sure data config is SBE37");
                ctd_close();  // Close Optode, power off
                ctd.state = -1;
                return(ST_CTD_NADA);
            }

            ctd.state = ST_CTD_SBE_GET_DATA;  // redundandt assignment (same state until end of data or timeout)
            return(ST_CTD_SBE_GET_DATA);


        case ST_CTD_AAND_PWR_RESP:       // look for a response from Aanderaa (state was retooled due to firmware change 31 Mar 2022 TM)
            if( ctd_rxBytesAvail() )
            {
                inChar = ctd_getc();
                if(debugFlag == 1) uprintf( "st2[%02x] %c ", inChar,inChar );   // DEBUG

                if(inChar == '%')  //Aanderaa 5860 (type=2)
                {
                    ctd.old_tick10ms = Timer_10ms(false);
                    ctd_putc(0x0d);  // CR=13
                    ctd_putc(0x0a);  // LF=10
                    if(debugFlag == 1) uprintf("[GO3]");       //DEBUG

                    // TODO - add a time out here
                    inChar = ctd_getc();            //
                    if(debugFlag == 1) uprintf( "(%02x)", inChar );        //DEBUG
                    if(inChar == '!')
                    {
                        ctd_write("do sample\r\n",12 );
                        ctd.old_tick10ms = Timer_10ms(false);
                        ctd.state = ST_CTD_GET_AAND_DATA;        //4;
                        return(ST_CTD_GET_AAND_DATA);
                    }
                    else
                    {
                        //What happens if ! is not received?
                        if(sys_data.diag > 0) uprintf("CTD Err: did not receive ! after crlf following %%\r\n");
                        wait_consoleTx();
                        ctd.state = -1;
                        return(ST_CTD_NADA);
                    }

                }
            }

            ctd.new_tick10ms = Timer_10ms(false);
            if((ctd.new_tick10ms - ctd.old_tick10ms) >= 250)  // wait at least 2500msec for slow statemachine pumping.   600msec = 60*10msec
            {

                if(sys_data.diag > 0) uprintf("\r\nNo CTD response in 2.5sec, statemachine pumping too slow or instrument not connected\r\n");   // DEBUG
                sprintf((char *)&ctd.buf[0], "CTD not responding with Aanderaa %% then ! after powerup");
                wait_consoleTx();
                ctd.state = -1;
                return(ST_CTD_NADA);

            }
            ctd.state = ST_CTD_AAND_PWR_RESP;
            return(ST_CTD_AAND_PWR_RESP);


        case ST_CTD_GET_AAND_DATA:      //was 4:
            if( ctd_rxBytesAvail() )      // if 1st char is available, get the entire do sample response string upto 1200msec
            {
                ctd.old_tick10ms = Timer_10ms(false);  // reset timer
                while(1)       // expect no more than 100 chars
                {
#define WAIT10MSTICKVAL  5
                    wait_ms = wait_ctdRx(WAIT10MSTICKVAL);   // 50msec ought to be enough
                    if(wait_ms == WAIT10MSTICKVAL)
                    {
                        if(sys_data.diag > 0) uprintf("\r\nDEBUG: inter-character delay exceeded 50msec receiving do_sample string\r\n");
                        sprintf((char *)&ctd.buf[0], "CTD driver Err: inter-character delay exceeded 50msec receiving do_sample string");
                        wait_consoleTx();
                        ctd_close();  // Close ctd, power off
                        ctd.state = -1;  // future, do something about error checking
                        return(ST_CTD_NADA);
                    }
                    // check timeout (all chars should be received within 120msec (10msec per char * 91 chars + crlf + #) + pad)
                    inChar = ctd_getc();

                    if(inChar == 0x0d)
                    {
                        inChar = 0;     //zero terminate ctd.buf
                    }
                    if(inChar == '#')  // end of data
                    {
                        ctd_Aand5860_parseData();       // ctd.buf is parsed into ctd.condo, ctd.tempC and ctd.salt
                        ctd_close();  // Close ctd, power off
                        //ctd.type = INST_AANDERAA_5860;
                        //if(ctd.type != sys_data.data_cfg[CFG_CTD])
                        //{
                        //    uprintf("\r\nERROR: CTD type %u, does not match data config type %u. Correcting data config to %u, Aanderaa 5860\r\n", ctd.type, sys_data.data_cfg[CFG_CTD], ctd.type);
                        //}
                        // Finished, return to do nothing state
                        ctd.state = ST_CTD_NADA;
                        return(ST_CTD_NADA);
                    }

                    ctd.buf[ctd.bufIndx] = inChar;
                    ctd.bufIndx++;
                    if(ctd.bufIndx >= ctd_buf_size())       //CTD_BUFFER_SIZE)
                    {
                        ctd.bufIndx = ctd_buf_size() - 1;
                        if(sys_data.diag > 0) uprintf("\r\nDEBUG: error in ctd driver bufIndx exceeds buf size, ctd_base.c\r\n");
                        ctd_close();  // Close CTD, power off
                        ctd.state = -1;
                        return(ST_CTD_NADA);
                    }
                }

            } // if rxByte

            ctd.new_tick10ms = Timer_10ms(false);
            if((ctd.new_tick10ms - ctd.old_tick10ms) >= 500)  // 5000msec = 500*10msec
            {
                sprintf((char *)&ctd.buf[0], "CTD not responding with sample string after do sample");
                ctd_close();  // Close Optode, power off
                ctd.state = -1;
                return(ST_CTD_NADA);
            }
            ctd.state = ST_CTD_GET_AAND_DATA;
            return(ST_CTD_GET_AAND_DATA);




        default:
            ctd.type = 0;
            ctd.state = -1;
            return(ST_CTD_NADA);
    }

    return(ST_CTD_NADA);
}
#endif


#ifdef OLDCODE
uint32_t ctd_qa_test(void)
{
    //uint32_t timeout;
    //uint32_t ticks, tickDelta;

    int ctdState;

    //start the ctd driver by passing 1, when complete, the statemachine returns 0
    ctdState = 1;
    ctdState = ctd_stateMachine(ctdState);     //pass in 1 to start the state machine, hereafter pass retVal

    //tickDelta = Timer_1ms(false) - tickDelta;
    //ticks = (Timer_1ms(false) - tickStart);
    //if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nCondo  St8Ma = %5u,   %5u", tickDelta, ticks);
    //tickDelta = ticks;

    while(1)
    {
        if(ctdState == 0)            // makes sure ctd statemachine is finished
        {
            if(ctd.state == -1)
                return(0);      // fail
            else
                return(1);      // success

        }
        ctdState = ctd_stateMachine(ctdState);

    }

    return(0);      // fail (never gets here)
}
#endif








#ifdef SIMULATOR
//Timing
// ctd microcat serial analyzer, bytes and times  Ctrl-X to quit
//
//open (ctd power on)
//   time = 260 msec
//SBE 37-SI
//ts
//   time = 2630+160 msec
//  28.8567,  0.00008,   -0.141,   0.0132, 03 May 2021, 17:06:57
//<Executed/>


ctd OPTODE serial analyzer, bytes and times
open
RX: % [0x25]  time = 230 msec
TX: crlf
RX: ! [0x21]  time = 10 msec
TX: crlf do sample crlf
RX: 5 [0x35]  time = 1470 msec
RX: 8 [0x38]  time = 0 msec
RX: 6 [0x36]  time = 0 msec
RX: 0 [0x30]  time = 0 msec
RX:      [0x09]  time = 0 msec
RX: 2 [0x32]  time = 0 msec
RX: 9 [0x39]  time = 0 msec
RX:      [0x09]  time = 0 msec
RX: - [0x2d]  time = 10 msec
RX: 0 [0x30]  time = 0 msec
RX: . [0x2e]  time = 0 msec
RX: 0 [0x30]  time = 0 msec
RX: 0 [0x30]  time = 0 msec
RX: 3 [0x33]  time = 0 msec
RX:      [0x09]  time = 0 msec
RX: 1 [0x31]  time = 0 msec
RX: 7 [0x37]  time = 0 msec
RX: . [0x2e]  time = 0 msec
RX: 2 [0x32]  time = 10 msec
RX: 7 [0x37]  time = 0 msec
RX: 2 [0x32]  time = 0 msec
RX:      [0x09]  time = 0 msec
RX: 0 [0x30]  time = 0 msec
RX: . [0x2e]  time = 0 msec
RX: 0 [0x30]  time = 0 msec
RX: 0 [0x30]  time = 0 msec
RX: 9 [0x39]  time = 0 msec
RX:      [0x09]  time = 0 msec
RX: 9 [0x39]  time = 0 msec
RX: 9 [0x39]  time = 0 msec
RX: 8 [0x38]  time = 0 msec
RX: . [0x2e]  time = 0 msec
RX: 7 [0x37]  time = 0 msec
RX: 3 [0x33]  time = 0 msec
RX: 6 [0x36]  time = 0 msec
RX:      [0x09]  time = 0 msec
RX: 1 [0x31]  time = 10 msec
RX: 4 [0x34]  time = 0 msec
RX: 7 [0x37]  time = 0 msec
RX: 3 [0x33]  time = 0 msec
RX: . [0x2e]  time = 0 msec
RX: 6 [0x36]  time = 0 msec
RX: 9 [0x39]  time = 0 msec
RX: 4 [0x34]  time = 0 msec
 [0x0d]  time = 0 msec
RX:
 [0x0a]  time = 0 msec
RX: # [0x23]  time = 10 msec
 [0x0d]  time = 0 msec
RX:
 [0x0a]  time = 0 msec

#endif
