/*
 * David Muller; Germán Alfaro
 * davehmuller@gmail.com; alfaro.germanevera@gmail.com
 * Thom Maughan, tm@mbari.org
 *
 *
 * TODO:
 *  change API to specify uart3
 */




#include "system.h"
#include "uartstdio.h"
#include "user_io.h"
#include "optode.h"

extern unsigned long Timer_10ms(bool reset);
// open / power on
//    time = 230 msec
//%
//!do sample
//    time = 1460 msec
//4831    856     232.810 93.450  26.906  26.489  28.780  37.056  8.276   548.4   628.1   -34.0
//#


#ifdef TIMINGFORSIMULATOR
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 = 1460 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 = 10 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: 5 [0x35]  time = 0 msec
RX:      [0x09]  time = 0 msec
RX: 1 [0x31]  time = 0 msec
RX: 6 [0x36]  time = 10 msec
RX: . [0x2e]  time = 0 msec
RX: 3 [0x33]  time = 0 msec
RX: 7 [0x37]  time = 0 msec
RX: 3 [0x33]  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: 1 [0x31]  time = 0 msec
RX: 0 [0x30]  time = 10 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: 8 [0x38]  time = 0 msec
RX: 9 [0x39]  time = 0 msec
RX: 0 [0x30]  time = 0 msec
RX:      [0x09]  time = 0 msec
RX: 1 [0x31]  time = 0 msec
RX: 4 [0x34]  time = 0 msec
RX: 7 [0x37]  time = 0 msec
RX: 0 [0x30]  time = 0 msec
RX: . [0x2e]  time = 0 msec
RX: 6 [0x36]  time = 0 msec
RX: 9 [0x39]  time = 0 msec
RX: 2 [0x32]  time = 0 msec
 [0x0d]  time = 10 msec
RX:
 [0x0a]  time = 0 msec
RX: # [0x23]  time = 0 msec
 [0x0d]  time = 0 msec
RX:
 [0x0a]  time = 0 msec
#endif



//Optode's UART module
#define OPTODE_UART_BASE           UART3_BASE
#define OPTODE_UART_PERIPH         SYSCTL_PERIPH_UART3
#define OPTODE_GPIO_PORT_BASE      GPIO_PORTC_BASE
#define OPTODE_GPIO_PERIPH         SYSCTL_PERIPH_GPIOC
#define OPTODE_GPIO_PIN_NAME_RX    GPIO_PC6_U3RX
#define OPTODE_GPIO_PIN_NAME_TX    GPIO_PC7_U3TX
#define OPTODE_GPIO_PIN_NUMBER_RX  GPIO_PIN_6
#define OPTODE_GPIO_PIN_NUMBER_TX  GPIO_PIN_7
#define OPTODE_UART_INT            INT_UART3

#define OPTODE_UART_RX_BUFFER_SIZE     256      //512  //128  Size for worst case string from Aanderaa Optode
#define OPTODE_UART_TX_BUFFER_SIZE     128

//static unsigned char optode_buff[OPTODE_BUFFER_SIZE];   // optode driver output buf, size defd in system.h

struct optodeDriver optode;   // struct defd in optode.h


 //MEASUREMENT     4831    856     O2Concentration[uM]     273.654 AirSaturation[%]        91.832  Temperature[Deg.C]      17.614  CalPhase[Deg]   28.336  TCPhase[Deg]    30.627  C1RPh[Deg]      38.676  C2RPh[Deg]      8.049   C1Amp[mV]        613.5   C2Amp[mV]       713.9   RawTemp[mV]     270.7

//
// %
// !do sample
// 4831    856     280.829 94.059  17.521  28.077  30.368  38.407  8.039   605.6   711.9   273.8
// #
// do sample
// 4831    856     280.826 94.062  17.523  28.076  30.367  38.403  8.037   605.6   711.5   273.7
// #
// do sample
// 4831    856     280.786 94.055  17.526  28.076  30.367  38.403  8.036   605.5   711.5   273.6
// #
//
// optode serial analyzer, bytes and times
// open
// RX: ŕ [0xe0]  time = 10 msec
// RX: % [0x25]  time = 220 msec
// TX: crlf
// RX: ! [0x21]  time = 10 msec
// TX: crlf do sample crlf
// RX: 4 [0x34]  time = 1820 msec
// RX: 8 [0x38]  time = 0 msec
// RX: 3 [0x33]  time = 0 msec
// RX: 1 [0x31]  time = 0 msec
// RX:      [0x09]  time = 0 msec
// RX: 8 [0x38]  time = 0 msec
// RX: 5 [0x35]  time = 10 msec
// RX: 6 [0x36]  time = 0 msec
// RX:      [0x09]  time = 0 msec


/*
 * ASCII characters.
 */
#define SPACE 0x20
#define OPENBRACE 0x7b
#define TAB 0x09

//char uart3_buff[OPTODE_BUFFER_SIZE];
//static unsigned char optode_buff[OPTODE_BUFFER_SIZE];   // optode driver output buf, size defd in optode.h

//SEE OPTODE MANUAL PAGES 17-19 TO LEARN MORE ABOUT RESPONSE TIMES
//AND ABOUT XON XOFF HANDSHAKES


// init backplane call
void optode_init(void)
{
    /*** Inititialize Optode on UART 3 ***/
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_1); // Optode power (PD1, pin 2)
    ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1, 0x00);    // Power off

    // set up UART3 to the optode, NOTE: ISR needs to be updated in tm4c123gh6pge_startup_ccs.c
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART3);
    ROM_GPIOPinConfigure(GPIO_PC6_U3RX);
    ROM_GPIOPinConfigure(GPIO_PC7_U3TX);
    ROM_GPIOPinTypeUART(GPIO_PORTC_BASE, GPIO_PIN_6 | GPIO_PIN_7);

    // Use the internal 16MHz oscillator as the UART clock source.
    UARTClockSourceSet(UART3_BASE, UART_CLOCK_PIOSC);

    //#define OPTODE_BAUD     9600  defd in optode.h, tm4c123gh6pge_startup_ccs.c needs UART3 isr plugged to match config
    optode_config(3, OPTODE_BAUD, 16000000); // Configure Optode UART  (9600,N,8,1)
    optode_echoSet(0);   // Disable echo to Optode

    //optode.state = 0;
    //optode.bufIndx = 0;
}


/*
 * Apply power to the Optode and prepare uart3 and driver state vars.
 * Assumes optode_init is called.
 */
void optode_open(void)
{

#if BOARD_MFET >= 2  || BOARD_MPHOX >= 1   //v3.9.2 bug fix - OPTODE not powered on due to incorrect conditional
	// turn on 5v supply on J7 MFET rev B
    ROM_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_2, 0xff);    // PL2, pin 106 is 5vON
#endif

    optode.state = 0;
    optode.bufIndx = 0;

}

void optode_close(void)
{

#if BOARD_MFET >= 2  || BOARD_MPHOX >= 1
    // turn off 5v supply on J7 MFET rev B
    ROM_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_2, 0x00);    // PL2, pin 106 is 5vON
#endif

}



/*
 * optode_stateMachine
 *
 * pass in state=1 to start it, check for finish when returned state value is 0
 *
 */
int optode_stateMachine(int optodeState)
{
    int nextState = 0;
    unsigned int indx;
    unsigned int tick1, tick2;
    unsigned int wait_ms;
    unsigned char inChar;


    // example usage:
    //optodeState = 1;
    //optodeState = optode_statemachine(optodeState);     //pass in 1 to start the state machine, hereafter pass retVal
    //call statemachine repeatedly until optodeState == 0

    // optode_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

    // optode open (turn on power, wait 1msec, flush rx and tx bufs


    optode.state = optodeState;    // for debugging, optode.state not used at this time.

    switch(optodeState)
    {
        case 0:
            // do nothing, caller needs to pass in state=1 to start things
            return(0);

        case 1:
            optode_open();   // power on optode 5v supply, 10msec with flush

            ROM_SysCtlDelay(MILLISECOND*1);  // power stable for 1mec (TODO, this could be trimmed down)
            optode_flushRx();
            optode_flushTx(true);   // true says discard

            optode.old_tick10ms = Timer_10ms(false);
            //uprintf("\nold tick10ms = %u \n", optode.old_tick10ms);
            optode.state = 2;
            return(2);


        case 2:
            //look for % char response within 600msec, then send crlf
            // if longer than 600msec, then next state = 0;
            if( optode_rxBytesAvail() )
            {
                inChar = optode_getc();
                //uprintf( "[%02x]", inChar );   // DEBUG
                if(inChar == '%')       // 0x25
                {
                    optode.old_tick10ms = Timer_10ms(false);
                    optode_putc(0x0d);  // CR=13
                    optode_putc(0x0a);  // LF=10
                    //uprintf("[GO3]");

                    // TODO - add a time out here
                    inChar = optode_getc();
                    //uprintf( "(%02x)", inChar );
                    if(inChar == '!')
                    {
                        optode_write("do sample\r\n",12 );
                        optode.old_tick10ms = Timer_10ms(false);
                        optode.state = 4;
                        return(4);
                    }

                    //return(3);
                }
            }

            // statemachine resilience - call as slow as once per 1.5sec in fast_sample
            optode.new_tick10ms = Timer_10ms(false);
            //if((optode.new_tick10ms - optode.old_tick10ms) >= 60)  // 600msec = 60*10msec
            if((optode.new_tick10ms - optode.old_tick10ms) >= 160)  // 1600msec = 160*10msec
            {
                if(sys_data.diag > 0) uprintf("\nOptode power on did not receive %% char delimiter in 600msec - check optode connection or setup\n");
                sprintf((char *)&optode.buf[0], "Optode not responding with %% char after power up");
                wait_consoleTx();
                optode_close();
                optode.state = -1;
                return(0);
            }
            optode.state = 2;
            return(2);

            // case 3 is gone
        case 3:
            // look for !, then send do_sample and crlf
            if( optode_rxBytesAvail() )
            {
                inChar = optode_getc();
                //uprintf( "(%02x)", inChar );
                if(inChar == '!')
                {
                    optode_write("do sample\r\n",12 );
                    optode.old_tick10ms = Timer_10ms(false);
                    optode.state = 4;
                    return(4);
                }
            }

            optode.new_tick10ms = Timer_10ms(false);
            if((optode.new_tick10ms - optode.old_tick10ms) >= 200)  //200 is 2sec, was 500msec = 50*10msec
            {
                if(sys_data.diag > 0) uprintf("\nOptode power on did not receive ! char delimiter in 2000msec - check optode connection or setup\n");
                sprintf((char *)&optode.buf[0], "Optode not responding with ! char after crlf");
                wait_consoleTx();
                optode_close();  // Close Optode, power off
                optode.state = -1;
                return(0);
            }
            optode.state = 3;
            return(3);

        case 4:
            // look for output terminated by crlf and # within 2000msec
            // trim crlf
            // optode_close
            // nextState = 0

            if( optode_rxBytesAvail() )      // if 1st char is available, get the entire do sample response string upto 1200msec
            {
                optode.old_tick10ms = Timer_10ms(false);  // reset timer
                while(1)       // expect no more than 100 chars
                {
#define WAIT10MSTICKVAL  5
                    wait_ms = wait_optodeRx(WAIT10MSTICKVAL);   // 50msec ought to be enough
                    if(wait_ms == WAIT10MSTICKVAL)
                    {
                        if(sys_data.diag > 0) uprintf("\nDEBUG: inter-character delay exceeded 50msec receiving do_sample string\n");
                        sprintf((char *)&optode.buf[0], "Optode Err ST4: inter-character delay exceeded 50msec receiving do_sample string");
                        wait_consoleTx();
                        optode_close();  // Close Optode, power off
                        return(0);
                    }
                    // check timeout (all chars should be received within 120msec (10msec per char * 91 chars + crlf + #) + pad)
                    inChar = optode_getc();

                    // 4831    856     280.786 94.055  17.526  28.076  30.367  38.403  8.036   605.5   711.5   273.6
                    // #
                    if(inChar == 0x0d)
                    {
                        inChar = 0;     //zero terminate optode.buf
                    }
                    if(inChar == '#')  // end of data
                    {
                        optode_close();  // Close Optode, power off
                        optode.state = 0;       // success
                        return(0);
                        //break;  // from while(1), do sample is done
                    }

                    // put the data into optode_buff[indx]
                    //optode.new_tick10ms = Timer_10ms(false);  // DEBUG
                    //tick2 = optode.new_tick10ms - optode.old_tick10ms;  // DEBUG
                    //uprintf(" %c", inChar );  // DEBUG
                    //uprintf("[%02x](%ums) ", inChar, tick2); //DEBUG

                    optode.buf[optode.bufIndx] = inChar;
                    optode.bufIndx++;
                    if(optode.bufIndx >= OPTODE_BUFFER_SIZE)
                    {
                        optode.bufIndx = OPTODE_BUFFER_SIZE-1;
                        if(sys_data.diag > 0) uprintf("\nDEBUG: error in optode driver bufIndx exceeds buf size, optode.c\n");
                        wait_consoleTx();
                        optode_close();  // Close Optode, power off
                        optode.state = -1;
                        return(0);
                    }


                }

            } // if rxByte

            optode.new_tick10ms = Timer_10ms(false);
            if((optode.new_tick10ms - optode.old_tick10ms) >= 500)  // 5000msec = 500*10msec
            {
                if(sys_data.diag > 0) uprintf("\nOptode power on did not receive sample string after do sample - check optode connection or setup\n");
                sprintf((char *)&optode.buf[0], "Optode not responding with sample string after do sample");
                optode_close();  // Close Optode, power off
                wait_consoleTx();
                optode.state = -1;
                return(0);
            }
            return(4);


        default:
            optode_close();
            return(0);
            //break;


    }


}



