/*
 * mms_spec.c   (ported from Persistor CF2 cronin.c)
 *
 *  Created on: Feb 3, 2024
 *      Author: tm   Ported from from Luke Colleti CF2 persistor code, per Yui private handoff of source Jan 29, 2024
 *      Note: Luke suddenly retired Feb 16, 2024
 */


#include "system.h"
#include "string.h"
#include "uartstdio.h"
#include "user_io.h"
#include "uart3.h"
#include "serial.h"
#include "sample.h"
#include "config.h"
#include "test.h"
#include "i2c_pcal64xx.h"
#include "i2c_bme280.h"
#include "mms_spec.h"
#include "apf_init.h"
#include "apf.h"



//LampPwrOff => mms_lampPwrOff

extern struct apfGlobals apf;          // defd in serial.h for now, APF globals from Persistor CF2 ISUS/DURA MSC1
extern unsigned char uart3_prn_buf[];

struct mmsDriver mms;

int     LogErrorMsg(char *emsg, int ecode, uint8_t outp);
void    ShortVectorMeanStdDev(unsigned short end, unsigned short data[], float *mean, float *stdev);

// routines for operating the MMS UV Spectrometer.   Includes FiberLite fxn

//int LampPwrOnUsingSpec( TUPort *tup, ushort *Data, uchar ShowRef )
int LampPwrOnUsingSpec( unsigned short *Data, uint8_t ShowRef )
{
    char ebuf[ERRBUFSIZE];
    unsigned long  scan_period;
    unsigned short scan_min, scan_max;
    int    i;
    float  volts, amps;
    //RTCTimer TmOut;

    if( apf.isus_lamp_pwr == TRUE )
        return( TRUE );

    if( apf.isus_spec_pwr != TRUE )
    {
        sprintf(ebuf, "Powerup Failure, Lamp requires spectromter to be powered");
        LogErrorMsg(ebuf, (int)LAMP_PWR_ON_FAILURE, apf.sys_message_enable);
        if( ShowRef == TRUE )
        printf("  %s\n", ebuf);
        return( ERROR );
    }

    if( ShowRef == TRUE )
        printf("  RefLimit = %hu\n", apf.isus_ref_limit);

    pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, LAMP_PWR_ON, HIGH);
    //DelaySecs( 1 );
    delay_sec(1);

    pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, (LAMP_DU_ENABLE | LAMP_W_ENABLE | LAMP_SHUT_ENABLE), HIGH);
    //DelayMilliSecs( 500 );
    delay_msec(500);

    i = 0;
    scan_max = 0;
    scan_period = 250UL;

    //RTCCountdownTimerSetup(&TmOut, APF_LAMP_IGNITE_TIMEOUT);
    uprintf("RTCCountdown...LampPwrOnUsingSpec in mms_spec.c");

    do{

      pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, LAMP_W_ENABLE, HIGH);
      //DelayMilliSecs( 100 );
      delay_msec(100);

      mms_singleScanSpectra( scan_period, Data );
      ShortVectorMinMax( 100, Data, &scan_min, &scan_max );

      pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, LAMP_W_ENABLE, LOW);
      //DelayMilliSecs( 100 );
      delay_msec(100);

      ++i;
      scan_period = scan_period + (unsigned long)(i*50);

      if( ShowRef == TRUE )
        printf("  %d, %hu\n", i, scan_max);

      if( (scan_max < apf.isus_ref_limit) && (i > 4) ){
        LampCloseShutter();
        LampOpenShutter();
        }
#ifdef APFTODO
      if( RTCCountdownTimeout(&TmOut) == true ){
         INA219_ReadVoltageCurrent( &volts, &amps );
         sprintf(ebuf, "Powerup Failure, Du Lamp could not turn on, RefLimit = %hu, VSYS = %.3f, ISYS = %.4e", isus_ref_limit, volts, amps);
         LogErrorMsg(ebuf, (int)LAMP_PWR_ON_FAILURE, sys_message_enable);
         if( ShowRef == TRUE )
           printf("  %s\n", ebuf);
         return( TIMEOUT );
        }
#endif
      }while( (scan_max < apf.isus_ref_limit) );

    DataMean = (float)scan_max;
    DataStdDev = (float)scan_min;

    apf.isus_lamp_pwr = TRUE;

    return( TRUE );

}



void LampOpenShutter(void)
{
    pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, LAMP_SHUT_ENABLE, HIGH);
    //DelayMilliSecs( 500 );
    delay_msec(500);
}

void LampCloseShutter(void)
{
    pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, LAMP_SHUT_ENABLE, LOW);
    //DelayMilliSecs( 500 );
    delay_msec(500);
}

int RefPwrOn(void)
{
    apf.isus_ref_pwr = TRUE;

    return( TRUE );
}

int RefPwrOff(void)
{
    apf.isus_ref_pwr = FALSE;

    return( TRUE );
}











