/*
 * Thom Maughan, tm@mbari.org
 *
 *
 * NanoFET driver for MFET or MpHOX Optode port
 *
 */




#include "system.h"
#include "uartstdio.h"
#include "user_io.h"
#include "uart3.h"
#include "nanofet.h"
#include "main.h"

extern unsigned char uart3_prn_buf[];

struct nanofetDriver nanofet;   // struct defd in nanofet.h


/*
 * ASCII characters.
 */
#define SPACE 0x20
#define OPENBRACE 0x7b
#define TAB 0x09


// nanofet_init configures onchip uart3 peripheral, isr, and buffers.   Does not turn on 5v output
 void nanofet_init(void)
 {
     uart3_init();

     uart3_setup(NANOFET_BAUD, 16000000);

     uart3_echo_set(0);
 }


/*
 * Apply power to the NanoFET and prepare uart3 and driver state vars.
 * Assumes nanofet_init() is called.
 */
void nanofet_open(void)
{

    // on MPHOX, triple rs232 level translator is enabled for NanoFET J7, Console J6, and CTD J8 by console_enable/shutdown
    // on MFET, dual rs232 level translator is enabled for NanoFET J7 and Console J6 by console_enable/shutdown

#if BOARD_MFET >= 2  || BOARD_MPHOX >= 1  || BOARD_MSC == 1
	// turn on 5v supply on J7 MFET rev C, MPHOX rev A
    MAP_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_2, 0xff);    // PL2, pin 106 is 5vON
#endif

    nanofet_buf_flush(); // Not needed, implemented to help chase down a bug in nanofet driver - sampleNum is not incrementing when using the statemachine
    nanofet.state = 0;
    nanofet.bufIndx = 0;


}

void nanofet_close(void)
{

#if BOARD_MFET >= 2  || BOARD_MPHOX >= 1  || BOARD_MSC == 1
    // turn on 5v supply on J7 MFET rev C, MPHOX rev A
    MAP_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_2, 0x00);    // PL2, pin 106 is 5vON
#endif

}


unsigned char nanofet_getc(void)
{
    unsigned char c;

    c = uart3_rx_byte();
    return c;
}

void nanofet_putc(unsigned char c)
{
    uart3_tx_byte(c);
}

int nanofet_rxBytesAvail(void)
{
    return(uart3_rx_bytes_avail());
}

void nanofet_flushRx(void)
{
    uart3_rx_bufr_flush();
}

void nanofet_flushTx(bool bDiscard)
{
    uart3_tx_bufr_flush(bDiscard);
}

int nanofet_write(const char *pcBuf, uint32_t ui32Len)
{
    return(uart3_write(pcBuf, ui32Len));
}

int nanofet_rx_buf_size(void)
{
    return(UART3_RX_BUFFER_SIZE);
}

int nanofet_tx_buf_size(void)
{
    return(UART3_TX_BUFFER_SIZE);
}

int nanofet_buf_write(unsigned char inChar)
{
    uart3_prn_buf[nanofet.bufIndx] = inChar;
    nanofet.bufIndx++;
    if(nanofet.bufIndx >= nanofet_tx_buf_size())
    {
        uprintf("\r\nDEBUG: error in nanofet driver bufIndx exceeds buf size, nanofet.c\r\n");

        nanofet.bufIndx = nanofet_tx_buf_size() - 1;
        if(sys_data.diag > 0) uprintf("\r\nDEBUG: error in nanofet driver bufIndx exceeds buf size, nanofet.c\r\n");
        wait_consoleTx();
        return(0);      // return of zero is buffer overflow error
    }
    return(1);
}

void nanofet_buf_flush(void)
{
    unsigned int indx;

    for(indx=0; indx<nanofet_tx_buf_size(); indx++)
        uart3_prn_buf[indx] = 0x00;

    nanofet.bufIndx = 0;
}

void nanofet_buf_print(void)
{
    //uprintf("%s", nanofet.buf);
    uprintf("%s", uart3_prn_buf);
}
/*
 * nanofet_stateMachine
 *
 * pass in state=1 to start it, check for finish when returned state value is 0
 *
 */