uint32_t optode_qa_test(void)
{
    //uint32_t timeout;
    //uint32_t ticks, tickDelta;

    int optodeState;


    //start the optode driver by passing 1, when complete, the statemachine returns 0
    optodeState = 1;
    optodeState = optode_stateMachine(optodeState);     //pass in 1 to start the state machine, hereafter pass retVal

    //tickDelta = Timer_1ms(false) - tickDelta;
    //ticks = (Timer_1ms(false) - tickStart);
    //uprintf("\nOptode St8Ma = %5u,   %5u", tickDelta, ticks);
    //tickDelta = ticks;


    while(1)
    {
        if(optodeState == 0)            // makes sure optode statemachine is finished
        {
            if(optode.state == -1)
                return(0);              // fail
            else
                return(1);              // pass
            break;
        }
        optodeState = optode_stateMachine(optodeState);

    }
    //tickDelta = Timer_1ms(false) - tickDelta;
    //ticks = (Timer_1ms(false) - tickStart);
    //if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\nOptode       = %5u,   %5u", tickDelta, ticks);
    //tickDelta = ticks;

    return(0);   // fail, never gets here
}



void optode_serial_analyzer(void)
{
    int nextState = 0;
    unsigned int indx;
    unsigned int tick1, tick2;
    unsigned char inChar;

    uprintf("optode serial analyzer, bytes and times\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

    while(1)
    {
        uprintf("open\n");
        optode_open();   // power on optode 5v supply
        optode.old_tick10ms = Timer_10ms(false);
        while(1)
        {
        // look for !, then send do_sample and crlf
            if( optode_rxBytesAvail() )
            {
               // [0x11]  time = 220 msec
               //% [0x25]  time = 0 msec
               //! [0x21]  time = 10 msec
               // [0x11]  time = 940 msec


#ifdef NOCODE
                optode 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

                optode.new_tick10ms = Timer_10ms(false);
                inChar = optode_getc();
                uprintf("RX: %c [0x%02x] ", inChar, inChar );
                tick1 = (optode.new_tick10ms - optode.old_tick10ms)*10;
                uprintf(" time = %u msec\n", tick1);
                optode.old_tick10ms = Timer_10ms(false);

                if(inChar == '%')
                {
                    uprintf("TX: crlf \n");
                    optode_putc(0x0d);  // CR=13
                    optode_putc(0x0a);  // LF=10
                }
                if(inChar == '!')
                {
                    uprintf("TX: crlf do sample crlf \n");
                    optode_putc(0x0d);  // CR=13
                    optode_putc(0x0a);  // LF=10
                    optode_write("do sample\r\n",12 );
                }
            }
            if(UARTRxBytesAvail())
            {
                inChar = UARTgetc();


                if(inChar == 24) // ctrl-x to exit loop
                {
                    optode_close();
                    ms_delay(500);
                    break;
                }


            }

        } // while(1)

        if(UARTRxBytesAvail())
        {
            inChar = UARTgetc();

            if(inChar == 24) // ctrl-x to exit loop
                break;

        }

    }


}

void optode_print_buf(void)
{
    uprintf("%s", optode.buf);
}

/*
 * optode_poll() tells the Optode to "do_sample."  Data is received
 * via the UART3 interrupt handler.
 */
void optode_poll(void)
{
	//send "do_sample\r\n" to Optode

    //optode_write(" ",1); //added space before do sample for 4835 optodes so only have to do 1 "do sample" 5/5/17 - TW
    //ROM_SysCtlDelay(100*MILLISECOND);
    optode_write("do sample\r\n",12 );
    ROM_SysCtlDelay(1000*MILLISECOND); //add 800 to try to limit "SYNTAX ERROR"
    //optode_flushRx();
    //ROM_SysCtlDelay(100*MILLISECOND);
 	//optode_write("do_sample\r\n", 12);
 	//SEE OPTODE MANUAL PAGES 17-19 TO LEARN MORE ABOUT RESPONSE TIMES
	//AND ABOUT XON XOFF HANDSHAKES
}






void optode_comm_test(void)
{
    unsigned char inChar;


    // Tested with Aanderaa Oxygen 5730 https://www.aanderaa.com/media/pdfs/d419_aanderaa_oxygen_sensor_5730.pdf
    uprintf("\nNote: smart sensor mode, disable data descriptor text, set flow control to none \n\n");
    uprintf("\n\nCommand procedure to setup Optode for numeric output:\n\n");
    uprintf("set passkey(1)\n");
    uprintf("set mode(smart sensor terminal)\n");
    uprintf("set enable polled mode(yes)\n");
    uprintf("save\n");
    uprintf("\n");
    uprintf("set passkey(1)\n");
    uprintf("set enable text(no)\n");
    uprintf("save\n");
    uprintf("\n");
    uprintf("set passkey(1000)\n");       // response: #
    uprintf("set flow control(none)\n");  // response: #
    uprintf("save\n");
    uprintf("\n");

    uprintf("do sample\n");
    uprintf("\nThis should return a sample: \t4831\t856\t286.196\t94.284\t16.728\t28.200\t30.491\t38.573\t8.082\t621.1\t720.0\t300.0\t\n\n");
    //uprintf("                               \t5860\t29\t-0.003\t16.892\t0.009\t998.802\t1472.435\t\n");
    uprintf("\n\n*Press CTRL-X to stop communicating with the Optode.*\n\n");

    //set up the optode
    optode_open();               // power on optode
    ROM_SysCtlDelay(500);       //500 is a guess
    //Optode_UARTwrite("do sample\r\n",12 );
    //ROM_SysCtlDelay(MILLISECOND*2000);

    while(1)
    {
        //if Optode sent anything, print it out on UART1 (the desktop)
        if( optode_rxBytesAvail() )      // Optode
        {
            uprintf( "%c", optode_getc() );
        }

        //if user types anything, send it to the Optode--exit on CTRL-X
        if(UARTRxBytesAvail())
        {
            inChar = UARTgetc();

            if(inChar == 13)     // If user hit carriage return, add a line feed
            {
                optode_putc(13);  // CR
                optode_putc(10);     // LF
            }
            else if(inChar == 24)
            {
                break;
            }
            else
            {
                optode_putc(inChar);
            }
        }
    }

    optode_close();  // Close up the Optode
}


/*
 * Parse the data returned by the Optode and put it in the output form we'd like (tab delimited etc.).
 * While parsing, move the data out of poll_Buffers.optodeBuffer and into the instrument buffer which
 * will have all of our measurements.
 */
// optode 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 parseOptodeData(void)
{

    // REWRITE OR GET RID OF THIS
#ifdef NOCODE
	//bytesRead holds the # of bytes received from Optode
	int bytesRead;
	int i;
	int bytes2delete = 0;

	bytesRead = uart3_rxBytesAvail();

	// DEBUG code
	//uprintf("optode bytesRead = %d\n", bytesRead);
	//uprintf("%s", uart3_buff);

	if(bytesRead)
	{
		uart3_gets(optode_buff, bytesRead);

		// look for first "integer" in Optode string. Will delete until then for junk characters. //YT 3/23/2015
		for(i = bytesRead; i >= 0; --i)
		{
			//uprintf("%c",optode_buff[i]);
			if(optode_buff[i] >47 & optode_buff[i] < 58)
			{
				bytes2delete = i;
			}
		}
		// End YT

		for(i = 0; i < bytesRead-bytes2delete; ++i)
		{
			optode_buff[i] = optode_buff[i+bytes2delete];	// Get rid of first few characters
		}
	}
	else
	{
	    strcpy(optode_buff, "NAN\tNAN\tNAN\tNAN\tNAN\tNAN\tNAN\tNAN\tNAN\tNAN\tNAN\tNAN\t");
	}
#endif
}


uint32_t wait_optodeRx(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( optode_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: wait_optodeRx 10msTick timer rolled over\n");
            return(0);
        }
    }

}

//--------------------------------------------

//*****************************************************************************
//
// This global controls whether or not we are echoing characters back to the
// transmitter.  By default, echo is enabled but if using this module as a
// convenient method of implementing a buffered serial interface over which
// you will be running an application protocol, you are likely to want to
// disable echo by calling UARTEchoSet(false).
//
//*****************************************************************************
static bool g_bDisableEcho;

//*****************************************************************************
//
// Output ring buffer.  Buffer is full if g_ui32UARTTxReadIndex is one ahead of
// g_ui32UARTTxWriteIndex.  Buffer is empty if the two indices are the same.
//
//*****************************************************************************
// static is used to set scope to this file (uart drivers have same var names scoped to file)
static unsigned char g_pcUARTTxBuffer[OPTODE_UART_TX_BUFFER_SIZE];
static volatile uint32_t g_ui32UARTTxWriteIndex = 0;
static volatile uint32_t g_ui32UARTTxReadIndex = 0;