#ifdef BADCODE
int mms_write_rtc_en_lo(unsigned int state)
{
    uprintf("mms_write_rtc_en_lo needs implementation, mms_spec.c");

}
#endif



int mms_lampPwrOn( void )   //;was LampPwrOn
{

    if( apf.isus_lamp_pwr == TRUE )
        return( TRUE );

    //pcal6416_write_port_bit(uint8_t regNum, uint8_t bitMask, uint32_t state)
    pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, LAMP_PWR_ON, 1);
    delay_sec( 1 );

    pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, (LAMP_DU_ENABLE | LAMP_W_ENABLE | LAMP_SHUT_ENABLE), 1);

    delay_msec( 500 );
    pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, LAMP_W_ENABLE, 0);
    delay_msec( 500 );
    pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, LAMP_W_ENABLE, 1);
    delay_msec( 500 );
    pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, LAMP_W_ENABLE, 0);
    delay_msec( 500 );
    pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, LAMP_W_ENABLE, 1);
    delay_msec( 500 );
    pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, LAMP_W_ENABLE, 0);
    delay_msec( 500 );

    apf.isus_lamp_pwr = TRUE;

    return( TRUE );
}

//int mms_lampPwrOnUsingSpec( TUPort *tup, ushort *Data, uchar ShowRef )
int mms_lampPwrOnUsingSpec(uint16_t *Data, uint8_t ShowRef )
{
    char ebuf[ERRBUFSIZE];
    unsigned long  scan_period;
    unsigned short scan_min, scan_max;
    int    i;
    float  volts, amps;

    //RTCTimer TmOut;

#ifdef APFTODO
    if( isus_lamp_pwr == TRUE )
        return( TRUE );

    if( isus_spec_pwr != TRUE ){
      sprintf(ebuf, "Powerup Failure, Lamp requires speectromter to be powered");
      LogErrorMsg(ebuf, (int)LAMP_PWR_ON_FAILURE, sys_message_enable);
      if( ShowRef == TRUE )
        printf("  %s\n", ebuf);
      return( ERROR );
    }

    if( ShowRef == TRUE )
      printf("  RefLimit = %hu\n", isus_ref_limit);

    pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, LAMP_PWR_ON, 1);
    delay_sec( 1 );

    pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, (LAMP_DU_ENABLE | LAMP_W_ENABLE | LAMP_SHUT_ENABLE), 1);
    delay_msec( 500 );

    i = 0;
    scan_max = 0;
    scan_period = 250UL;

    RTCCountdownTimerSetup(&TmOut, APF_LAMP_IGNITE_TIMEOUT);

    do{

      pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, LAMP_W_ENABLE, 1);
      delay_msec( 100 );

      mms_singleScanSpectra( scan_period, Data );
      ShortVectorMinMax( 100, Data, &scan_min, &scan_max );

      pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, LAMP_W_ENABLE, 0);
      delay_msec( 100 );

      ++i;
      scan_period = scan_period + (unsigned long)(i*50);

      if( ShowRef == TRUE )
        printf("  %d, %hu\n", i, scan_max);

      if( (scan_max < isus_ref_limit) && (i > 4) ){
        LampCloseShutter();
        LampOpenShutter();
        }

      if( RTCCountdownTimeout(&TmOut) == true ){
         INA219_ReadVoltageCurrent( &volts, &amps );
         sprintf(ebuf, "Powerup Failure, Du Lamp could not turn on, RefLimit = %hu, VSYS = %.3f, ISYS = %.4e", isus_ref_limit, volts, amps);
         LogErrorMsg(ebuf, (int)LAMP_PWR_ON_FAILURE, sys_message_enable);
         if( ShowRef == TRUE )
           printf("  %s\n", ebuf);
         return( TIMEOUT );
        }

      }while( (scan_max < isus_ref_limit) );

    DataMean = (float)scan_max;
    DataStdDev = (float)scan_min;
#endif
    apf.isus_lamp_pwr = TRUE;

    return( TRUE );

}

int mms_lampPwrOff( void )      // was LampPwrOff
{
#ifdef APFTODO
    // Turn Off all Lamp I/O Pins
    pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, (LAMP_DU_ENABLE | LAMP_W_ENABLE | LAMP_SHUT_ENABLE), 0);
    delay_msec( 250 );

    // Now Turn of 12VDC Lamp Power
    pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, LAMP_PWR_ON, 0);
#endif
    apf.isus_lamp_pwr = FALSE;

    return( TRUE );

}




//int log_write_errorMsg(char *ebuf, (int)SPEC_PWR_ON_FAILURE, sys_message_enable)
int log_write_errorMsg(char *ebuf, int errorCode, uint32_t enableFlg)
{
    uprintf("log_write_errorMsg needs imp\r\n");
}

#define TIMEOUT (-2)        // APFTODO - place this in the right .h file - LJC had it in zmodem.h wtf




