/*
 * ctd_aand5860.c
 *
 *  Created on: May 2, 2021
 *      Author: thomm
 */

#include "main.h"
#include "system.h"
#include "uartstdio.h"
#include "user_io.h"
#include "ctd_base.h"
#include "ctd_aand5860.h"

//(open / power on)
//   time = 240 msec
//%
//!do sample
//   time = 1460 msec
//MEASUREMENT     5860    29      Conductivity[mS/cm]     -0.005  Temperature[Deg.C]      24.152  Salinity[PSU]   0.012   Density[kg/m3]  997.270 Soundspeed[m/s] 1494.439
//5860    29      -0.001  26.054  0.012   996.780 1499.510
//#

extern struct ctdDriver ctd;

extern unsigned char uart4_prn_buf[];

int ctd_aand5860_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.

    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_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_UART4_INST],ctd.type );   // DEBUG
                ctd.state = ST_CTD_AAND_PWR_RESP;
                return(ST_CTD_AAND_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_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();
                    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();
                        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();
            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 *)&uart4_prn_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();  // reset timer
                while(1)       // expect no more than 100 chars
                {
#define WAIT10MSTICKVAL  5
                    wait_ms = ctd_waitRx(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 *)&uart4_prn_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 uart4_prn_buf
                    }
                    if(inChar == '#')  // end of data
                    {
                        ctd_aand5860_parseData();       // ctd.bufIndx is parsed into ctd.condo, ctd.tempC and ctd.salt
                        ctd_close();  // Close ctd, power off

                        // Finished, return to do nothing state
                        ctd.state = ST_CTD_NADA;
                        return(ST_CTD_NADA);
                    }

                    //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\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();
            if((ctd.new_tick10ms - ctd.old_tick10ms) >= 500)  // 5000msec = 500*10msec
            {
                sprintf((char *)&uart4_prn_buf[0], "CTD not responding with sample string after do sample");
                ctd_close();  // Close CTD, 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);
    }

#ifdef WARNING_ABATEMENT_UNREACHABLE
    return(ST_CTD_NADA);        // should never get here
#endif
}