//*****************************************************************************
//
// Input ring buffer.  Buffer is full if g_ui32UARTTxReadIndex is one ahead of
// g_ui32UARTTxWriteIndex.  Buffer is empty if the two indices are the same.
//
//*****************************************************************************
static unsigned char g_pcUARTRxBuffer[OPTODE_UART_RX_BUFFER_SIZE];
static volatile uint32_t g_ui32UARTRxWriteIndex = 0;
static volatile uint32_t g_ui32UARTRxReadIndex = 0;

//*****************************************************************************
//
// Macros to determine number of free and used bytes in the transmit buffer.
//
//*****************************************************************************
#define TX_BUFFER_USED          (GetBufferCount(&g_ui32UARTTxReadIndex,  \
                                                &g_ui32UARTTxWriteIndex, \
                                                OPTODE_UART_TX_BUFFER_SIZE))
#define TX_BUFFER_FREE          (OPTODE_UART_TX_BUFFER_SIZE - TX_BUFFER_USED)
#define TX_BUFFER_EMPTY         (IsBufferEmpty(&g_ui32UARTTxReadIndex,   \
                                               &g_ui32UARTTxWriteIndex))
#define TX_BUFFER_FULL          (IsBufferFull(&g_ui32UARTTxReadIndex,  \
                                              &g_ui32UARTTxWriteIndex, \
                                              OPTODE_UART_TX_BUFFER_SIZE))
#define ADVANCE_TX_BUFFER_INDEX(Index) \
                                (Index) = ((Index) + 1) % OPTODE_UART_TX_BUFFER_SIZE

//*****************************************************************************
//
// Macros to determine number of free and used bytes in the receive buffer.
//
//*****************************************************************************
#define RX_BUFFER_USED          (GetBufferCount(&g_ui32UARTRxReadIndex,  \
                                                &g_ui32UARTRxWriteIndex, \
                                                OPTODE_UART_RX_BUFFER_SIZE))
#define RX_BUFFER_FREE          (OPTODE_UART_RX_BUFFER_SIZE - RX_BUFFER_USED)
#define RX_BUFFER_EMPTY         (IsBufferEmpty(&g_ui32UARTRxReadIndex,   \
                                               &g_ui32UARTRxWriteIndex))
#define RX_BUFFER_FULL          (IsBufferFull(&g_ui32UARTRxReadIndex,  \
                                              &g_ui32UARTRxWriteIndex, \
                                              OPTODE_UART_RX_BUFFER_SIZE))
#define ADVANCE_RX_BUFFER_INDEX(Index) \
                                (Index) = ((Index) + 1) % OPTODE_UART_RX_BUFFER_SIZE

//*****************************************************************************
//
// The base address of the chosen UART.
//
//*****************************************************************************
static uint32_t g_ui32Base = 0;

//*****************************************************************************
//
// The list of possible base addresses for the console UART.
//
//*****************************************************************************
static const uint32_t g_ui32UARTBase[6] =
{
    UART0_BASE, UART1_BASE, UART2_BASE, UART3_BASE, UART4_BASE, UART5_BASE
};

//*****************************************************************************
//
// The list of possible interrupts for the console UART.
//
//*****************************************************************************
static const uint32_t g_ui32UARTInt[6] =
{
    INT_UART0, INT_UART1, INT_UART2, INT_UART3, INT_UART4, INT_UART5
};

//*****************************************************************************
//
// The port number in use.
//
//*****************************************************************************
static uint32_t g_ui32PortNum;

//*****************************************************************************
//
// The list of UART peripherals.
//
//*****************************************************************************
static const uint32_t g_ui32UARTPeriph[6] =
{
    SYSCTL_PERIPH_UART0, SYSCTL_PERIPH_UART1, SYSCTL_PERIPH_UART2, SYSCTL_PERIPH_UART3, SYSCTL_PERIPH_UART4, SYSCTL_PERIPH_UART5
};
//-------------------------------------------



//*****************************************************************************
//
//! Determines whether the ring buffer whose pointers and size are provided
//! is full or not.
//!
//! \param pui32Read points to the read index for the buffer.
//! \param pui32Write points to the write index for the buffer.
//! \param ui32Size is the size of the buffer in bytes.
//!
//! This function is used to determine whether or not a given ring buffer is
//! full.  The structure of the code is specifically to ensure that we do not
//! see warnings from the compiler related to the order of volatile accesses
//! being undefined.
//!
//! \return Returns \b true if the buffer is full or \b false otherwise.
//
//*****************************************************************************
static bool
IsBufferFull(volatile uint32_t *pui32Read,
             volatile uint32_t *pui32Write, uint32_t ui32Size)
{
    uint32_t ui32Write;
    uint32_t ui32Read;

    ui32Write = *pui32Write;
    ui32Read = *pui32Read;

    return((((ui32Write + 1) % ui32Size) == ui32Read) ? true : false);
}

//*****************************************************************************
//
//! Determines whether the ring buffer whose pointers and size are provided
//! is empty or not.
//!
//! \param pui32Read points to the read index for the buffer.
//! \param pui32Write points to the write index for the buffer.
//!
//! This function is used to determine whether or not a given ring buffer is
//! empty.  The structure of the code is specifically to ensure that we do not
//! see warnings from the compiler related to the order of volatile accesses
//! being undefined.
//!
//! \return Returns \b true if the buffer is empty or \b false otherwise.
//
//*****************************************************************************
static bool
IsBufferEmpty(volatile uint32_t *pui32Read,
              volatile uint32_t *pui32Write)
{
    uint32_t ui32Write;
    uint32_t ui32Read;

    ui32Write = *pui32Write;
    ui32Read = *pui32Read;

    return((ui32Write == ui32Read) ? true : false);
}

//*****************************************************************************
//
//! Determines the number of bytes of data contained in a ring buffer.
//!
//! \param pui32Read points to the read index for the buffer.
//! \param pui32Write points to the write index for the buffer.
//! \param ui32Size is the size of the buffer in bytes.
//!
//! This function is used to determine how many bytes of data a given ring
//! buffer currently contains.  The structure of the code is specifically to
//! ensure that we do not see warnings from the compiler related to the order
//! of volatile accesses being undefined.
//!
//! \return Returns the number of bytes of data currently in the buffer.
//
//*****************************************************************************
static uint32_t
GetBufferCount(volatile uint32_t *pui32Read,
               volatile uint32_t *pui32Write, uint32_t ui32Size)
{
    uint32_t ui32Write;
    uint32_t ui32Read;

    ui32Write = *pui32Write;
    ui32Read = *pui32Read;

    return((ui32Write >= ui32Read) ? (ui32Write - ui32Read) :
           (ui32Size - (ui32Read - ui32Write)));
}

//*****************************************************************************
//
// Take as many bytes from the transmit buffer as we have space for and move
// them into the UART transmit FIFO.
//
//*****************************************************************************
static void
UARTPrimeTransmit(uint32_t ui32Base)
{
    //
    // Do we have any data to transmit?
    //
    if(!TX_BUFFER_EMPTY)
    {
        //
        // Disable the UART interrupt.  If we don't do this there is a race
        // condition which can cause the read index to be corrupted.
        //
        MAP_IntDisable(g_ui32UARTInt[g_ui32PortNum]);

        //
        // Yes - take some characters out of the transmit buffer and feed
        // them to the UART transmit FIFO.
        //
        while(MAP_UARTSpaceAvail(ui32Base) && !TX_BUFFER_EMPTY)
        {
            MAP_UARTCharPutNonBlocking(ui32Base,
                                      g_pcUARTTxBuffer[g_ui32UARTTxReadIndex]);
            ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxReadIndex);
        }

        //
        // Reenable the UART interrupt.
        //
        MAP_IntEnable(g_ui32UARTInt[g_ui32PortNum]);
    }
}

//*****************************************************************************
//
//! Configures the MicroCAT UART console.
//!
//! \param ui32PortNum is the number of UART port to use for the serial console
//! (0-2)
//! \param ui32Baud is the bit rate that the UART is to be configured to use.
//! \param ui32SrcClock is the frequency of the source clock for the UART
//! module.
//!
//! This function will configure the specified serial port to be used as a
//! serial console.  The serial parameters are set to the baud rate
//! specified by the \e ui32Baud parameter and use 8 bit, no parity, and 1 stop
//! bit.
//!
//! This function must be called prior to using any of the other UART console
//! functions: uprintf() or UARTgets().  This function assumes that the
//! caller has previously configured the relevant UART pins for operation as a
//! UART rather than as GPIOs.
//!
//! \return None.
//
//*****************************************************************************
void
optode_config(uint32_t ui32PortNum, uint32_t ui32Baud, uint32_t ui32SrcClock)
{
    //
    // Check to make sure the UART peripheral is present.
    //
    if(!MAP_SysCtlPeripheralPresent(g_ui32UARTPeriph[ui32PortNum]))
    {
        return;
    }

    //
    // Select the base address of the UART.
    //
    g_ui32Base = g_ui32UARTBase[ui32PortNum];

    //
    // Enable the UART peripheral for use.
    //
    MAP_SysCtlPeripheralEnable(g_ui32UARTPeriph[ui32PortNum]);

    //
    // Configure the UART for Baud, n, 8, 1
    //
    MAP_UARTConfigSetExpClk(g_ui32Base, ui32SrcClock, ui32Baud,
                            (UART_CONFIG_PAR_NONE | UART_CONFIG_STOP_ONE |
                             UART_CONFIG_WLEN_8));

    //
    // Set the UART to interrupt whenever the TX FIFO is almost empty or
    // when any character is received.
    //
    MAP_UARTFIFOLevelSet(g_ui32Base, UART_FIFO_TX1_8, UART_FIFO_RX1_8);

    //
    // Flush both the buffers.
    //
    optode_flushRx();
    optode_flushTx(true);

    //
    // Remember which interrupt we are dealing with.
    //
    g_ui32PortNum = ui32PortNum;

    //
    // We are configured for buffered output so enable the master interrupt
    // for this UART and the receive interrupts.  We don't actually enable the
    // transmit interrupt in the UART itself until some data has been placed
    // in the transmit buffer.
    //
    MAP_UARTIntDisable(g_ui32Base, 0xFFFFFFFF);
    MAP_UARTIntEnable(g_ui32Base, UART_INT_RX | UART_INT_RT);
    MAP_IntEnable(g_ui32UARTInt[ui32PortNum]);

    //
    // Enable the UART operation.
    //
    MAP_UARTEnable(g_ui32Base);
}