//int SpecPwrOn( TUPort **tup )
int mms_specPwrOn(void)
{
    int retVal;
    int timeOutFlg;
    uint32_t tick_ms_delta, tick_ms_start;

#define MMS_ERRBUFSIZE      256
    char errbuf[MMS_ERRBUFSIZE];        // 256

    if( apf.isus_spec_pwr == TRUE )
        return( TRUE );

    tick_ms_start = Timer_1ms(false);
    timeOutFlg = 0;

    pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, SPEC_PWR_ON, 1);   // bit.02 was SPEC_PWR_BIT

    delay_msec(10);

    mms_enable_rs232_xcvr(1);   // on

    //wait for SPEC_CTS to go low (asserted)
    //it never will if spectrometer isn't connected as the RS232 receiver output is high via internal pull-down on its input
    while(1)
    {
        // APF todo, add timeout 500msec
        retVal = mms_get_cts();
        if(retVal == 0)
            break;

        tick_ms_delta = (Timer_1ms(false) - tick_ms_start);
        if(tick_ms_delta >= 500)
            timeOutFlg = 1;

        if(timeOutFlg == 1)     // 500ms
        {
            sprintf(errbuf, "Powerup Timeout, Spectrometer CTS never asserted");
            //LogErrorMsg(errbuf, (int)SPEC_PWR_ON_FAILURE, sys_message_enable);
            log_write_errorMsg(errbuf, (int)SPEC_PWR_ON_FAILURE, apf.sys_message_enable);
            return (TIMEOUT);
        }
    }


    //wait for SPEC_CTS to return back high (released)
    tick_ms_start = Timer_1ms(false);
    timeOutFlg = 0;
    while(1)
    {
        // APF todo, add timeout 500msec
        retVal = mms_get_cts();
        if(retVal == 1)
            break;

        tick_ms_delta = (Timer_1ms(false) - tick_ms_start);
        if(tick_ms_delta >= 500)
            timeOutFlg = 1;

        if(timeOutFlg == 1)     // 500ms
        {
            sprintf(errbuf, "Powerup Timeout, Spectrometer CTS never released");
            //LogErrorMsg(errbuf, (int)SPEC_PWR_ON_FAILURE, sys_message_enable);
            log_write_errorMsg(errbuf, (int)SPEC_PWR_ON_FAILURE, apf.sys_message_enable);
            return (TIMEOUT);
        }
    }


    //set SPEC_RTS high (released state)
    //PinSet( 15 );
    mms_set_rts(1);

    mms_uart_init(115200);

#ifdef NOCODE
    *tup = TUOpen(TPUChanFromPin(35), TPUChanFromPin(37), 115200, 0);
    if( *tup == 0 ) {
        sprintf(errbuf, "Init Error, Spectrometer TPU UART");
        LogErrorMsg(errbuf, (int)SPEC_TPU_INIT_ERROR, apf.sys_message_enable);
        return( ERROR );
    }
#endif


    //Delay1ms();
    delay_msec(1);

    //UARTFlushRx();      mms_set_rtssh( *tup );
    mms_rx_flush();

    apf.isus_spec_pwr = TRUE;

    return( TRUE );

}


//int SpecPwrOff( TUPort **tup )
int mms_specPwrOff(void)
{

    // PinSet( 15 );
    mms_set_rts(1);

    mms_enable_rs232_xcvr(1);   // on

    pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, SPEC_PWR_ON, 0);

    apf.isus_spec_pwr = FALSE;

    return( TRUE );

#ifdef APFTODO
    if( tup != 0 ) {
        TURxFlush( tup );
        TUClose( tup );
    }

    PinSet( 15 );


    RegIO_ClrBit( SPEC_232_ENABLE );

    pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, SPEC_PWR_ON, 0);

    isus_spec_pwr = FALSE;

    return( TRUE );
#endif
}