int nanofet_stateMachine(int nanofetState)
{
    //int nextState = 0;
    //unsigned int indx;
    //unsigned int tick1, tick2;
    unsigned int wait_ms;
    unsigned char inChar;


    // example usage:
    //nanofetState = 1;
    //nanofetState = nanofet_statemachine(nanofetState);     //pass in 1 to start the state machine, hereafter pass retVal
    //call statemachine repeatedly until nanofetState == 0

    // nanofet_open
    // look for % within 600msec, then send crlf
    // look for !, then send do_sample and crlf
    // look for output terminated by crlf and # within 2000msec
    // trim crlf
    // closeOptde
    // look at retVal, if retVal=-1, that's a timeout, then terminate statemachine by sending it a 0 as arg

    // nanofet open (turn on power, wait 1msec, flush rx and tx bufs


    nanofet.state = nanofetState;    // for debugging, nanofet.state not used at this time.

    switch(nanofetState)
    {
        case 0:
            // do nothing, caller needs to pass in state=1 to start things
            return(0);

        case 1:
			nanofet_init();      // moved from init()
            nanofet_open();      // power on nanofet 5v supply, 10msec with flush

            MAP_SysCtlDelay(MILLISECOND*100);  // power stable, changed to 100msec to help eliminate factors during driver dev
            nanofet_flushRx();
            nanofet_flushTx(true);   // true says discard


            nanofet_putc(' ');      // send space char to wake nanoFET
            nanofet_putc(0x0d);      // // CR=13
            nanofet_putc(0x0a);      // // CR=10
            MAP_SysCtlDelay(MILLISECOND*100);       //was 300

            nanofet_putc(0x0d);      // // CR=13
            nanofet_putc(0x0a);      // // CR=10
            MAP_SysCtlDelay(MILLISECOND*300);       //was 300
            nanofet_flushRx();      // flush NAK
            nanofet_flushTx(true);   // true says discard

#ifdef NOCODE  // backspace does not wake the nanoFET, enter does
            nanofet_putc(0x08);     // send backspace key to wake nanoFET
            MAP_SysCtlDelay(MILLISECOND*100); // wait for nanoFET to wakeup
            nanofet_putc(0x08);     // send backspace again
#endif
            //nanofet_putc(' ');      // send space char to wake nanoFET
            //MAP_SysCtlDelay(MILLISECOND*50);
            nanofet_putc('t');      // send ts<cr)
            nanofet_putc('s');
            nanofet_putc(0x0d);      // // CR=13
            nanofet_putc(0x0a);      // // CR=10

            //MAP_SysCtlDelay(MILLISECOND*100);       //was 300
            //nanofet_flushRx();      // flush ts
            //nanofet_flushTx(true);   // true says discard

            nanofet.old_tick10ms = Timer_10ms();
            //uprintf("\r\nold tick10ms = %u \r\n", nanofet.old_tick10ms);
            nanofet.state = 2;
            return(2);


        case 2:
            // look for output terminated by crlf within 5000msec
            // trim crlf
            // nanofet_close
            // nextState = 0

            if( nanofet_rxBytesAvail() )      // if 1st char is available, get the entire do sample response string upto 1200msec
            {
                nanofet.old_tick10ms = Timer_10ms();  // reset timer
                while(1)       // expect no more than 100 chars
                {
#define WAIT10MSTICKVAL  500
                    wait_ms = nanofet_waitRx(WAIT10MSTICKVAL);   // 5000msec 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 *)&uart3_prn_buf[0], "NanoFET Err ST2: inter-character delay exceeded 50msec receiving do_sample string");
                        wait_consoleTx();
                        nanofet_close();  // Close NanoFET, power off
                        return(0);
                    }
                    // check timeout (all chars should be received within 120msec (10msec per char * 91 chars + crlf + #) + pad)
                    inChar = nanofet_getc();

                    //#0000001        11/01/2022 15:48:45        -0.31            0.00          147754        -0.084788       0.000000            +inf   -2.048000       0.000000        -2.048000       0.000000            0.72          -0.090
                    if(inChar == 0x0d)
                    {
                        inChar = 0;     //zero terminate nanofet.buf
                        nanofetState = 3;
                    }

                    //nanofet.new_tick10ms = Timer_10ms(false);  // DEBUG
                    //tick2 = nanofet.new_tick10ms - nanofet.old_tick10ms;  // DEBUG
                    //uprintf(" %c", inChar );  // DEBUG
                    //uprintf("[%02x](%ums) ", inChar, tick2); //DEBUG

                    //uprintf(" %c [%02x](%ums) ", inChar, inChar, tick2); //DEBUG
                    //uprintf("%c", inChar);      // DEBUG


                    if(!nanofet_buf_write(inChar))
                    {
                        nanofet_close();  // Close NanoFET, power off
                        nanofet.state = -1;
                        return(0);
                    }

                    return(nanofetState);
                }

            } // if rxByte

            nanofet.new_tick10ms = Timer_10ms();
            if((nanofet.new_tick10ms - nanofet.old_tick10ms) >= 500)  // 5000msec = 500*10msec
            {
                if(sys_data.diag > 0) uprintf("\r\nNanoFET power on did not receive sample string after sending ts - check nanofet connection or setup\r\n");
                sprintf((char *)&uart3_prn_buf[0], "NanoFET not responding with sample string after ts");
                nanofet_close();  // Close NanoFET, power off
                wait_consoleTx();
                nanofet.state = -1;
                return(0);
            }
            return(2);

        case 3:
            MAP_SysCtlDelay(MILLISECOND*50);       //allow time for nanoFET to save into FRAM
            nanofet_close();        // power off port
            return(0);          // returning 0 is state 'do nothing'

        default:
            nanofet_close();        // power off port
            return(0);

    }


}