//*****************************************************************************
//
//! Writes a string of characters to the UART output.
//!
//! \param pcBuf points to a buffer containing the string to transmit.
//! \param ui32Len is the length of the string to transmit.
//!
//! This function will transmit the string to the UART output.  The number of
//! characters transmitted is determined by the \e ui32Len parameter.  This
//! function does no interpretation or translation of any characters.  Since
//! the output is sent to a UART, any LF (/n) characters encountered will be
//! replaced with a CRLF pair.
//!
//! Besides using the \e ui32Len parameter to stop transmitting the string, if
//! a null character (0) is encountered, then no more characters will be
//! transmitted and the function will return.
//!
//! In non-buffered mode, this function is blocking and will not return until
//! all the characters have been written to the output FIFO.  In buffered mode,
//! the characters are written to the UART transmit buffer and the call returns
//! immediately.  If insufficient space remains in the transmit buffer,
//! additional characters are discarded.
//!
//! \return Returns the count of characters written.
//
//*****************************************************************************
int
optode_write(const char *pcBuf, uint32_t ui32Len)
{
    unsigned int uIdx;

    //
    // Send the characters
    //
    for(uIdx = 0; uIdx < ui32Len; uIdx++)
    {
        //
        // If the character to the UART is \n, then add a \r before it so that
        // \n is translated to \n\r in the output.
        //
        if(pcBuf[uIdx] == '\n')
        {
            if(!TX_BUFFER_FULL)
            {
                g_pcUARTTxBuffer[g_ui32UARTTxWriteIndex] = '\r';
                ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxWriteIndex);
            }
            else
            {
                //
                // Buffer is full - discard remaining characters and return.
                //
                break;
            }
        }

        //
        // Send the character to the UART output.
        //
        if(!TX_BUFFER_FULL)
        {
            g_pcUARTTxBuffer[g_ui32UARTTxWriteIndex] = pcBuf[uIdx];
            ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxWriteIndex);
        }
        else
        {
            //
            // Buffer is full - discard remaining characters and return.
            //
            break;
        }
    }

    //
    // If we have anything in the buffer, make sure that the UART is set
    // up to transmit it.
    //
    if(!TX_BUFFER_EMPTY)
    {
        UARTPrimeTransmit(g_ui32Base);
        MAP_UARTIntEnable(g_ui32Base, UART_INT_TX);
    }

    //
    // Return the number of characters written.
    //
    return(uIdx);
}

/*****************************************************************************
 * optode_putc()
 ******************************************************************************/

int optode_putc(const char c)
{

    // Send the character to the UART output.
	if(!TX_BUFFER_FULL)
	{
		g_pcUARTTxBuffer[g_ui32UARTTxWriteIndex] = c;
		ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxWriteIndex);
	}
	else return 0;	// Buffer full. No character written

	// Flush the TX buffer
	if(!TX_BUFFER_EMPTY)
    {
        UARTPrimeTransmit(g_ui32Base);
        MAP_UARTIntEnable(g_ui32Base, UART_INT_TX);
    }

    return 1; // Success
}

//*****************************************************************************
//
//! A simple UART based get string function, with some line processing.
//!
//! \param pcBuf points to a buffer for the incoming string from the UART.
//! \param ui32Len is the length of the buffer for storage of the string,
//! including the trailing 0.
//!
//! This function will receive a string from the UART input and store the
//! characters in the buffer pointed to by \e pcBuf.  The characters will
//! continue to be stored until a termination character is received.  The
//! termination characters are CR, LF, or ESC.  A CRLF pair is treated as a
//! single termination character.  The termination characters are not stored in
//! the string.  The string will be terminated with a 0 and the function will
//! return.
//!
//! In both buffered and unbuffered modes, this function will block until
//! a termination character is received.  If non-blocking operation is required
//! in buffered mode, a call to UARTPeek() may be made to determine whether
//! a termination character already exists in the receive buffer prior to
//! calling UARTgets().
//!
//! Since the string will be null terminated, the user must ensure that the
//! buffer is sized to allow for the additional null character.
//!
//! \return Returns the count of characters that were stored, not including
//! the trailing 0.
//
//*****************************************************************************
int
optode_gets(char *pcBuf, uint32_t ui32Len)
{
    uint32_t ui32Count = 0;
    int8_t cChar;
    //int i;

    //
    // Adjust the length back by 1 to leave space for the trailing
    // null terminator.
    //
    ui32Len--;

    //
    // Process characters until a newline is received.
    //
    while(1)
    {
        //
        // Read the next character from the receive buffer.
        //
        if(!RX_BUFFER_EMPTY)
        {
            cChar = g_pcUARTRxBuffer[g_ui32UARTRxReadIndex];
            ADVANCE_RX_BUFFER_INDEX(g_ui32UARTRxReadIndex);

            //
            // See if a newline or escape character was received.
            //
            if((cChar == '\r') || (cChar == '\n') || (cChar == 0x1b))
            {
                //
                // Stop processing the input and end the line.
                //
                break;
            }

            //
            // Process the received character as long as we are not at the end
            // of the buffer.  If the end of the buffer has been reached then
            // all additional characters are ignored until a newline is
            // received.
            //
            if(ui32Count < ui32Len)
            {
                //
                // Store the character in the caller supplied buffer.
                //
                pcBuf[ui32Count] = cChar;

                //
                // Increment the count of characters received.
                //
                ui32Count++;
            }
        }
    }

    //
    // Add a null termination to the string.
    //
    pcBuf[ui32Count] = 0;

    //
    // Return the count of int8_ts in the buffer, not counting the trailing 0.
    //
    return(ui32Count);
}

//*****************************************************************************
//
//! Read a single character from the UART, blocking if necessary.
//!
//! This function will receive a single character from the UART and store it at
//! the supplied address.
//!
//! In both buffered and unbuffered modes, this function will block until a
//! character is received.  If non-blocking operation is required in buffered
//! mode, a call to UARTRxAvail() may be made to determine whether any
//! characters are currently available for reading.
//!
//! \return Returns the character read.
//
//*****************************************************************************
unsigned char
optode_getc(void)
{
    unsigned char cChar;

    //
    // Wait for a character to be received.
    //
    while(RX_BUFFER_EMPTY)
    {
        //
        // Block waiting for a character to be received (if the buffer is
        // currently empty).
        //
    }

    //
    // Read a character from the buffer.
    //
    cChar = g_pcUARTRxBuffer[g_ui32UARTRxReadIndex];
    ADVANCE_RX_BUFFER_INDEX(g_ui32UARTRxReadIndex);

    //
    // Return the character to the caller.
    //
    return(cChar);
}

//*****************************************************************************
//
//! Returns the number of bytes available in the receive buffer.
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to determine the number
//! of bytes of data currently available in the receive buffer.
//!
//! \return Returns the number of available bytes.
//
//*****************************************************************************
#if defined(UART_BUFFERED) || defined(DOXYGEN)
int
optode_rxBytesAvail(void)
{
    return(RX_BUFFER_USED);
}
#endif

//*****************************************************************************
//
//! Returns the number of bytes free in the transmit buffer.
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to determine the amount
//! of space currently available in the transmit buffer.
//!
//! \return Returns the number of free bytes.
//
//*****************************************************************************
int
optode_txBytesFree(void)
{
    return(TX_BUFFER_FREE);
}

//*****************************************************************************
//
//! Looks ahead in the receive buffer for a particular character.
//!
//! \param ucChar is the character that is to be searched for.
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to look ahead in the
//! receive buffer for a particular character and report its position if found.
//! It is typically used to determine whether a complete line of user input is
//! available, in which case ucChar should be set to CR ('\\r') which is used
//! as the line end marker in the receive buffer.
//!
//! \return Returns -1 to indicate that the requested character does not exist
//! in the receive buffer.  Returns a non-negative number if the character was
//! found in which case the value represents the position of the first instance
//! of \e ucChar relative to the receive buffer read pointer.
//
//*****************************************************************************
int
optode_peek(unsigned char ucChar)
{
    int iCount;
    int iAvail;
    uint32_t ui32ReadIndex;

    //
    // How many characters are there in the receive buffer?
    //
    iAvail = (int)RX_BUFFER_USED;
    ui32ReadIndex = g_ui32UARTRxReadIndex;

    //
    // Check all the unread characters looking for the one passed.
    //
    for(iCount = 0; iCount < iAvail; iCount++)
    {
        if(g_pcUARTRxBuffer[ui32ReadIndex] == ucChar)
        {
            //
            // We found it so return the index
            //
            return(iCount);
        }
        else
        {
            //
            // This one didn't match so move on to the next character.
            //
            ADVANCE_RX_BUFFER_INDEX(ui32ReadIndex);
        }
    }

    //
    // If we drop out of the loop, we didn't find the character in the receive
    // buffer.
    //
    return(-1);
}

//*****************************************************************************
//
//! Flushes the receive buffer.
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to discard any data
//! received from the UART but not yet read using UARTgets().
//!
//! \return None.
//
//*****************************************************************************
void
optode_flushRx(void)
{
    uint32_t ui32Int;

    //
    // Temporarily turn off interrupts.
    //
    ui32Int = MAP_IntMasterDisable();

    //
    // Flush the receive buffer.
    //
    g_ui32UARTRxReadIndex = 0;
    g_ui32UARTRxWriteIndex = 0;

    //
    // If interrupts were enabled when we turned them off, turn them
    // back on again.
    //
    if(!ui32Int)
    {
        MAP_IntMasterEnable();
    }
}

//*****************************************************************************
//
//! Flushes the transmit buffer.
//!
//! \param bDiscard indicates whether any remaining data in the buffer should
//! be discarded (\b true) or transmitted (\b false).
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to flush the transmit
//! buffer, either discarding or transmitting any data received via calls to
//! uprintf() that is waiting to be transmitted.  On return, the transmit
//! buffer will be empty.
//!
//! \return None.
//
//*****************************************************************************
void
optode_flushTx(bool bDiscard)
{
    uint32_t ui32Int;

    //
    // Should the remaining data be discarded or transmitted?
    //
    if(bDiscard)
    {
        //
        // The remaining data should be discarded, so temporarily turn off
        // interrupts.
        //
        ui32Int = MAP_IntMasterDisable();

        //
        // Flush the transmit buffer.
        //
        g_ui32UARTTxReadIndex = 0;
        g_ui32UARTTxWriteIndex = 0;

        //
        // If interrupts were enabled when we turned them off, turn them
        // back on again.
        //
        if(!ui32Int)
        {
            MAP_IntMasterEnable();
        }
    }
    else
    {
        //
        // Wait for all remaining data to be transmitted before returning.
        //
        while(!TX_BUFFER_EMPTY)
        {
        }
    }
}

//*****************************************************************************
//
//! Enables or disables echoing of received characters to the transmitter.
//!
//! \param bEnable must be set to \b true to enable echo or \b false to
//! disable it.
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to control whether or not
//! received characters are automatically echoed back to the transmitter.  By
//! default, echo is enabled and this is typically the desired behavior if
//! the module is being used to support a serial command line.  In applications
//! where this module is being used to provide a convenient, buffered serial
//! interface over which application-specific binary protocols are being run,
//! however, echo may be undesirable and this function can be used to disable
//! it.
//!
//! \return None.
//
//*****************************************************************************
void
optode_echoSet(bool bEnable)
{
    g_bDisableEcho = !bEnable;
}