//int ScanSpectra( TUPort *tup, FILE *fptr, ushort scan_num, ushort *Data, uchar ScanType )
int mms_scanSpectra(FILE *fptr, uint16_t scan_num, uint16_t *Data, unsigned char ScanType )
{
//#ifdef APFTODO

    char   *ScanTypes[] = {"D", "S"};
    char   ebuf[ERRBUFSIZE];
    char   SpecCmd[128];
    int    i, loop;
    short  val1, val2;
    struct tm *t;
    //uint32_t    indx;
    uint32_t    retVal;
    int timeOutFlg;
    uint32_t tick_ms_delta, tick_ms_start;

    //RTCTimer TmOut;

    if( apf.isus_spec_pwr != TRUE )
      return( ERROR );

    if( ( ScanType < 0 ) || ( ScanType > 1 ) )
      return( ERROR );

    //negate RTS output
    //PinSet( 15 );
    //mms_
    mms_set_rts(1);

    //set spec trigger mode to "MBARI CUSTOM"
    //TUPuts(tup, "E5\r" );
    mms_tx_str("E5\r");
    delay_msec( 50 );

    //set spec scan buffer depth
    sprintf(SpecCmd, "R%hu\r", scan_num );
    //TUPuts( tup, SpecCmd );
    mms_tx_str( SpecCmd );
    delay_msec( 50 );

    //set spec integration period
    sprintf(SpecCmd, "I%lu\r", apf.isus_spec_period );
    //TUPuts( tup, SpecCmd );
    mms_tx_str( SpecCmd );
    delay_msec( 50 );

    for( loop=0; loop<scan_num; loop++ )
    {

        //HIH6130_ReadTempHumidity( &sysTemperature, &sysHumidity );
        bme280_read_data();   // why read humidity in the loop?

        //isus_sample_time = RTCGetTime( NULL, NULL );            //get time at start of data collection

        //start "automatic" scanning
        //TUPuts( tup, "S\r" );
        mms_tx_str( "S\r" );


        // wait for SPEC_CTS to go lo (active)
        //timeout in 500msec
        tick_ms_start = Timer_1ms(false);
        timeOutFlg = 0;
        while(1)
        {
            retVal = mms_get_cts();
            if(retVal == 0)
              break;

            tick_ms_delta = (Timer_1ms(false) - tick_ms_start);
            if(tick_ms_delta >= 500)
                timeOutFlg = 1;

            if(timeOutFlg == 1)     // 500ms
            {
                sprintf(ebuf, "Scan Timeout, Spectrometer CTS never asserted");
                LogErrorMsg(ebuf, (int)SPEC_CTS_SCAN_ERROR, apf.sys_message_enable);
                return( TIMEOUT );
            }

        }

        //wait for SPEC_CTS to return back high (released)
        tick_ms_start = Timer_1ms(false);
        timeOutFlg = 0;
        while(1)
        {
            // APF todo, add timeout 500msec
            retVal = mms_get_cts();
            if(retVal == 1)
              break;

            tick_ms_delta = (Timer_1ms(false) - tick_ms_start);
            if(tick_ms_delta >= 500)
              timeOutFlg = 1;

            if(timeOutFlg == 1)     // 500ms
            {
              sprintf(ebuf, "Scan Timeout, Spectrometer CTS never released");
              LogErrorMsg(ebuf, (int)SPEC_CTS_SCAN_ERROR, apf.sys_message_enable);
              return( TIMEOUT );
            }
        }


        //get data, one byte at a time, using RTS/CTS handshaking
        //TUPuts( tup, "g\r" );
        mms_tx_str( "g\r" );

        // wait for SPEC_CTS to go lo (active)
        //timeout in 500msec
        tick_ms_start = Timer_1ms(false);
        timeOutFlg = 0;
        while(1)
        {
            retVal = mms_get_cts();
            if(retVal == 0)
              break;

            tick_ms_delta = (Timer_1ms(false) - tick_ms_start);
            if(tick_ms_delta >= 500)
              timeOutFlg = 1;

            if(timeOutFlg == 1)     // 500ms
            {
              sprintf(ebuf, "Data Timeout, Spectrometer CTS never asserted");
              LogErrorMsg(ebuf, (int)SPEC_CTS_DATA_ERROR, apf.sys_message_enable);
              return( TIMEOUT );
            }
        }


        // MMS_UV Spectometer sends pixel 256 (400nm) first and pixel 1 (200nm) last.
        // Load data into array in the opposite oder, i.e., SpecData[0] = 200nm
        //TURxFlush( tup );
        mms_rx_flush();
        for( i = 255; i >= 0; i-- )
        {

            //PinClear( 15 );  //assert RTS output
            mms_set_rts(0);
            //val1 = TURxGetByteWithTimeout( tup, SPEC_DAT_TIMEOUT );                     /* get high byte of value */
            val1 = mms_rx_byte_timeout( SPEC_DAT_TIMEOUT );              // timeout in msec
            //PinSet( 15 );    //negate RTS output
            mms_set_rts(1);

            //Delay10us();
            delay_usec(10);

            //PinClear( 15 );  //assert RTS output
            mms_set_rts(0);      //assert RTS output
            //val2 = TURxGetByteWithTimeout( tup, SPEC_DAT_TIMEOUT );                     /* get low  byte of value */
            val2 = mms_rx_byte_timeout( SPEC_DAT_TIMEOUT );              // timeout in msec
            //PinSet( 15 );    //negate RTS output
            mms_set_rts(1);      //negate RTS output

            if( (val1 == -1) || (val2 == -1) )
            {
                //printf("Data Timeout, cell = %d\n", i);
                sprintf(ebuf, "Data Timeout, Data Byte Read");
                LogErrorMsg(ebuf, (int)SPEC_DAT_READ_ERROR, apf.sys_message_enable);
                return( TIMEOUT );
            }

            Data[i+(loop*256)] = ((val1 << 8) & 0xFF00) | (val2 & 0x00FF);

            if( i == 255 ) //set first clocked pixel value to zero
                Data[i+(loop*256)] = 0;

        } // for


          //wait for SPEC_CTS to return back high (released)
          tick_ms_start = Timer_1ms(false);
          timeOutFlg = 0;
          while(1)
          {
              // APF todo, add timeout 500msec
              retVal = mms_get_cts();
              if(retVal == 1)
                break;

              tick_ms_delta = (Timer_1ms(false) - tick_ms_start);
              if(tick_ms_delta >= 500)
                  timeOutFlg = 1;

              if(timeOutFlg == 1)     // 500ms
              {
                  sprintf(ebuf, "Data Timeout, Spectrometer CTS never released");
                  LogErrorMsg(ebuf, (int)SPEC_CTS_SCAN_ERROR, apf.sys_message_enable);
                  return( TIMEOUT );
              }
          }


        if( ScanType == DARKCURRENT_SCAN )
            ShortVectorMeanStdDev(100, &Data[(loop*256)], &DataMean, &DataStdDev);
        else
            ShortVectorMeanStdDev(256-1, &Data[(loop*256)], &DataMean, &DataStdDev);

        if( fptr != FNULL )
        {
            t = localtime(&apf.isus_sample_time);

            fprintf(fptr, "%s,%02d/%02d/%02d %02d:%02d:%02d,%.2f,%.2f,%.2f,", ScanTypes[ScanType], t->tm_mon+1, t->tm_mday, t->tm_year+1900, t->tm_hour, t->tm_min, t->tm_sec, sysTemperature, DataMean, DataStdDev);

            for(i = 0; i < 256; i++)
            {
                if(i != 255)
                    fprintf(fptr, "%hu,", Data[i+(loop*256)]);
                else
                    fprintf(fptr, "%hu", Data[i+(loop*256)]);
            }
            fprintf(fptr, "\n");
        }

    } /* end for loop */

    return( TRUE );
//#endif
}

