/*
 * ctd_sbe37.c
 *
 *  Created on: Nov 28, 2022
 *      Author: thomm
 */

#include "main.h"
#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 char uart4_prn_buf[];

extern struct ctdDriver ctd;   // struct defd in ctd_base.h


int ctd_sbe37_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

            MAP_SysCtlDelay(MILLISECOND*1);  // power stable for 1mec (was 20msec)

            ctd_flushRx();
            ctd_flushTx(true);   // true says discard

            ctd.old_tick10ms = Timer_10ms();

            // 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_UART4_INST]) == INST_SBE37_MICROCAT)         // 1
            {
                ctd.type = INST_SBE37_MICROCAT;
                ctd.state = ST_CTD_SBE_PWR_RESP;
                return(ST_CTD_SBE_PWR_RESP);
            }

            uprintf("Error: sys_data.data_cfg[CFG_UART4_INST] = %u, no driver for this CTD type, Config -> Data Fields\r\n", sys_data.data_cfg[CFG_UART4_INST]);
            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
            //MAP_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();
#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
                MAP_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
                MAP_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();
                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_close();  // Close CTD, power off
                    ctd_sbe37_parseData();

                    if(debugFlag == 1) uprintf("CTD: %s\r\n", uart4_prn_buf);        // DEBUG  // was ctd.buf
                    wait_consoleTx();

                    ctd.state = ST_CTD_NADA;
                    return(ST_CTD_NADA);  // Success, driver is done

                }



                //ctd.buf[ctd.bufIndx] = inChar;
                uart4_prn_buf[ctd.bufIndx] = inChar;
                ctd.bufIndx++;
                if(ctd.bufIndx >= ctd_rx_buf_size())       //CTD_BUFFER_SIZE)
                {
                    ctd.bufIndx = ctd_rx_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 *)&uart4_prn_buf[0], "ST7: error in ctd driver bufIndx exceeds buf size, ctd.c");     //was ctd.buf
                    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();
            if((ctd.new_tick10ms - ctd.old_tick10ms) >= 350)  // 5000msec = 500*10msec   5 seconds is maybe a bit much.  Changed to 3500 seconds
            {
                sprintf((char *)&uart4_prn_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);



        default:
            ctd.type = 0;
            ctd.state = -1;
            return(ST_CTD_NADA);
    }

#ifdef WARNING_ABATEMENT_UNREACHABLE
    return(ST_CTD_NADA);
#endif
}


uint32_t ctd_sbe37_qa_test(void)
{

    int ctd_sbe37_State;


    //start the optode driver by passing 1, when complete, the statemachine returns 0
    ctd_sbe37_State = 1;
    ctd_sbe37_State = ctd_sbe37_stateMachine(ctd_sbe37_State);     //pass in 1 to start the state machine, hereafter pass retVal


    while(1)
    {
        if(ctd_sbe37_State == 0)            // makes sure optode statemachine is finished
        {
            if(ctd.state == -1)
                return(0);              // fail
            else
                return(1);              // pass
#ifdef WARNING_ABATEMENT_UNREACHABLE
            break;
#endif
        }
        ctd_sbe37_State = ctd_sbe37_stateMachine(ctd_sbe37_State);

    }

#ifdef WARNING_ABATEMENT_UNREACHABLE
    return(0);   // fail, never gets here
#endif
}


void ctd_sbe37_serial_analyzer(void)
{
    //int nextState = 0;
    //unsigned int indx;
    unsigned int tick1;
    unsigned char inChar;
    uint32_t essFlg = 0;

    uprintf("ctd microcat serial analyzer, bytes and times  Ctrl-X to quit\r\n");
    ctd_init();  // moved from init()

    while(1)
    {
        uprintf("open\r\n");
        ctd_open();   // power on ctd Vbat supply
        ctd.old_tick10ms = Timer_10ms();
        while(1)
        {
        // look for !, then send do_sample and crlf
            if( ctd_rxBytesAvail() )
            {


                ctd.new_tick10ms = Timer_10ms();
                inChar = ctd_getc();
                uprintf("RX: %c [0x%02x] ", inChar, inChar );
                tick1 = (ctd.new_tick10ms - ctd.old_tick10ms)*10;
                uprintf(" time = %u msec\r\n", tick1);
                ctd.old_tick10ms = Timer_10ms();

                if(inChar == 'S')
                {
                    essFlg = 1;
                    uprintf("TX: crlf \r\n");
                    ctd_putc(0x0d);  // CR=13
                    ctd_putc(0x0a);  // LF=10

                }
                if((inChar == 0x0a) && (essFlg == 1))
                {
                    essFlg = 0;
                    uprintf("TX: ts cr \r\n");
                    ctd_putc('t');
                    ctd_putc('s');
                    ctd_putc(0x0d);  // CR=13
                    //ctd_putc(0x0a);  // LF=10
                }
            }
            if(UARTRxBytesAvail())
            {
                inChar = UARTgetc();

                if(inChar == 24) // ctrl-x to exit loop
                {
                    ctd_close();
                    delay_msec(500);
                    break;
                }

            }

        } // while(1)

        if(UARTRxBytesAvail())
        {
            inChar = UARTgetc();

            if(inChar == 24) // ctrl-x to exit loop
                break;

        }

    }


}