//*****************************************************************************
//
//! Handles UART interrupts.
//!
//! This function handles interrupts from the UART.  It will copy data from the
//! transmit buffer to the UART transmit FIFO if space is available, and it
//! will copy data from the UART receive FIFO to the receive buffer if data is
//! available.
//!
//! \return None.
//
//*****************************************************************************
void
optode_IntHandler(void)    // Optode_UARTIntHandler(void)
{
    uint32_t ui32Ints;
    int8_t cChar;
    int32_t i32Char;
    static bool bLastWasCR = false;

    //
    // Get and clear the current interrupt source(s)
    //
    ui32Ints = MAP_UARTIntStatus(g_ui32Base, true);
    MAP_UARTIntClear(g_ui32Base, ui32Ints);

    //
    // Are we being interrupted because the TX FIFO has space available?
    //
    if(ui32Ints & UART_INT_TX)
    {
        //
        // Move as many bytes as we can into the transmit FIFO.
        //
        UARTPrimeTransmit(g_ui32Base);

        //
        // If the output buffer is empty, turn off the transmit interrupt.
        //
        if(TX_BUFFER_EMPTY)
        {
            MAP_UARTIntDisable(g_ui32Base, UART_INT_TX);
        }
    }

    //
    // Are we being interrupted due to a received character?
    //
    if(ui32Ints & (UART_INT_RX | UART_INT_RT))
    {
        //
        // Get all the available characters from the UART.
        //
        while(MAP_UARTCharsAvail(g_ui32Base))
        {
            //
            // Read a character
            //
            i32Char = MAP_UARTCharGetNonBlocking(g_ui32Base);
            cChar = (unsigned char)(i32Char & 0xFF);

            //
            // If echo is disabled, we skip the various text filtering
            // operations that would typically be required when supporting a
            // command line.
            //
            if(!g_bDisableEcho)
            {
                //
                // Handle backspace by erasing the last character in the
                // buffer.
                //
                if(cChar == '\b')
                {
                    //
                    // If there are any characters already in the buffer, then
                    // delete the last.
                    //
                    if(!RX_BUFFER_EMPTY)
                    {
                        //
                        // Rub out the previous character on the users
                        // terminal.
                        //
                    	optode_write("\b \b", 3);

                        //
                        // Decrement the number of characters in the buffer.
                        //
                        if(g_ui32UARTRxWriteIndex == 0)
                        {
                            g_ui32UARTRxWriteIndex = OPTODE_UART_RX_BUFFER_SIZE - 1;    // Was UART_RX  25 Apr 2021
                        }
                        else
                        {
                            g_ui32UARTRxWriteIndex--;
                        }
                    }

                    //
                    // Skip ahead to read the next character.
                    //
                    continue;
                }

                //
                // If this character is LF and last was CR, then just gobble up
                // the character since we already echoed the previous CR and we
                // don't want to store 2 characters in the buffer if we don't
                // need to.
                //
                if((cChar == '\n') && bLastWasCR)
                {
                    bLastWasCR = false;
                    continue;
                }

                //
                // See if a newline or escape character was received.
                //
                if((cChar == '\r') || (cChar == '\n') || (cChar == 0x1b))
                {
                    //
                    // If the character is a CR, then it may be followed by an
                    // LF which should be paired with the CR.  So remember that
                    // a CR was received.
                    //
                    if(cChar == '\r')
                    {
                        bLastWasCR = 1;
                    }

                    //
                    // Regardless of the line termination character received,
                    // put a CR in the receive buffer as a marker telling
                    // UARTgets() where the line ends.  We also send an
                    // additional LF to ensure that the local terminal echo
                    // receives both CR and LF.
                    //
                    cChar = '\r';
                    optode_write("\n", 1);
                }
            }

            //
            // If there is space in the receive buffer, put the character
            // there, otherwise throw it away.
            //
            if(!RX_BUFFER_FULL)
            {
                //
                // Store the new character in the receive buffer
                //
                g_pcUARTRxBuffer[g_ui32UARTRxWriteIndex] =
                    (unsigned char)(i32Char & 0xFF);
                ADVANCE_RX_BUFFER_INDEX(g_ui32UARTRxWriteIndex);

                //
                // If echo is enabled, write the character to the transmit
                // buffer so that the user gets some immediate feedback.
                //
                if(!g_bDisableEcho)
                {
                	optode_write((const char *)&cChar, 1);
                }
            }
        }

        //
        // If we wrote anything to the transmit buffer, make sure it actually
        // gets transmitted.
        //
        UARTPrimeTransmit(g_ui32Base);
        MAP_UARTIntEnable(g_ui32Base, UART_INT_TX);
    }
}


#ifdef OLDCODE
/*
 * David Muller; Germán Alfaro
 * davehmuller@gmail.com; alfaro.germanevera@gmail.com
 * Thom Maughan, tm@mbari.org
 */


#include "system.h"
#include "optode.h"
#include "uartstdio.h"

extern unsigned long Timer_10ms(bool reset);

//Optode's UART module
#define OPTODE_UART_BASE           UART3_BASE
#define OPTODE_UART_PERIPH         SYSCTL_PERIPH_UART3
#define OPTODE_GPIO_PORT_BASE      GPIO_PORTC_BASE
#define OPTODE_GPIO_PERIPH         SYSCTL_PERIPH_GPIOC
#define OPTODE_GPIO_PIN_NAME_RX    GPIO_PC6_U3RX
#define OPTODE_GPIO_PIN_NAME_TX    GPIO_PC7_U3TX
#define OPTODE_GPIO_PIN_NUMBER_RX  GPIO_PIN_6
#define OPTODE_GPIO_PIN_NUMBER_TX  GPIO_PIN_7
#define OPTODE_UART_INT            INT_UART3

#define OPTODE_UART_RX_BUFFER_SIZE     256      //512  //128  Size for worst case string from Aanderaa Optode
#define OPTODE_UART_TX_BUFFER_SIZE     128

//static unsigned char optode_buff[OPTODE_BUFFER_SIZE];   // optode driver output buf, size defd in system.h

struct optodeDriver optode;   // struct defd in optode.h



//*****************************************************************************
//
// This global controls whether or not we are echoing characters back to the
// transmitter.  By default, echo is enabled but if using this module as a
// convenient method of implementing a buffered serial interface over which
// you will be running an application protocol, you are likely to want to
// disable echo by calling UARTEchoSet(false).
//
//*****************************************************************************
static bool g_bDisableEcho;

//*****************************************************************************
//
// Output ring buffer.  Buffer is full if g_ui32UARTTxReadIndex is one ahead of
// g_ui32UARTTxWriteIndex.  Buffer is empty if the two indices are the same.
//
//*****************************************************************************
// static is used to set scope to this file (uart drivers have same var names scoped to file)
static unsigned char g_pcUARTTxBuffer[OPTODE_UART_TX_BUFFER_SIZE];
static volatile uint32_t g_ui32UARTTxWriteIndex = 0;
static volatile uint32_t g_ui32UARTTxReadIndex = 0;

//*****************************************************************************
//
// Input ring buffer.  Buffer is full if g_ui32UARTTxReadIndex is one ahead of
// g_ui32UARTTxWriteIndex.  Buffer is empty if the two indices are the same.
//
//*****************************************************************************
static unsigned char g_pcUARTRxBuffer[OPTODE_UART_RX_BUFFER_SIZE];
static volatile uint32_t g_ui32UARTRxWriteIndex = 0;
static volatile uint32_t g_ui32UARTRxReadIndex = 0;

//*****************************************************************************
//
// Macros to determine number of free and used bytes in the transmit buffer.
//
//*****************************************************************************
#define TX_BUFFER_USED          (GetBufferCount(&g_ui32UARTTxReadIndex,  \
                                                &g_ui32UARTTxWriteIndex, \
                                                OPTODE_UART_TX_BUFFER_SIZE))
#define TX_BUFFER_FREE          (OPTODE_UART_TX_BUFFER_SIZE - TX_BUFFER_USED)
#define TX_BUFFER_EMPTY         (IsBufferEmpty(&g_ui32UARTTxReadIndex,   \
                                               &g_ui32UARTTxWriteIndex))
#define TX_BUFFER_FULL          (IsBufferFull(&g_ui32UARTTxReadIndex,  \
                                              &g_ui32UARTTxWriteIndex, \
                                              OPTODE_UART_TX_BUFFER_SIZE))
#define ADVANCE_TX_BUFFER_INDEX(Index) \
                                (Index) = ((Index) + 1) % OPTODE_UART_TX_BUFFER_SIZE

//*****************************************************************************
//
// Macros to determine number of free and used bytes in the receive buffer.
//
//*****************************************************************************
#define RX_BUFFER_USED          (GetBufferCount(&g_ui32UARTRxReadIndex,  \
                                                &g_ui32UARTRxWriteIndex, \
                                                OPTODE_UART_RX_BUFFER_SIZE))
#define RX_BUFFER_FREE          (OPTODE_UART_RX_BUFFER_SIZE - RX_BUFFER_USED)
#define RX_BUFFER_EMPTY         (IsBufferEmpty(&g_ui32UARTRxReadIndex,   \
                                               &g_ui32UARTRxWriteIndex))
#define RX_BUFFER_FULL          (IsBufferFull(&g_ui32UARTRxReadIndex,  \
                                              &g_ui32UARTRxWriteIndex, \
                                              OPTODE_UART_RX_BUFFER_SIZE))
#define ADVANCE_RX_BUFFER_INDEX(Index) \
                                (Index) = ((Index) + 1) % OPTODE_UART_RX_BUFFER_SIZE

//*****************************************************************************
//
// The base address of the chosen UART.
//
//*****************************************************************************
static uint32_t g_ui32Base = 0;

//*****************************************************************************
//
// The list of possible base addresses for the console UART.
//
//*****************************************************************************
static const uint32_t g_ui32UARTBase[6] =
{
    UART0_BASE, UART1_BASE, UART2_BASE, UART3_BASE, UART4_BASE, UART5_BASE
};

//*****************************************************************************
//
// The list of possible interrupts for the console UART.
//
//*****************************************************************************
static const uint32_t g_ui32UARTInt[6] =
{
    INT_UART0, INT_UART1, INT_UART2, INT_UART3, INT_UART4, INT_UART5
};

//*****************************************************************************
//
// The port number in use.
//
//*****************************************************************************
static uint32_t g_ui32PortNum;

//*****************************************************************************
//
// The list of UART peripherals.
//
//*****************************************************************************
static const uint32_t g_ui32UARTPeriph[6] =
{
    SYSCTL_PERIPH_UART0, SYSCTL_PERIPH_UART1, SYSCTL_PERIPH_UART2, SYSCTL_PERIPH_UART3, SYSCTL_PERIPH_UART4, SYSCTL_PERIPH_UART5
};

/*
 * ASCII characters.
 */
#define SPACE 0x20
#define OPENBRACE 0x7b
#define TAB 0x09

//char uart3_buff[OPTODE_BUFFER_SIZE];
//static unsigned char optode_buff[OPTODE_BUFFER_SIZE];   // optode driver output buf, size defd in optode.h

//SEE OPTODE MANUAL PAGES 17-19 TO LEARN MORE ABOUT RESPONSE TIMES
//AND ABOUT XON XOFF HANDSHAKES


// init backplane call
void optode_init(void)
{
    /*** Inititialize Optode on UART 3 ***/
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_1); // Optode power (PD1, pin 2)
    ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1, 0x00);    // Power off

    // set up UART to the optode
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART3);
    ROM_GPIOPinConfigure(GPIO_PC6_U3RX);
    ROM_GPIOPinConfigure(GPIO_PC7_U3TX);
    ROM_GPIOPinTypeUART(GPIO_PORTC_BASE, GPIO_PIN_6 | GPIO_PIN_7);

    // Use the internal 16MHz oscillator as the UART clock source.
    UARTClockSourceSet(UART3_BASE, UART_CLOCK_PIOSC);

    //#define OPTODE_BAUD     9600  defd in optode.h
    uart3_Config(3, OPTODE_BAUD, 16000000); // Configure Optode UART  (9600,N,8,1)
    uart3_echoSet(0);   // Disable echo to Optode

    //optode.state = 0;
   // optode.bufIndx = 0;
}


/*
 * Apply power to the Optode and prepare uart3 and driver state vars.
 * Assumes optode_init is called.
 */