//int SingleScanSpectra( TUPort *tup, unsigned long scan_period, ushort *Data )
int mms_singleScanSpectra(uint32_t scan_period, uint16_t *Data )
{
//#ifdef APFTODO
    char   ebuf[ERRBUFSIZE];
    char   SpecCmd[128];
    int    i;
    short  val1, val2;
    //RTCTimer TmOut;

        if( apf.isus_spec_pwr != TRUE )
          return( ERROR );

        //negate RTS output
        //PinSet( 15 );
        mms_set_rts(1);

        //set spec trigger mode to "MBARI CUSTOM"
        //TUPuts(tup, "E5\r" );
        mms_tx_str( "E5\r" );
        delay_msec( 50 );

        //set spec scan buffer depth
        sprintf(SpecCmd, "R1\r");
        //TUPuts( tup, SpecCmd );
        mms_tx_str( SpecCmd );
        delay_msec( 50 );

        //set spec integration period
        sprintf(SpecCmd, "I%lu\r", scan_period );
        //TUPuts( tup, SpecCmd );
        mms_tx_str( SpecCmd );
        delay_msec( 50 );

        //start "automatic" scanning
        //TUPuts( tup, "S\r" );
        mms_tx_str( "S\r" );

#ifdef APFTODO
        //wait for SPEC_CTS to go low (asserted)
        RTCCountdownTimerSetup(&TmOut, SPEC_CTS_TIMEOUT);       // timeout in 500ms
        do {
            if( RTCCountdownTimeout(&TmOut) == true ) {
                sprintf(ebuf, "Scan Timeout, Spectrometer CTS never asserted");
                LogErrorMsg(ebuf, (int)SPEC_CTS_SCAN_ERROR, sys_message_enable);
                return( TIMEOUT );
            }
        } while( RegIO_RdWord() & SPEC_CMOS_CTS );
#endif

        while(1)
        {
            // APFTODO add timeout
            if(mms_get_cts() == 0)
                break;
        }

#ifdef APFTODO
        //wait for SPEC_CTS to return back high (released)
        RTCCountdownTimerSetup(&TmOut, SPEC_INT_TIMEOUT);       // timeout in 15 seconds
        do {
            if( RTCCountdownTimeout(&TmOut) == true ) {
                sprintf(ebuf, "Scan Timeout, Spectrometer CTS never released");
                LogErrorMsg(ebuf, (int)SPEC_CTS_SCAN_ERROR, sys_message_enable);
                return( TIMEOUT );
            }
        } while( !(RegIO_RdWord() & SPEC_CMOS_CTS) );
#endif

        while(1)
        {
            // APFTODO add timeout
            if(mms_get_cts() == 1)
                break;
        }

        //get data, one byte at a time, using RTS/CTS handshaking
        //TUPuts( tup, "g\r" );
        mms_tx_str( "g\r" );

#ifdef APFTODO
        //wait for SPEC_CTS to go low (asserted)
        RTCCountdownTimerSetup(&TmOut, SPEC_CTS_TIMEOUT);       // timeout in 500ms
        do {
            if( RTCCountdownTimeout(&TmOut) == true ) {
                sprintf(ebuf, "Data Timeout, Spectrometer CTS never asserted");
                LogErrorMsg(ebuf, (int)SPEC_CTS_DATA_ERROR, sys_message_enable);
                return( TIMEOUT );
            }
        } while( RegIO_RdWord() & SPEC_CMOS_CTS );
#endif

        while(1)
        {
            // APFTODO add timeout
            if(mms_get_cts() == 0)
                break;
        }

        // MMS_UV Spectometer sends pixel 256 (400nm) first and pixel 1 (200nm) last.
        // Load data into array in the opposite oder, i.e., SpecData[0] = 200nm
        //TURxFlush( tup );
        mms_rx_flush();
        for( i = 255; i >= 0; i-- ){

           //PinClear( 15 );  //assert RTS output
           mms_set_rts(0);  //assert RTS output
           //val1 = TURxGetByteWithTimeout( tup, SPEC_DAT_TIMEOUT );                     /* get high byte of value */
           val1 = mms_rx_byte_timeout( SPEC_DAT_TIMEOUT );              // timeout in msec, get high byte
           //PinSet( 15 );    //negate RTS output
           mms_set_rts(1);      //negate RTS output

           //Delay10us();
           delay_usec(10);

           //PinClear( 15 );  //assert RTS output
           mms_set_rts(0);  //assert RTS output
           //val2 = TURxGetByteWithTimeout( tup, SPEC_DAT_TIMEOUT );                     /* get low  byte of value */
           val2 = mms_rx_byte_timeout( SPEC_DAT_TIMEOUT );              // timeout in msec, get lo byte
           //PinSet( 15 );    //negate RTS output
           mms_set_rts(1);      //negate RTS output

           if( (val1 == -1) || (val2 == -1) ){
              //printf("Data Timeout, cell = %d\n", i);
              sprintf(ebuf, "Data Timeout, Data Byte Read");
              LogErrorMsg(ebuf, (int)SPEC_DAT_READ_ERROR, apf.sys_message_enable);
              return( TIMEOUT );
              }

            Data[i] = ((val1 << 8) & 0xFF00) | (val2 & 0x00FF);

            if( i == 255 )          // MMS_UV supported, dropping support for MMS_UV_VIS
              Data[i] = 0;
#ifdef APFTODO
#if SPECTROMETER_TYPE == MMS_UV
            if( i == 255 )
              Data[i] = 0;
#elif SPECTROMETER_TYPE == MMS_UV_VIS
            if( i == 0 )
              Data[i] = Data[(i+1)];
#endif
#endif
        }

#ifdef APFTODO
        //wait for SPEC_CTS to return back high (released), all data has been sent!
        RTCCountdownTimerSetup(&TmOut, SPEC_DAT_TIMEOUT);       // timeout in 500ms
        do {
            if( RTCCountdownTimeout(&TmOut) == true ) {
                sprintf(ebuf, "Data Timeout, Spectrometer CTS never released");
                LogErrorMsg(ebuf, (int)SPEC_CTS_SCAN_ERROR, sys_message_enable);
                return( TIMEOUT );
            }
        } while( !(RegIO_RdWord() & SPEC_CMOS_CTS) );
#endif
        while(1)
        {
            // APFTODO add timeout
            if(mms_get_cts() == 1)
                break;
        }

        return( TRUE );
//#endif
}