uint32_t nanofet_qa_test(void)
{

    int nanofetState;

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

    while(1)
    {

        nanofetState = nanofet_stateMachine(nanofetState);

        if(nanofetState == 0)            // makes sure nanofet statemachine is finished
        {
            if(nanofet.state == -1)     // check for error
            {
                uprintf("NanoFET driver error...\r\n");
                return(0);              // fail
            }
            else
            {
                nanofet_buf_print();
                return(1);              // pass
            }
        }
    }

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



void nanofet_serial_analyzer(void)   //UNTESTED
{
    unsigned int tick1;
    unsigned char inChar;

    uprintf("nanofet serial analyzer, bytes and times\r\n");

	nanofet_init();      // moved from init()
    while(1)
    {
        uprintf("open\r\n");
        nanofet_open();   // power on nanofet 5v supply
        nanofet.old_tick10ms = Timer_10ms();

        MAP_SysCtlDelay(MILLISECOND*10);  // power stable (10msec is a guess, could be less)
        nanofet_flushRx();
        nanofet_flushTx(true);   // true says discard

        nanofet_putc(' ');      // send space char to wake nanoFET
        MAP_SysCtlDelay(MILLISECOND*25);
        nanofet_putc('t');      // send ts<cr)
        nanofet_putc('s');
        nanofet_putc(0x0d);      // // CR=13

        while(1)
        {
            if( nanofet_rxBytesAvail() )
            {
                nanofet.new_tick10ms = Timer_10ms();
                inChar = nanofet_getc();
                uprintf("RX: %c [0x%02x] ", inChar, inChar );
                tick1 = (nanofet.new_tick10ms - nanofet.old_tick10ms)*10;
                uprintf(" time = %u msec\r\n", tick1);
                nanofet.old_tick10ms = Timer_10ms();

                if(inChar == 0x0d)      // sample is terminated by 0x0d 0x0a
                {
                    uprintf("Break from while loop \r\n");
                    break;
                    //nanofet_putc(0x0d);  // CR=13
                    //nanofet_putc(0x0a);  // LF=10
                }

            }

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

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


            }

        } // while(1)

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

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

        }

    }


}



/*
 * nanofet_poll() tells the NanoFET to 'take sample' by sending ts<cr><lf>  Data is received
 * via the UART3 interrupt handler.
 */
void nanofet_poll(void)   //UNTESTED
{

    nanofet_write(" ",1); //added space before do sample for 4835 nanofets so only have to do 1 "do sample" 5/5/17 - TW
    MAP_SysCtlDelay(100*MILLISECOND);
    nanofet_write("ts\r\n",12);
    //nanofet_flushRx();

}