void optode_open(void)
{
#if BOARD_SEAPHOX == 1
    ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1, 0xff);    // Power on
    ROM_GPIOPinWrite(GPIO_PORTK_BASE, GPIO_PIN_3, 0xff);    // COM1 on
#endif

#if BOARD_MPHOX >= 1        // was BOARD_MFET >= 2  || BOARD_MPHOX >= 1
    // turn on 5v supply on J7 MFET rev B
    ROM_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_2, 0xff);    // PL2, pin 106 is 5vON
#endif

    optode.state = 0;
    optode.bufIndx = 0;
    ROM_SysCtlDelay(MILLISECOND*1);  // power stable for 1mec
#if BOARD_MPHOX >= 1
    uart3_flushRx();
    uart3_flushTx(true);   // true says discard
#endif
}

void optode_close(void)
{

#if BOARD_MPHOX >= 1
    // turn off 5v supply on J7 MFET rev B
    ROM_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_2, 0x00);    // PL2, pin 106 is 5vON
#endif

}

/*
 * optode_stateMachine
 *
 * pass in state=1 to start it, check for finish when returned state value is 0
 *
 */
int optode_stateMachine(int optodeState)
{
    int nextState = 0;
    unsigned int indx;
    unsigned int tick1, tick2;
    unsigned char inChar;


    // example usage:
    //optodeState = 1;
    //optodeState = optode_statemachine(optodeState);     //pass in 1 to start the state machine, hereafter pass retVal
    //call statemachine repeatedly until optodeState == 0

    // optode_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

    // optode open (turn on power, wait 1msec, flush rx and tx bufs


    optode.state = optodeState;    // for debugging, optode.state not used at this time.

    switch(optodeState)
    {
        case 0:
            // do nothing, caller needs to pass in state=1 to start things
            return(0);
            //break;
        case 1:
            optode_open();   // power on optode 5v supply
 //           ROM_SysCtlDelay(MILLISECOND*1);  //
 //           uart3_flushRx();
 //           uart3_flushTx(true);   // true says discard
            optode.old_tick10ms = Timer_10ms(false);
            //uprintf("\nold tick10ms = %u \n", optode.old_tick10ms);
            return(2);
            break;

        case 2:
            //tick1 = ROM_SysTickValueGet();
            //uprintf("  case 2 tick:  %u ", tick1);
            //ROM_SysCtlDelay(MILLISECOND*1000);
            //tick2 = ROM_SysTickValueGet();
            //uprintf("  case 2 1000msec:  (%u  %u) = %u\n", tick1, tick2, ((tick1-tick2)&0x00ffffff));
            //24bit timer, count down
            // temp =  (ROM_SysTickValueGet() - temp) & SYSTICK_MAXVALUE; 0x00ffffff
            //If the SysTick counter is in fact 24  bits, then SYSTICK_MAXVALUE should be defined to 0x00ffffff

            //look for % char response within 600msec, then send crlf
            // if longer than 600msec, then next state = 0;
            // todo - add optode struct and state variables for timeout
            if( uart3_rxBytesAvail() )
            {
                inChar = uart3_getc();
                //uprintf( "%c", inChar );
                if(inChar == '%')
                {
                    optode.old_tick10ms = Timer_10ms(false);
                    uart3_putc(0x0d);  // CR=13
                    uart3_putc(0x0a);  // LF=10
                    return(3);
                }
            }

            optode.new_tick10ms = Timer_10ms(false);
            if((optode.new_tick10ms - optode.old_tick10ms) >= 60)  // 600msec = 60*10msec
            {
                //uprintf("\nOptode power on did not receive %% char delimiter in 600msec - check optode connection or setup\n");
                //sprintf((char *)&optode.buf[0], "Optode not responding with %% char after power up");


                uart3_putc(0x0d);  // CR=13
                uart3_putc(0x0a);  // LF=10
                //ROM_SysCtlDelay(MILLISECOND*500);  //DEBUG

                uart3_putc(0x0d);  // CR=13
                uart3_putc(0x0a);  // LF=10
                //ROM_SysCtlDelay(MILLISECOND*500);   // DEBUG

                uart3_write("do sample\r\n",12 );
                optode.old_tick10ms = Timer_10ms(false);
                return(4);
                //return(0);
            }

            return(2);
            //break;
        case 3:
            // look for !, then send do_sample and crlf
            if( uart3_rxBytesAvail() )
            {
                inChar = uart3_getc();
                //uprintf( "%c", inChar );
                if(inChar == '!')
                {
                    uart3_write("do sample\r\n",12 );
                    optode.old_tick10ms = Timer_10ms(false);
                    return(4);
                }
            }
            optode.new_tick10ms = Timer_10ms(false);
            if((optode.new_tick10ms - optode.old_tick10ms) >= 50)  // 500msec = 50*10msec
            {
                //uprintf("\nOptode power on did not receive ! char delimiter in 500msec - check optode connection or setup\n");
                sprintf((char *)&optode.buf[0], "Optode not responding with ! char after crlf");
                optode_close();  // Close Optode, power off
                return(0);
            }
            return(3);
            //break;
        case 4:
            // look for output terminated by crlf and # within 2000msec
            // trim crlf
            // optode_close
            // nextState = 0
            if( uart3_rxBytesAvail() )      // Optode
            {
                inChar = uart3_getc();
                // put the data into optode_buff[indx]
                //uprintf( "%c", inChar );

                optode.buf[optode.bufIndx] = inChar;
                optode.bufIndx++;
                if(optode.bufIndx >= OPTODE_BUFFER_SIZE)
                {
                    optode.bufIndx = OPTODE_BUFFER_SIZE-1;
                    uprintf("\nDEBUG: error in optode driver bufIndx exceeds buf size, optode.c\n");
                    optode_close();  // Close Optode, power off
                    return(0);
                }

            }

            if(inChar == '#')
            {

                //uprintf("\nDEBUG: Optode power off\n");

                // trim any leading chars, trim crlf and make it 0 terminated string
                for(indx=0; indx<optode.bufIndx; indx++)
                {
                    if(optode.buf[indx] == 0x0d)
                    {
                        optode.buf[indx] = 0;       // 0 terminated
                        break;
                    }

                }
                //uprintf("\nDEBUG OPTODE string=%s\n", &optode.buf[0]);
                optode_close();  // Close Optode, power off
                return(0);
                //break;  // from while(1), do sample is done
            }

            optode.new_tick10ms = Timer_10ms(false);
            if((optode.new_tick10ms - optode.old_tick10ms) >= 300)  // 2000msec = 200*10msec
            {
                //uprintf("\nOptode power on did not receive sample string after do sample - check optode connection or setup\n");
                sprintf((char *)&optode.buf[0], "Optode not responding with sample string after do sample");
                optode_close();  // Close Optode, power off
                return(0);
            }
            return(4);
            //break;

        default:
            return(0);
            //break;


    }


}

void optode_serial_analyzer(void)
{
    int nextState = 0;
    unsigned int indx;
    unsigned int tick1, tick2;
    unsigned char inChar;

    uprintf("optode serial analyzer, bytes and times\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

    while(1)
    {
        uprintf("open\n");
        optode_open();   // power on optode 5v supply
        optode.old_tick10ms = Timer_10ms(false);
        while(1)
        {
        // look for !, then send do_sample and crlf
            if( uart3_rxBytesAvail() )
            {
               // [0x11]  time = 220 msec
               //% [0x25]  time = 0 msec
               //! [0x21]  time = 10 msec
               // [0x11]  time = 940 msec


#ifdef NOCODE
                optode 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

                optode.new_tick10ms = Timer_10ms(false);
                inChar = uart3_getc();
                uprintf("RX: %c [0x%02x] ", inChar, inChar );
                tick1 = (optode.new_tick10ms - optode.old_tick10ms)*10;
                uprintf(" time = %u msec\n", tick1);
                optode.old_tick10ms = Timer_10ms(false);

                if(inChar == '%')
                {
                    uprintf("TX: crlf \n");
                    uart3_putc(0x0d);  // CR=13
                    uart3_putc(0x0a);  // LF=10
                }
                if(inChar == '!')
                {
                    uprintf("TX: crlf do sample crlf \n");
                    uart3_putc(0x0d);  // CR=13
                    uart3_putc(0x0a);  // LF=10
                    uart3_write("do sample\r\n",12 );
                }
            }
            if(UARTRxBytesAvail())
            {
                inChar = UARTgetc();


                if(inChar == 24) // ctrl-x to exit loop
                {
                    optode_close();
                    ms_delay(500);
                    break;
                }


            }

        } // while(1)

        if(UARTRxBytesAvail())
        {
            inChar = UARTgetc();

            if(inChar == 24) // ctrl-x to exit loop
                break;

        }

    }


}

void optode_print_buf(void)
{
    uprintf("%s", optode.buf);
}

/*
 * optode_poll() tells the Optode to "do_sample."  Data is received
 * via the UART3 interrupt handler.
 */
void optode_poll()
{
    //send "do_sample\r\n" to Optode

    //uart3_write(" ",1); //added space before do sample for 4835 optodes so only have to do 1 "do sample" 5/5/17 - TW
    //ROM_SysCtlDelay(100*MILLISECOND);
    uart3_write("do sample\r\n",12 );
    ROM_SysCtlDelay(1000*MILLISECOND); //add 800 to try to limit "SYNTAX ERROR"
    //uart3_flushRx();
    //ROM_SysCtlDelay(100*MILLISECOND);
    //uart3_write("do_sample\r\n", 12);
    //SEE OPTODE MANUAL PAGES 17-19 TO LEARN MORE ABOUT RESPONSE TIMES
    //AND ABOUT XON XOFF HANDSHAKES
}



/*
 * optode_close turns off the Optode (removes power
 * and disables the UART).
 */
void optode_close(void)
{

#if BOARD_MFET == 2 || BOARD_MPHOX >= 1
    // turn off 5v supply on J7 MFET rev B
    ROM_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_2, 0x00);    // PL2, pin 106 is 5vON
#endif

}



/*
 * Parse the data returned by the Optode and put it in the output form we'd like (tab delimited etc.).
 * While parsing, move the data out of poll_Buffers.optodeBuffer and into the instrument buffer which
 * will have all of our measurements.
 */
// optode 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 parseOptodeData(void)
{

    // REWRITE OR GET RID OF THIS
#ifdef NOCODE
    //bytesRead holds the # of bytes received from Optode
    int bytesRead;
    int i;
    int bytes2delete = 0;

    bytesRead = uart3_rxBytesAvail();

    // DEBUG code
    //uprintf("optode bytesRead = %d\n", bytesRead);
    //uprintf("%s", uart3_buff);

    if(bytesRead)
    {
        uart3_gets(optode_buff, bytesRead);

        // look for first "integer" in Optode string. Will delete until then for junk characters. //YT 3/23/2015
        for(i = bytesRead; i >= 0; --i)
        {
            //uprintf("%c",optode_buff[i]);
            if(optode_buff[i] >47 & optode_buff[i] < 58)
            {
                bytes2delete = i;
            }
        }
        // End YT

        for(i = 0; i < bytesRead-bytes2delete; ++i)
        {
            optode_buff[i] = optode_buff[i+bytes2delete];   // Get rid of first few characters
        }
    }
    else
    {
        strcpy(optode_buff, "NAN\tNAN\tNAN\tNAN\tNAN\tNAN\tNAN\tNAN\tNAN\tNAN\tNAN\tNAN\t");
    }
#endif
}