//int TUGetsTmout(TUPort *tup, char *buf, ushort buflen, ushort seconds)
int mms_tuGetsTmout(char *buf, uint16_t buflen, uint16_t seconds)
{
#ifdef APFTODO
    register int c;
    register int nchars;
    RTCTimer TmOut;

    RTCCountdownTimerSetup( &TmOut, (1000000L * seconds) );         // set timeout

    nchars = 0;
    buf[0] = '\0';

    while(  RTCCountdownTimeout(&TmOut) != true ) {
        if ( TURxQueuedCount(tup) ) {
            switch( c = TURxGetByte(tup, false) ) {
            case '\n':
            case '\r':
                if(nchars > 0)
                    return( nchars );
                else
                    break;

            default:
                buf[nchars++] = (char)c;
                buf[nchars] = '\0';
                if ( nchars >= (buflen-1) )
                    return( nchars );
                break;
            } // end switch
        } // end if
    } // end while

    if( RTCCountdownTimeout(&TmOut) == true )
        return( TIMEOUT );

    return( nchars );


#endif
}

//int TUPuts(TUPort *tup, char *str)
int mms_tuPuts(char *str)
{
#ifdef APFTODO
    //spectrometer command interpreter only breaks on ^M
    int TUPuts(TUPort *tup, char *str)
    {

        while( *str ) {
            if( (*str == '\n') || (*str == '\r') ) {
                TUTxPutByte(tup, '\r', FALSE);
                break;
            }
            TUTxPutByte(tup, *str++, FALSE);
        }

        TUTxWaitCompletion(tup);

        return( TRUE );
    }
#endif
}