/*
 * ctd_sbe37_poll() wakes up the microCAT with a carriage return
 * and then sends "tss" to the microCAT.  Data is received
 * via the MicroCAT's interrupt handler.
 * assumes ctd_init and ctd_open have been called
 */
void ctd_sbe37_poll(void)        // pollMicroCAT(void)
{
    ctd_write("\r\n", 1);
    MAP_SysCtlDelay(ONESEC);    // Give MicroCAT a second to wake up

    ctd_write("tss\r\n", 4);
    MAP_SysCtlDelay(MILLISECOND * 100);
    ctd_flushRx();     // Get rid of "tss"
}


/*
 * Parse the data returned by the microCAT and put it in the output form we'd like (tab delimited etc.).
 * While parsing, move the data out of poll_Buffers.microBuffer and into the instrument buffer which
 * will have all of our measurements.
 */
void ctd_sbe37_parseData(void)
{
    unsigned char datebuff[20];
    unsigned char timebuff[20];
    float tempC, salt;
    float dummy;


    // TODO, get the instrument back, and figure out depth field

    // "%f %f %f %s %s", &tempC, &dummy, &salt, buff, buff) != 5)
    //21.4218,  0.00006,   -0.147,   0.0105, 02 May 2021, 12:37:24
    if( sscanf( (char*)uart4_prn_buf, "%f\t%f\t%f\t%s\t%s", &tempC, &dummy, &salt, datebuff, timebuff) != 5)    //if( sscanf( ctd.buf, "%f\t%f\t%f\t%s\t%s", &tempC, &dummy, &salt, datebuff, timebuff) != 5)
    {
        uprintf("\r\nError:  sscanf for parsing MicroCat does not return 5 args.  ctd.state = %d.  TempC and salt are 0.0\r\n", ctd.state);
        uprintf("%s\r\n", uart4_prn_buf);
        tempC = salt = 0.0;
    }

    sys_samp.sensor_sal = salt;     // sys_data.sensor_sal is used when CTD is configured for vrse ph calc


    ctd.tempC = tempC;
    ctd.salt = salt;
    //ctd.depth = depth;

}

void ctd_sbe37_comm_test(void)
{
    unsigned char charInput;

    UARTEchoSet(false); // Disable console echo for MicroCAT
    prn_nl(); prn_nl(); uprintf("* Type ts<Enter> to take sample *"); prn_nl(); prn_nl(); 
    prn_nl(); prn_nl(); uprintf("* Press CTRL-X to stop communicating with the SBE37 MicroCAT *"); prn_nl(); prn_nl(); 

    //set up the MicroCAT
    ctd_init();  // moved from init()
    ctd_open();

    while(1)
    {
        //if MicroCAT sent anything, print it out on UART1 (the desktop)
        //if( ctd_rxBytesAvail() )
        if( ctd_rxBytesAvail() )

        {
            //uprintf( "%c", ctd_getc() );
            uprintf( "%c", ctd_getc() );
        }

        //if user types anything, send it to the MicroCAT--exit on CTRL-X
        if(UARTRxBytesAvail())
        {
            charInput = UARTgetc();

            if(charInput == 24)  // ctrl-x
            {
                break;
            }

            //ctd_putc(charInput);
            ctd_putc(charInput);
        }
    }


    //close up the MicroCAT
    //ctd_close();
    ctd_close();
    UARTEchoSet(true);  // Enable console echo
}