uint32_t ctd_aand5860_qa_test(void)
{

    int ctd_aand5860_State;


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


    while(1)
    {
        if(ctd_aand5860_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_aand5860_State = ctd_aand5860_stateMachine(ctd_aand5860_State);

    }

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




void ctd_aand5860_serial_analyzer(void)
{
    //int nextState = 0;
    //unsigned int indx;
    unsigned int tick1;
    unsigned char inChar;

    uprintf("ctd serial analyzer, bytes and times  Ctrl-X to quit\r\n");
#ifdef NOCODE
    set passkey(1)
    set mode(smart sensor terminal)
    set enable polled mode(yes)
    save

    To set the output mode:
    do sample
    set passkey(1)
    set enable text(no)
    save
    do sample

    // ctrl-q and ctrl-s will be sent from optode and conductivity, this can be removed by changing flow control to none
    set passkey(1000)
    #
    set Flow Control(none)
    #
    save

    get flow control
    Flow Control    4831    856     None
#endif
    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() )
            {
               // [0x11]  time = 220 msec
               //% [0x25]  time = 0 msec
               //! [0x21]  time = 10 msec
               // [0x11]  time = 940 msec


#ifdef NOCODE
                ctd serial analyzer, bytes and times
                open
                RX:  [0x11]  time = 230 msec
                RX: % [0x25]  time = 0 msec
                TX: crlf
                RX: ! [0x21]  time = 10 msec
                TX: crlf do sample crlf
                RX:  [0x11]  time = 940 msec
                RX:  [0x13]  time = 0 msec
                RX:  [0x11]  time = 940 msec
                RX: 4 [0x34]  time = 0 msec
                RX: 8 [0x38]  time = 0 msec
                RX: 3 [0x33]  time = 0 msec
                RX: 1 [0x31]  time = 10 msec

#endif

                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 == '%')
                {
                    uprintf("TX: crlf \r\n");
                    ctd_putc(0x0d);  // CR=13
                    ctd_putc(0x0a);  // LF=10

                }
                if(inChar == '!')
                {
                    uprintf("TX: crlf do sample crlf \r\n");
                    ctd_putc(0x0d);  // CR=13
                    ctd_putc(0x0a);  // LF=10
                    ctd_write("do sample\r\n",12 );
                }
            }
            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_poll() tells the Optode to "do_sample."  Data is received
 * via the UART3 interrupt handler.
 */
void ctd_aand5860_poll(void)
{

    ctd_write("do sample\r\n",12 );
    //MAP_SysCtlDelay(1000*MILLISECOND); //add 800 to try to limit "SYNTAX ERROR"

}



/*
 * Parse the data returned by the Aanderaa 5860 Conductivity sensor and put it in the output form we'd like (tab delimited etc.).
 * While parsing, move the data out of poll_Buffers.condoBuffer and into the instrument buffer which
 * will have all of our measurements.
 */

void ctd_aand5860_parseData(void)
{
    unsigned int model, sernum;
    float condo, tempC, salt, density, speedSound;

    //if( sscanf( ctd.buf, "%u\t%u\t%f\t%f\t%f\t%f\t%f", &model, &sernum, &condo, &tempC, &salt, &density, &speedSound) != 7)
    if( sscanf( (char*)uart4_prn_buf, "%u %u %f %f %f %f %f", &model, &sernum, &condo, &tempC, &salt, &density, &speedSound) != 7)
    {
        uprintf("\r\nError:  sscanf for parsing Aanderaa 5860 does not return 7 args.  ctd.type = %u.  TempC and salt are 0.0\r\n", ctd.type);
        uprintf("\r\nCheck setup of Aanderaa 5860, enable derived, raw, etc.   To Fix, use Test Menu, Communicate with Instrument\r\n");
        condo = tempC = salt = 0.0;
    }

    sys_samp.sensor_sal = salt;     // sys_data.sensor_sal is used when CTD is configured for vrse ph calc called in fast_sample in sample.c

    ctd.condo = condo;
    ctd.tempC = tempC;
    ctd.salt = salt;

}


/*
 * ctd_aand5860_comm_test is called to communicate directly with the instrument thru the users console port
 */

void ctd_aand5860_comm_test(void)
{
    unsigned char charInput;

#ifdef NOCODE
    Enable Derived Parameters: Controls inclusion of Salinity, Density and Speed of sound in the output string
    Enable Rawdata:  Controls inclusion of Controls inclusion of Conductivity in the output string
    Enable Temperature:
    set enable text(yes) to see data header
#endif

    uprintf("\r\nNote: smart sensor mode, disable data descriptor text, set flow control to none "); prn_nl(); prn_nl(); 
    uprintf("With enable text(1), output has field descriptors and units:\r\n");
    uprintf("do sample\r\n");
    uprintf("MEASUREMENT     5860    29      Conductivity[mS/cm]     -0.000  Temperature[Deg.C]      16.021  Salinity[PSU]   0.008   Density[kg/m3]  998.947 Soundspeed[m/s] 1469.494"); prn_nl(); prn_nl(); 
    uprintf("\r\n\r\nCommand procedure to setup Aanderaa Conductivty 5860 for numeric output:"); prn_nl(); prn_nl(); 
    uprintf("set passkey(1)\r\n");
    uprintf("set mode(smart sensor terminal)\r\n");
    uprintf("set enable polled mode(yes)\r\n");
    uprintf("save\r\n");
    prn_nl();
    uprintf("set passkey(1)\r\n");
    uprintf("set enable text(no)\r\n");
    uprintf("save\r\n");
    prn_nl();
    uprintf("set passkey(1000)\r\n");       // response: #
    uprintf("set Flow Control(none)\r\n");  // response: #
    uprintf("save\r\n");
    prn_nl();

    uprintf("do sample\r\n");
	prn_nl(); 
    uprintf("This should return a sample: \t5860\t29\t-0.003\t16.892\t0.009\t998.802\t1472.435\t"); prn_nl(); prn_nl(); 
    //uprintf("                               \t5860\t29\t-0.003\t16.892\t0.009\t998.802\t1472.435\t\r\n");
#ifdef GETALLOUTPUT
    get all
    Product Name    5860    29      Conductivity Sensor
    Product Number  5860    29      5860
    Serial Number   5860    29      29
    SW ID   5860    29      1940039
    SW Version      5860    29      5       5       1
    Enable Conductivity     5860    29      Yes
    Node Description        5860    29      Conductivity Sensor #29
    Owner   5860    29
    Mode    5860    29      Smart Sensor Terminal
    Enable Sleep    5860    29      Yes
    Enable Polled Mode      5860    29      Yes
    Enable Text     5860    29      No
    Enable Decimalformat    5860    29      Yes
    Enable Temperature      5860    29      Yes
    Enable Rawdata  5860    29      No
    Enable Derived Parameters       5860    29      Yes
    Interval[s]     5860    29      10.000
    Location        5860    29
    Geographic Position     5860    29      36.8044, -121.7869
    Vertical Position       5860    29
    Reference       5860    29
    Pressure        5860    29      0.000000E+00
#endif



    prn_nl(); prn_nl(); uprintf("*Press CTRL-X to stop communicating with the Conductivity instrument.*"); prn_nl(); prn_nl(); 

    //set up the condo
    ctd_init();                 // fixes crash in 4.0.2 30 Dec 2021
    ctd_open();               // power on optode
    MAP_SysCtlDelay(500);       //500 is a guess

    while(1)
    {
        //if condo sent anything, print it out on the console
        if( ctd_rxBytesAvail() )      // condo
        {
            uprintf( "%c", ctd_getc() );
        }

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

            if(charInput == 13)     // If user hit carriage return, add a line feed
            {
                ctd_putc(charInput);  // CR
                ctd_putc(10);     // LF
            }
            else if(charInput == 24)
            {
                break;
            }
            else
            {
                ctd_putc(charInput);
            }
        }
    }

    ctd_close();  // Close up the Optode
}