// Persistent/Config params, global state vars
//isus_spec_pwr










//#if  || BOARD_MSC == 2
#ifdef NOCODE

*******************************************************************************
** Summary  : Routines to access Zeiss MMS-UV Spectrometer fitted with Cronin PIC based RS232 interface
** Filename : cronin.c
** Author   : Luke Coletti
** Project  :
** Version  : 1.0
** Compiler : MetroWerks Code Warrior v8.3
** Created  : 12/15/14
** Archived :
*******************************************************************************
** Modification History:
** 01/02/15 : CF2 Port, LJC
*******************************************************************************/

#include    <cfxpico.h>
#include    <stdio.h>
#include    <stdlib.h>
#include    <math.h>
#include    <time.h>
#include    <pcal6416.h>
#include    <io_regs.h>
#include    <hih6130.h>
#include    <cronin.h>






int TUGetsTmout(TUPort *tup, char *buf, ushort buflen, ushort seconds)
{
    register int c;
    register int nchars;
    RTCTimer TmOut;

    RTCCountdownTimerSetup( &TmOut, (1000000L * seconds) );         // set timeout

    nchars = 0;
    buf[0] = '\0';

    while(  RTCCountdownTimeout(&TmOut) != true ) {
        if ( TURxQueuedCount(tup) ) {
            switch( c = TURxGetByte(tup, false) ) {
            case '\n':
            case '\r':
                if(nchars > 0)
                    return( nchars );
                else
                    break;

            default:
                buf[nchars++] = (char)c;
                buf[nchars] = '\0';
                if ( nchars >= (buflen-1) )
                    return( nchars );
                break;
            } // end switch
        } // end if
    } // end while

    if( RTCCountdownTimeout(&TmOut) == true )
        return( TIMEOUT );

    return( nchars );

}

//spectrometer command interpreter only breaks on ^M
int TUPuts(TUPort *tup, char *str)
{

    while( *str ) {
        if( (*str == '\n') || (*str == '\r') ) {
            TUTxPutByte(tup, '\r', FALSE);
            break;
        }
        TUTxPutByte(tup, *str++, FALSE);
    }

    TUTxWaitCompletion(tup);

    return( TRUE );

}

#endif



//-------------- Uart Interface ------------------


// mms_uart_init configures onchip uart3 peripheral, isr, and buffers.   Does not turn on 5v output
void mms_uart_init(unsigned long mms_baud)
 {
     uart3_init();

//#define MMS_BAUD    115200
     //uart3_setup(MMS_BAUD, 16000000);
     uart3_setup(mms_baud, 16000000);

     uart3_echo_set(0);
 }

/*
 * Apply power to the MMS Digital board and prepare uart3 and driver state vars.
 * Assumes mms_uart_init() is called.
 */
void mms_open(void)
{

    // on MPHOX, triple rs232 level translator is enabled for Optode J7, Console J6, and CTD J8 by console_enable/shutdown
    // on MFET, dual rs232 level translator is enabled for Optode J7 and Console J6 by console_enable/shutdown

#if BOARD_MFET >= 2  || BOARD_MPHOX >= 1  || BOARD_MSC == 2
    // turn on 5v supply on J7 MFET rev C, MPHOX rev A
    ROM_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_2, 0xff);    // PL2, pin 106 is 5vON
#endif

    //mms.state = 0;
    //mms.bufIndx = 0;

}

void mms_close(void)
{

#if BOARD_MFET >= 2  || BOARD_MPHOX >= 1  || BOARD_MSC == 2
    // turn on 5v supply on J7 MFET rev C, MPHOX rev A
    ROM_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_2, 0x00);    // PL2, pin 106 is 5vON
#endif

}

unsigned char mms_getc(void)
{
    unsigned char c;

    c = uart3_rx_byte();
    return c;
}

void mms_putc(unsigned char c)
{
    uart3_tx_byte(c);
}


uint32_t mms_get_cts(void)
{
    uint32_t state;
//APFTODO
    //state = read_
    // APF TODO
    // schematic, locate cts gpio
    // add code

    state = ROM_GPIOPinRead(GPIO_PORTP_BASE, GPIO_PIN_0);
    if(state > 0)
        state = 1;
    return(state);
}