//*****************************************************************************
//
//! Determines whether the ring buffer whose pointers and size are provided
//! is full or not.
//!
//! \param pui32Read points to the read index for the buffer.
//! \param pui32Write points to the write index for the buffer.
//! \param ui32Size is the size of the buffer in bytes.
//!
//! This function is used to determine whether or not a given ring buffer is
//! full.  The structure of the code is specifically to ensure that we do not
//! see warnings from the compiler related to the order of volatile accesses
//! being undefined.
//!
//! \return Returns \b true if the buffer is full or \b false otherwise.
//
//*****************************************************************************
static bool
IsBufferFull(volatile uint32_t *pui32Read,
             volatile uint32_t *pui32Write, uint32_t ui32Size)
{
    uint32_t ui32Write;
    uint32_t ui32Read;

    ui32Write = *pui32Write;
    ui32Read = *pui32Read;

    return((((ui32Write + 1) % ui32Size) == ui32Read) ? true : false);
}

//*****************************************************************************
//
//! Determines whether the ring buffer whose pointers and size are provided
//! is empty or not.
//!
//! \param pui32Read points to the read index for the buffer.
//! \param pui32Write points to the write index for the buffer.
//!
//! This function is used to determine whether or not a given ring buffer is
//! empty.  The structure of the code is specifically to ensure that we do not
//! see warnings from the compiler related to the order of volatile accesses
//! being undefined.
//!
//! \return Returns \b true if the buffer is empty or \b false otherwise.
//
//*****************************************************************************
static bool
IsBufferEmpty(volatile uint32_t *pui32Read,
              volatile uint32_t *pui32Write)
{
    uint32_t ui32Write;
    uint32_t ui32Read;

    ui32Write = *pui32Write;
    ui32Read = *pui32Read;

    return((ui32Write == ui32Read) ? true : false);
}

//*****************************************************************************
//
//! Determines the number of bytes of data contained in a ring buffer.
//!
//! \param pui32Read points to the read index for the buffer.
//! \param pui32Write points to the write index for the buffer.
//! \param ui32Size is the size of the buffer in bytes.
//!
//! This function is used to determine how many bytes of data a given ring
//! buffer currently contains.  The structure of the code is specifically to
//! ensure that we do not see warnings from the compiler related to the order
//! of volatile accesses being undefined.
//!
//! \return Returns the number of bytes of data currently in the buffer.
//
//*****************************************************************************
static uint32_t
GetBufferCount(volatile uint32_t *pui32Read,
               volatile uint32_t *pui32Write, uint32_t ui32Size)
{
    uint32_t ui32Write;
    uint32_t ui32Read;

    ui32Write = *pui32Write;
    ui32Read = *pui32Read;

    return((ui32Write >= ui32Read) ? (ui32Write - ui32Read) :
           (ui32Size - (ui32Read - ui32Write)));
}

//*****************************************************************************
//
// Take as many bytes from the transmit buffer as we have space for and move
// them into the UART transmit FIFO.
//
//*****************************************************************************
static void
UARTPrimeTransmit(uint32_t ui32Base)
{
    //
    // Do we have any data to transmit?
    //
    if(!TX_BUFFER_EMPTY)
    {
        //
        // Disable the UART interrupt.  If we don't do this there is a race
        // condition which can cause the read index to be corrupted.
        //
        MAP_IntDisable(g_ui32UARTInt[g_ui32PortNum]);

        //
        // Yes - take some characters out of the transmit buffer and feed
        // them to the UART transmit FIFO.
        //
        while(MAP_UARTSpaceAvail(ui32Base) && !TX_BUFFER_EMPTY)
        {
            MAP_UARTCharPutNonBlocking(ui32Base,
                                      g_pcUARTTxBuffer[g_ui32UARTTxReadIndex]);
            ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxReadIndex);
        }

        //
        // Reenable the UART interrupt.
        //
        MAP_IntEnable(g_ui32UARTInt[g_ui32PortNum]);
    }
}

//*****************************************************************************
//
//! Configures the MicroCAT UART console.
//!
//! \param ui32PortNum is the number of UART port to use for the serial console
//! (0-2)
//! \param ui32Baud is the bit rate that the UART is to be configured to use.
//! \param ui32SrcClock is the frequency of the source clock for the UART
//! module.
//!
//! This function will configure the specified serial port to be used as a
//! serial console.  The serial parameters are set to the baud rate
//! specified by the \e ui32Baud parameter and use 8 bit, no parity, and 1 stop
//! bit.
//!
//! This function must be called prior to using any of the other UART console
//! functions: uprintf() or UARTgets().  This function assumes that the
//! caller has previously configured the relevant UART pins for operation as a
//! UART rather than as GPIOs.
//!
//! \return None.
//
//*****************************************************************************
void
uart3_Config(uint32_t ui32PortNum, uint32_t ui32Baud, uint32_t ui32SrcClock)
{
    //
    // Check to make sure the UART peripheral is present.
    //
    if(!MAP_SysCtlPeripheralPresent(g_ui32UARTPeriph[ui32PortNum]))
    {
        return;
    }

    //
    // Select the base address of the UART.
    //
    g_ui32Base = g_ui32UARTBase[ui32PortNum];

    //
    // Enable the UART peripheral for use.
    //
    MAP_SysCtlPeripheralEnable(g_ui32UARTPeriph[ui32PortNum]);

    //
    // Configure the UART for Baud, n, 8, 1
    //
    MAP_UARTConfigSetExpClk(g_ui32Base, ui32SrcClock, ui32Baud,
                            (UART_CONFIG_PAR_NONE | UART_CONFIG_STOP_ONE |
                             UART_CONFIG_WLEN_8));

    //
    // Set the UART to interrupt whenever the TX FIFO is almost empty or
    // when any character is received.
    //
    MAP_UARTFIFOLevelSet(g_ui32Base, UART_FIFO_TX1_8, UART_FIFO_RX1_8);

    //
    // Flush both the buffers.
    //
    uart3_flushRx();
    uart3_flushTx(true);

    //
    // Remember which interrupt we are dealing with.
    //
    g_ui32PortNum = ui32PortNum;

    //
    // We are configured for buffered output so enable the master interrupt
    // for this UART and the receive interrupts.  We don't actually enable the
    // transmit interrupt in the UART itself until some data has been placed
    // in the transmit buffer.
    //
    MAP_UARTIntDisable(g_ui32Base, 0xFFFFFFFF);
    MAP_UARTIntEnable(g_ui32Base, UART_INT_RX | UART_INT_RT);
    MAP_IntEnable(g_ui32UARTInt[ui32PortNum]);

    //
    // Enable the UART operation.
    //
    MAP_UARTEnable(g_ui32Base);
}

//*****************************************************************************
//
//! Writes a string of characters to the UART output.
//!
//! \param pcBuf points to a buffer containing the string to transmit.
//! \param ui32Len is the length of the string to transmit.
//!
//! This function will transmit the string to the UART output.  The number of
//! characters transmitted is determined by the \e ui32Len parameter.  This
//! function does no interpretation or translation of any characters.  Since
//! the output is sent to a UART, any LF (/n) characters encountered will be
//! replaced with a CRLF pair.
//!
//! Besides using the \e ui32Len parameter to stop transmitting the string, if
//! a null character (0) is encountered, then no more characters will be
//! transmitted and the function will return.
//!
//! In non-buffered mode, this function is blocking and will not return until
//! all the characters have been written to the output FIFO.  In buffered mode,
//! the characters are written to the UART transmit buffer and the call returns
//! immediately.  If insufficient space remains in the transmit buffer,
//! additional characters are discarded.
//!
//! \return Returns the count of characters written.
//
//*****************************************************************************
int
uart3_write(const char *pcBuf, uint32_t ui32Len)
{
    unsigned int uIdx;

    //
    // Send the characters
    //
    for(uIdx = 0; uIdx < ui32Len; uIdx++)
    {
        //
        // If the character to the UART is \n, then add a \r before it so that
        // \n is translated to \n\r in the output.
        //
        if(pcBuf[uIdx] == '\n')
        {
            if(!TX_BUFFER_FULL)
            {
                g_pcUARTTxBuffer[g_ui32UARTTxWriteIndex] = '\r';
                ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxWriteIndex);
            }
            else
            {
                //
                // Buffer is full - discard remaining characters and return.
                //
                break;
            }
        }

        //
        // Send the character to the UART output.
        //
        if(!TX_BUFFER_FULL)
        {
            g_pcUARTTxBuffer[g_ui32UARTTxWriteIndex] = pcBuf[uIdx];
            ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxWriteIndex);
        }
        else
        {
            //
            // Buffer is full - discard remaining characters and return.
            //
            break;
        }
    }

    //
    // If we have anything in the buffer, make sure that the UART is set
    // up to transmit it.
    //
    if(!TX_BUFFER_EMPTY)
    {
        UARTPrimeTransmit(g_ui32Base);
        MAP_UARTIntEnable(g_ui32Base, UART_INT_TX);
    }

    //
    // Return the number of characters written.
    //
    return(uIdx);
}

/*****************************************************************************
 * uart3_putc()
 ******************************************************************************/

int uart3_putc(const char c)
{

    // Send the character to the UART output.
    if(!TX_BUFFER_FULL)
    {
        g_pcUARTTxBuffer[g_ui32UARTTxWriteIndex] = c;
        ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxWriteIndex);
    }
    else return 0;  // Buffer full. No character written

    // Flush the TX buffer
    if(!TX_BUFFER_EMPTY)
    {
        UARTPrimeTransmit(g_ui32Base);
        MAP_UARTIntEnable(g_ui32Base, UART_INT_TX);
    }

    return 1; // Success
}

//*****************************************************************************
//
//! A simple UART based get string function, with some line processing.
//!
//! \param pcBuf points to a buffer for the incoming string from the UART.
//! \param ui32Len is the length of the buffer for storage of the string,
//! including the trailing 0.
//!
//! This function will receive a string from the UART input and store the
//! characters in the buffer pointed to by \e pcBuf.  The characters will
//! continue to be stored until a termination character is received.  The
//! termination characters are CR, LF, or ESC.  A CRLF pair is treated as a
//! single termination character.  The termination characters are not stored in
//! the string.  The string will be terminated with a 0 and the function will
//! return.
//!
//! In both buffered and unbuffered modes, this function will block until
//! a termination character is received.  If non-blocking operation is required
//! in buffered mode, a call to UARTPeek() may be made to determine whether
//! a termination character already exists in the receive buffer prior to
//! calling UARTgets().
//!
//! Since the string will be null terminated, the user must ensure that the
//! buffer is sized to allow for the additional null character.
//!
//! \return Returns the count of characters that were stored, not including
//! the trailing 0.
//
//*****************************************************************************
int
uart3_gets(char *pcBuf, uint32_t ui32Len)
{
    uint32_t ui32Count = 0;
    int8_t cChar;
    //int i;

    //
    // Adjust the length back by 1 to leave space for the trailing
    // null terminator.
    //
    ui32Len--;

    //
    // Process characters until a newline is received.
    //
    while(1)
    {
        //
        // Read the next character from the receive buffer.
        //
        if(!RX_BUFFER_EMPTY)
        {
            cChar = g_pcUARTRxBuffer[g_ui32UARTRxReadIndex];
            ADVANCE_RX_BUFFER_INDEX(g_ui32UARTRxReadIndex);

            //
            // See if a newline or escape character was received.
            //
            if((cChar == '\r') || (cChar == '\n') || (cChar == 0x1b))
            {
                //
                // Stop processing the input and end the line.
                //
                break;
            }

            //
            // Process the received character as long as we are not at the end
            // of the buffer.  If the end of the buffer has been reached then
            // all additional characters are ignored until a newline is
            // received.
            //
            if(ui32Count < ui32Len)
            {
                //
                // Store the character in the caller supplied buffer.
                //
                pcBuf[ui32Count] = cChar;

                //
                // Increment the count of characters received.
                //
                ui32Count++;
            }
        }
    }

    //
    // Add a null termination to the string.
    //
    pcBuf[ui32Count] = 0;

    //
    // Return the count of int8_ts in the buffer, not counting the trailing 0.
    //
    return(ui32Count);
}