#ifdef FORSIMULATOR
ctd serial analyzer, bytes and times  Ctrl-X to quit
open
RX: % [0x25]  time = 0 msec
TX: crlf
RX: % [0x25]  time = 240 msec
TX: crlf
RX: ! [0x21]  time = 10 msec
TX: crlf do sample crlf
RX: 5 [0x35]  time = 1460 msec
RX: 8 [0x38]  time = 0 msec
RX: 6 [0x36]  time = 0 msec
RX: 0 [0x30]  time = 0 msec
RX:      [0x09]  time = 10 msec
RX: 2 [0x32]  time = 0 msec
RX: 9 [0x39]  time = 0 msec
RX:      [0x09]  time = 0 msec
RX: - [0x2d]  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: 2 [0x32]  time = 0 msec
RX:      [0x09]  time = 10 msec
RX: 2 [0x32]  time = 0 msec
RX: 5 [0x35]  time = 0 msec
RX: . [0x2e]  time = 0 msec
RX: 5 [0x35]  time = 0 msec
RX: 8 [0x38]  time = 0 msec
RX: 9 [0x39]  time = 0 msec
RX:      [0x09]  time = 0 msec
RX: 0 [0x30]  time = 0 msec
RX: . [0x2e]  time = 0 msec
RX: 0 [0x30]  time = 10 msec
RX: 1 [0x31]  time = 0 msec
RX: 2 [0x32]  time = 0 msec
RX:      [0x09]  time = 0 msec
RX: 9 [0x39]  time = 0 msec
RX: 9 [0x39]  time = 0 msec
RX: 6 [0x36]  time = 0 msec
RX: . [0x2e]  time = 0 msec
RX: 9 [0x39]  time = 10 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: 4 [0x34]  time = 0 msec
RX: 9 [0x39]  time = 0 msec
RX: 8 [0x38]  time = 0 msec
RX: . [0x2e]  time = 0 msec
RX: 2 [0x32]  time = 0 msec
RX: 9 [0x39]  time = 10 msec
RX: 5 [0x35]  time = 0 msec
 [0x0d]  time = 0 msec
RX:
 [0x0a]  time = 0 msec
RX: # [0x23]  time = 0 msec
 [0x0d]  time = 0 msec
RX:
 [0x0a]  time = 0 msec
#endif