void nanofet_comm_test(void)
{
    unsigned char inChar;


    // Tested with Aanderaa Oxygen 5730 https://www.aanderaa.com/media/pdfs/d419_aanderaa_oxygen_sensor_5730.pdf
    prn_nl(); 
	uprintf("NanoFET needs to be configured, tested and in deploy mode for nanoFET driver operation "); prn_nl(); prn_nl(); 
    prn_nl(); prn_nl(); uprintf("NanoFET configuration procedure for driver mode, starting from NanoFET Main Menu.   NanoFET baud: 115200)"); prn_nl(); prn_nl(); 
    uprintf("Note: it can be confusing to see the NanoFET menu displayed via the MFET instrument comm session"); prn_nl(); prn_nl(); 
    uprintf("   First, select:  1 -- Configure\r\n");
    uprintf("   Next, select:   7 -- Config Data Fields\r\n");
    uprintf("   Then, select:   6 -- Use Case: nanoFET Default\r\n");
    uprintf("   Last, select:   Y -- Advanced\r\n");
    uprintf("         select:   A -- App Config Fields");
    uprintf("                   Enable character echo for deployment commands? (Y/N) [Y]? N ");
    uprintf("   Save:           9 -- Exit to Main Menu (saves config)\r\n");
    uprintf("   Verify nanoFET: 3 -- Test\r\n");
    uprintf("                   D/d- Data Header, Live Data (D loop), Sample Timing (d)\r\n");
    uprintf("   Exit test menu: 9 -- Exit to Main Menu\r\n");
    uprintf("   Main menu:      2 -- Deploy\r\n");
    prn_nl(); 
    uprintf("hit space key to wake nanoFET, then type ts<Enter>");
    prn_nl(); uprintf("This should return a sample: #0000001        11/01/2022 16:57:39        -1.96            0.00        536880967       -0.081446       0.000000            +inf   -2.048000       0.000000        -2.048000       0.000000            1.29          -0.088\t"); prn_nl(); prn_nl(); 
    prn_nl(); prn_nl(); uprintf("*Press CTRL-X to stop communicating with the NanoFET.*"); prn_nl(); prn_nl(); 

    //set up the nanofet
	nanofet_init();             // moved from init()
    nanofet_open();             // power on nanofet
    MAP_SysCtlDelay(10);        // Give the nanoFET time to boot


    while(1)
    {


        //if NanoFET sent anything, print it out on UART1 (the desktop)
        if( nanofet_rxBytesAvail() )      // NanoFET
        {
            uprintf( "%c", nanofet_getc() );
        }

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

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

                // BUG: we are getting an echo of commands sent to the menu....

            }
        }
    }

    nanofet_close();  // Close up the NanoFET
}


/*
 * Parse the data returned by the NanoFET and put it in the output form we'd like (tab delimited etc.).
 * While parsing, move the data out of poll_Buffers.nanofetBuffer and into the instrument buffer which
 * will have all of our measurements.
 */
// nanofet data looks like:
//StartupInfo     5730    1565    Mode    AADI Smart Sensor Terminal Protocol FW2 RS232 Protocol Version  3       Config Version  12
//MEASUREMENT     5730    1565    O2Concentration(uM)     215.385 AirSaturation(%)        99.342  Temperature(Deg.C)      24.506  CalPhase(Deg)   29.867  TCPhase(Deg)    29.867  C1RPh(Deg)      37.565  C2RPh(Deg)      7.698   C1Amp(mV)       753.6   C2Amp(mV)       737.3   RawTemp(mV)     96.2

void parseNanoFETData(void)
{

    // REWRITE OR GET RID OF THIS
#ifdef NOCODE
	//bytesRead holds the # of bytes received from NanoFET
	int bytesRead;
	int i;
	int bytes2delete = 0;

	bytesRead = uart3_rxBytesAvail();

	// DEBUG code
	//uprintf("nanofet bytesRead = %d\r\n", bytesRead);
	//uprintf("%s", uart3_buff);

	if(bytesRead)
	{
		uart3_gets(nanofet_buff, bytesRead);

		for(i = bytesRead; i >= 0; --i)
		{
			//uprintf("%c",nanofet_buff[i]);
			if(nanofet_buff[i] >47 & nanofet_buff[i] < 58)
			{
				bytes2delete = i;
			}
		}
		// End YT

		for(i = 0; i < bytesRead-bytes2delete; ++i)
		{
			nanofet_buff[i] = nanofet_buff[i+bytes2delete];	// Get rid of first few characters
		}
	}
	else
	{
	    strcpy(nanofet_buff, "NAN\tNAN\tNAN\tNAN\tNAN\tNAN\tNAN\tNAN\tNAN\tNAN\tNAN\tNAN\t");
	}
#endif
}


uint32_t nanofet_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();
    while(1)
    {
        if( nanofet_rxBytesAvail() )
        {
            now_10msTick = Timer_10ms();
            return(now_10msTick-start_10msTick);
        }
        MAP_SysCtlDelay(MICROSECOND*500);       // throttle the loop
        now_10msTick = Timer_10ms();
        if(maxWait_10msTick > 0)
        {
            if((now_10msTick - start_10msTick) >= maxWait_10msTick)
            {
                return(maxWait_10msTick);
            }
        }
        if(start_10msTick > now_10msTick)
        {
            uprintf("DEBUG: nanofet_waitRx 10msTick timer rolled over\r\n");
            return(0);
        }
    }

}