//*****************************************************************************
//
//! Read a single character from the UART, blocking if necessary.
//!
//! This function will receive a single character from the UART and store it at
//! the supplied address.
//!
//! In both buffered and unbuffered modes, this function will block until a
//! character is received.  If non-blocking operation is required in buffered
//! mode, a call to UARTRxAvail() may be made to determine whether any
//! characters are currently available for reading.
//!
//! \return Returns the character read.
//
//*****************************************************************************
unsigned char
uart3_getc(void)
{
    unsigned char cChar;

    //
    // Wait for a character to be received.
    //
    while(RX_BUFFER_EMPTY)
    {
        //
        // Block waiting for a character to be received (if the buffer is
        // currently empty).
        //
    }

    //
    // Read a character from the buffer.
    //
    cChar = g_pcUARTRxBuffer[g_ui32UARTRxReadIndex];
    ADVANCE_RX_BUFFER_INDEX(g_ui32UARTRxReadIndex);

    //
    // Return the character to the caller.
    //
    return(cChar);
}

//*****************************************************************************
//
//! Returns the number of bytes available in the receive buffer.
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to determine the number
//! of bytes of data currently available in the receive buffer.
//!
//! \return Returns the number of available bytes.
//
//*****************************************************************************
#if defined(UART_BUFFERED) || defined(DOXYGEN)
int
uart3_rxBytesAvail(void)
{
    return(RX_BUFFER_USED);
}
#endif

//*****************************************************************************
//
//! Returns the number of bytes free in the transmit buffer.
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to determine the amount
//! of space currently available in the transmit buffer.
//!
//! \return Returns the number of free bytes.
//
//*****************************************************************************
int
uart3_txBytesFree(void)
{
    return(TX_BUFFER_FREE);
}

//*****************************************************************************
//
//! Looks ahead in the receive buffer for a particular character.
//!
//! \param ucChar is the character that is to be searched for.
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to look ahead in the
//! receive buffer for a particular character and report its position if found.
//! It is typically used to determine whether a complete line of user input is
//! available, in which case ucChar should be set to CR ('\\r') which is used
//! as the line end marker in the receive buffer.
//!
//! \return Returns -1 to indicate that the requested character does not exist
//! in the receive buffer.  Returns a non-negative number if the character was
//! found in which case the value represents the position of the first instance
//! of \e ucChar relative to the receive buffer read pointer.
//
//*****************************************************************************
int
uart3_peek(unsigned char ucChar)
{
    int iCount;
    int iAvail;
    uint32_t ui32ReadIndex;

    //
    // How many characters are there in the receive buffer?
    //
    iAvail = (int)RX_BUFFER_USED;
    ui32ReadIndex = g_ui32UARTRxReadIndex;

    //
    // Check all the unread characters looking for the one passed.
    //
    for(iCount = 0; iCount < iAvail; iCount++)
    {
        if(g_pcUARTRxBuffer[ui32ReadIndex] == ucChar)
        {
            //
            // We found it so return the index
            //
            return(iCount);
        }
        else
        {
            //
            // This one didn't match so move on to the next character.
            //
            ADVANCE_RX_BUFFER_INDEX(ui32ReadIndex);
        }
    }

    //
    // If we drop out of the loop, we didn't find the character in the receive
    // buffer.
    //
    return(-1);
}

//*****************************************************************************
//
//! Flushes the receive buffer.
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to discard any data
//! received from the UART but not yet read using UARTgets().
//!
//! \return None.
//
//*****************************************************************************
void
uart3_flushRx(void)
{
    uint32_t ui32Int;

    //
    // Temporarily turn off interrupts.
    //
    ui32Int = MAP_IntMasterDisable();

    //
    // Flush the receive buffer.
    //
    g_ui32UARTRxReadIndex = 0;
    g_ui32UARTRxWriteIndex = 0;

    //
    // If interrupts were enabled when we turned them off, turn them
    // back on again.
    //
    if(!ui32Int)
    {
        MAP_IntMasterEnable();
    }
}

//*****************************************************************************
//
//! Flushes the transmit buffer.
//!
//! \param bDiscard indicates whether any remaining data in the buffer should
//! be discarded (\b true) or transmitted (\b false).
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to flush the transmit
//! buffer, either discarding or transmitting any data received via calls to
//! uprintf() that is waiting to be transmitted.  On return, the transmit
//! buffer will be empty.
//!
//! \return None.
//
//*****************************************************************************
void
uart3_flushTx(bool bDiscard)
{
    uint32_t ui32Int;

    //
    // Should the remaining data be discarded or transmitted?
    //
    if(bDiscard)
    {
        //
        // The remaining data should be discarded, so temporarily turn off
        // interrupts.
        //
        ui32Int = MAP_IntMasterDisable();

        //
        // Flush the transmit buffer.
        //
        g_ui32UARTTxReadIndex = 0;
        g_ui32UARTTxWriteIndex = 0;

        //
        // If interrupts were enabled when we turned them off, turn them
        // back on again.
        //
        if(!ui32Int)
        {
            MAP_IntMasterEnable();
        }
    }
    else
    {
        //
        // Wait for all remaining data to be transmitted before returning.
        //
        while(!TX_BUFFER_EMPTY)
        {
        }
    }
}

//*****************************************************************************
//
//! Enables or disables echoing of received characters to the transmitter.
//!
//! \param bEnable must be set to \b true to enable echo or \b false to
//! disable it.
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to control whether or not
//! received characters are automatically echoed back to the transmitter.  By
//! default, echo is enabled and this is typically the desired behavior if
//! the module is being used to support a serial command line.  In applications
//! where this module is being used to provide a convenient, buffered serial
//! interface over which application-specific binary protocols are being run,
//! however, echo may be undesirable and this function can be used to disable
//! it.
//!
//! \return None.
//
//*****************************************************************************
void
uart3_echoSet(bool bEnable)
{
    g_bDisableEcho = !bEnable;
}

//*****************************************************************************
//
//! Handles UART interrupts.
//!
//! This function handles interrupts from the UART.  It will copy data from the
//! transmit buffer to the UART transmit FIFO if space is available, and it
//! will copy data from the UART receive FIFO to the receive buffer if data is
//! available.
//!
//! \return None.
//
//*****************************************************************************
void
uart3_IntHandler(void)    // Optode_UARTIntHandler(void)

{
    uint32_t ui32Ints;
    int8_t cChar;
    int32_t i32Char;
    static bool bLastWasCR = false;

    //
    // Get and clear the current interrupt source(s)
    //
    ui32Ints = MAP_UARTIntStatus(g_ui32Base, true);
    MAP_UARTIntClear(g_ui32Base, ui32Ints);

    //
    // Are we being interrupted because the TX FIFO has space available?
    //
    if(ui32Ints & UART_INT_TX)
    {
        //
        // Move as many bytes as we can into the transmit FIFO.
        //
        UARTPrimeTransmit(g_ui32Base);

        //
        // If the output buffer is empty, turn off the transmit interrupt.
        //
        if(TX_BUFFER_EMPTY)
        {
            MAP_UARTIntDisable(g_ui32Base, UART_INT_TX);
        }
    }

    //
    // Are we being interrupted due to a received character?
    //
    if(ui32Ints & (UART_INT_RX | UART_INT_RT))
    {
        //
        // Get all the available characters from the UART.
        //
        while(MAP_UARTCharsAvail(g_ui32Base))
        {
            //
            // Read a character
            //
            i32Char = MAP_UARTCharGetNonBlocking(g_ui32Base);
            cChar = (unsigned char)(i32Char & 0xFF);

            //
            // If echo is disabled, we skip the various text filtering
            // operations that would typically be required when supporting a
            // command line.
            //
            if(!g_bDisableEcho)
            {
                //
                // Handle backspace by erasing the last character in the
                // buffer.
                //
                if(cChar == '\b')
                {
                    //
                    // If there are any characters already in the buffer, then
                    // delete the last.
                    //
                    if(!RX_BUFFER_EMPTY)
                    {
                        //
                        // Rub out the previous character on the users
                        // terminal.
                        //
                        uart3_write("\b \b", 3);

                        //
                        // Decrement the number of characters in the buffer.
                        //
                        if(g_ui32UARTRxWriteIndex == 0)
                        {
                            g_ui32UARTRxWriteIndex = OPTODE_UART_RX_BUFFER_SIZE - 1;
                        }
                        else
                        {
                            g_ui32UARTRxWriteIndex--;
                        }
                    }

                    //
                    // Skip ahead to read the next character.
                    //
                    continue;
                }

                //
                // If this character is LF and last was CR, then just gobble up
                // the character since we already echoed the previous CR and we
                // don't want to store 2 characters in the buffer if we don't
                // need to.
                //
                if((cChar == '\n') && bLastWasCR)
                {
                    bLastWasCR = false;
                    continue;
                }

                //
                // See if a newline or escape character was received.
                //
                if((cChar == '\r') || (cChar == '\n') || (cChar == 0x1b))
                {
                    //
                    // If the character is a CR, then it may be followed by an
                    // LF which should be paired with the CR.  So remember that
                    // a CR was received.
                    //
                    if(cChar == '\r')
                    {
                        bLastWasCR = 1;
                    }

                    //
                    // Regardless of the line termination character received,
                    // put a CR in the receive buffer as a marker telling
                    // UARTgets() where the line ends.  We also send an
                    // additional LF to ensure that the local terminal echo
                    // receives both CR and LF.
                    //
                    cChar = '\r';
                    uart3_write("\n", 1);
                }
            }

            //
            // If there is space in the receive buffer, put the character
            // there, otherwise throw it away.
            //
            if(!RX_BUFFER_FULL)
            {
                //
                // Store the new character in the receive buffer
                //
                g_pcUARTRxBuffer[g_ui32UARTRxWriteIndex] =
                    (unsigned char)(i32Char & 0xFF);
                ADVANCE_RX_BUFFER_INDEX(g_ui32UARTRxWriteIndex);

                //
                // If echo is enabled, write the character to the transmit
                // buffer so that the user gets some immediate feedback.
                //
                if(!g_bDisableEcho)
                {
                    uart3_write((const char *)&cChar, 1);
                }
            }
        }

        //
        // If we wrote anything to the transmit buffer, make sure it actually
        // gets transmitted.
        //
        UARTPrimeTransmit(g_ui32Base);
        MAP_UARTIntEnable(g_ui32Base, UART_INT_TX);
    }
}

#endif