// MMS spec power is controlled by i2c addressable latch, pcal6416, uart3 is used for spec serial, rts/cts MSC2:    MSC3: Spec_RTS=PD7, Spec_CTS=PD6
int mms_enable_rs232_xcvr(unsigned int state)
{
    //uprintf("mms_enable_rs232_xcvr needs imp\r\n");

    if(state == 0)
    {
        // transceiver off
#if BOARD_MSC == 2
        ROM_GPIOPinWrite(GPIO_PORTK_BASE, GPIO_PIN_0, 0x00);
#endif

    }
    else
    {
        // transceiver on
#if BOARD_MSC == 2
        ROM_GPIOPinWrite(GPIO_PORTK_BASE, GPIO_PIN_0, 0xFF);
#endif
    }

}

int mms_set_rts(unsigned int state)
{
    //uprintf("mms_set_rts needs imp\r\n");

    if(state == 0)
    {
#if BOARD_MSC == 2
    // PK0 = en_xcvr  (output)
    // PE0 = CTS (input)
    // PE1 = RTS (output)

    ROM_GPIOPinWrite(GPIO_PORTP_BASE, GPIO_PIN_1, 0x00);    // RTS = 0, asserted

#endif

    }
    else
    {
#if BOARD_MSC == 2
    ROM_GPIOPinWrite(GPIO_PORTP_BASE, GPIO_PIN_1, 0xFF);    // RTS = 1, inactive
#endif
    }
}


int mms_rxBytesAvail(void)
{
    return(uart3_rx_bytes_avail());
}


unsigned char mms_rx_byte_timeout(uint32_t timeout_ms)
{
    unsigned char c;
    uint32_t tickStart, ticks, tickDelta;

    tickStart = Timer_1ms(true);
    tickDelta = tickStart;


    while(1)
    {
        if( mms_rxBytesAvail() )
        {
            c = uart3_rx_byte();
            return(c);
        }

        ticks = (Timer_1ms(false) - tickStart);
        if(ticks > timeout_ms)
            return(0);

    }


}

void mms_rx_flush(void)
{
    uart3_rx_bufr_flush();
}

void mms_tx_flush(bool bDiscard)
{
    uart3_tx_bufr_flush(bDiscard);
}

//int mms_write(const char *pcBuf, uint32_t ui32Len)
//{
//    return(uart3_write(pcBuf, ui32Len));
//}

//void mms_buf_print(void)
//{
    //uprintf("%s", uart3_prn_buf);
//}

void mms_tx_str(unsigned char *strBuf)
{
    uprintf("%s", uart3_prn_buf);
}

void mms_tx_buf(unsigned char *strBuf ,unsigned int bufLen)
{
    uprintf("%s", uart3_prn_buf);
}

//int mms_buf_size(void)
//{
//    return(UART3_RX_BUFFER_SIZE);
//}

int mms_tx_buf_size(void)
{
    return(UART3_TX_BUFFER_SIZE);
}

int mms_rx_buf_size(void)
{
    return(UART3_RX_BUFFER_SIZE);
}

int mms_buf_write(unsigned char inChar)
{
    uart3_prn_buf[mms.bufIndx] = inChar;
    mms.bufIndx++;
    if(mms.bufIndx >= mms_tx_buf_size())
    {
        uprintf("\r\nDEBUG: error in mms spec driver bufIndx exceeds buf size, mms_spec.c\r\n");

        mms.bufIndx = mms_tx_buf_size() - 1;
        if(sys_data.diag > 0) uprintf("\r\nDEBUG: error in mms driver bufIndx exceeds buf size, mms_spec.c\r\n");
        wait_consoleTx();
        return(0);      // return of zero is buffer overflow error
    }
    return(1);
}

/*
 * mms_stateMachine
 *
 * pass in state=1 to start it, check for finish when returned state value is 0
 *
 */
int mms_stateMachine(int mmsState)
{
    int nextState = 0;
    unsigned int indx;
    unsigned int tick1, tick2;
    unsigned int wait_ms;
    unsigned char inChar;


    // example usage:
    //mmsState = 1;
    //mmsState = mms_statemachine(mmsState);     //pass in 1 to start the state machine, hereafter pass retVal
    //call statemachine repeatedly until mmsState == 0

    // mms_open


    // mms open (turn on power, wait 1msec, flush rx and tx bufs


    mms.state = mmsState;    // for debugging, mms.state not used at this time.

    switch(mmsState)
    {
        case 0:
            // do nothing, caller needs to pass in state=1 to start things
            return(0);

        case 1:
            mms_uart_init(115200);      // moved from init()
            mms_open();   // power on mms digital and Fiberlite 12v supply, 10msec with flush

            ROM_SysCtlDelay(MILLISECOND*10);  // power stable for 10mec
            mms_rx_flush();
            mms_tx_flush(true);   // true says discard

            mms.old_tick10ms = Timer_10ms(false);
            //uprintf("\r\nold tick10ms = %u \r\n", mms.old_tick10ms);
            mms.state = 2;
            return(2);


        case 2:
            if( mms_rxBytesAvail() )
            {
                inChar = mms_getc();
            }
            break;


        default:
            mms_close();
            return(0);
            //break;
    }


}

