/*
 * ocr.c
 *
 * Ocean Multi-spectral radiometer   Seabird OCR-504  https://www.seabird.com/multispectral-radiometers/product?id=60762467731
 * Fast sampling rate (7–24 Hz optional), 10 degree fov, 4 wavelengths available, UV wavelengths of 305, 325, 340, and 380 nm
 *
 *  Created on: Nov 15, 2021
 *      Author: tm
 */

#include "system.h"
#include "uartstdio.h"
#include "user_io.h"
#include "uart3.h"
#include "ocr.h"

/*
 * New Driver Instructions
 *
 * Driver name - ocr.c, ocr.h (could have been ocr-504.c)
 *
 * ocr_init (from optode_init)
 *
 * ocr driver primitives (getc, putc, etc), wrappers on uart3 primitives
 *
 * ocr comm test (make callable from "Communicate with Instrument" test menu in test.c)
 *
 * When properly setup, the OCR-504 will output when an <ENTER> key is received:
 * SATFI42247      0.1297  0.0154  -0.0071 0.0060
 *
 *
 */



extern unsigned long Timer_1ms(bool reset);

// global driver stuct
struct ocrDriver ocr;   // struct defd in ocr.h

// Uses UART3 (same as Optode) on J7 MFET or MPHOX

void ocr_init(void)
{
    uart3_init();

    uart3_setup(OCR_BAUD, 16000000);

    uart3_echo_set(0);
}


/*
 * Apply power to the OCR and prepare uart3 and driver state vars.
 * Assumes ocr_init is called.
 */
void ocr_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
    // turn on 5v supply on J7 MFET rev B
    ROM_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_2, 0xff);    // PL2, pin 106 is 5vON
#endif

    ocr.dataCnt = 1;
    ocr.state = 0;
    ocr.bufIndx = 0;

}


void ocr_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

}


// ocr driver primitives, wrap uart3 primitives

unsigned char ocr_getc(void)
{
    unsigned char c;

    c = uart3_rx_byte();
    return c;
}

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

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

void ocr_flushRx(void)
{
    uart3_rx_bufr_flush();
}

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

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

// maxlen is buffer max, returns only when newline chars are received (0x0D or 0x0A)
int ocr_rx_str(char *pcBuf, uint32_t ui32Len)
{
    return(uart3_rx_str(pcBuf, ui32Len));
}

// returns after receiving ui32Len bytes
int ocr_rx_buf(unsigned char *pcBuf, uint32_t ui32Len)
{
    return(uart3_rx_buf(pcBuf, ui32Len));
}


/*
 * ocr_stateMachine
 *
 * pass in state=1 to start it, check for finish when returned state value is 0
 *
 */
int ocr_stateMachine(int ocrState)
{
    int nextState = 0;
    unsigned int indx;
    unsigned int tick1, tick2;
    unsigned int wait_ms;
    unsigned char inChar;


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

    // ocr_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

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

#define ST_NADA         0
#define ST_INIT         1
#define ST_PWRON_DELAY  2
#define ST_REQ_DATA     3
#define ST_RX_START     4
#define ST_RX_DATA      5
#define ST_REPEAT       6
#define ST_OCR_CLOSE    7

    ocr.state = ocrState;    // for debugging, ocr.state not used at this time.

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

        case ST_INIT:
            ocr_init();         // moved from init()
            ocr_open();         // power on ocr 6v supply, 10msec with flush

            ROM_SysCtlDelay(MILLISECOND*1);  // power stable for 1mec (TODO, figure 'right' delay)
            ocr_flushRx();
            ocr_flushTx(true);   // true says discard

            ocr.old_tick10ms = Timer_10ms(false);

            //ROM_SysCtlDelay(MILLISECOND*750);

            ocr.state = ST_PWRON_DELAY;
            return(ST_PWRON_DELAY);

        case ST_PWRON_DELAY:  // 800msec
            ocr.new_tick10ms = Timer_10ms(false);
            if((ocr.new_tick10ms - ocr.old_tick10ms) >= 80)  // 800msec = 80*10msec
            {
                ocr.old_tick10ms = ocr.new_tick10ms;
                ocr.state = ST_REQ_DATA;
                return(ST_REQ_DATA);
            }
            ocr.state = ST_PWRON_DELAY;
            return(ST_PWRON_DELAY);

        case ST_REQ_DATA:
            //send <ENTER> to get OCR data
            ocr_putc(0x0d);  // CR=13
            ocr_putc(0x0a);  // LF=10

            ocr.state = ST_RX_START;
            return(ST_RX_START);

        case ST_RX_START:
            // receive:   SATFI42247      0.1297  0.0154  -0.0071 0.0060
            // run a timeout of 1.
            if( ocr_rxBytesAvail() )
            {
                inChar = ocr_getc();
                //uprintf( "[%02x]", inChar );   // DEBUG
                if(inChar == 'S')
                {
                    ocr.old_tick10ms = Timer_10ms(false);

                    ocr.bufIndx = 0;
                    ocr.buf[ocr.bufIndx] = inChar;
                    ocr.bufIndx++;

                    ocr.state = ST_RX_DATA;
                    return(ST_RX_DATA);
                }
            }

            // statemachine resilience - call as slow as once per 1.5sec in fast_sample
            ocr.new_tick10ms = Timer_10ms(false);
            if((ocr.new_tick10ms - ocr.old_tick10ms) >= 160)  // 1600msec = 160*10msec
            {
                if(sys_data.diag > 0) uprintf("\r\nOCR power on did not receive expected response to CR-LF in 1600msec - check ocr connection or setup\r\n");
                sprintf((char *)&ocr.buf[0], "OCR not responding to CR-LF after power up");
                wait_consoleTx();
                ocr_close();
                ocr.state = ST_NADA;
                return(ST_NADA);
            }
            ocr.state = ST_RX_START;
            return(ST_RX_START);        // return to same state

        case ST_RX_DATA:
            // receive the data string from the OCR, terminated by CR-LF
            if( ocr_rxBytesAvail() )
            {
                inChar = ocr_getc();
                //uprintf( "(%02x)", inChar );

                // check for terminating character
                if(inChar == 0x0a || inChar == 0x0d)
                {
                    // finished receiving data from OCR
                    ocr.buf[ocr.bufIndx] = 0x00;
                    ocr.old_tick10ms = Timer_10ms(false);
                    ocr.state = ST_OCR_CLOSE;
                    return(ST_OCR_CLOSE);
                }

                ocr.buf[ocr.bufIndx] = inChar;
                ocr.bufIndx++;

                if(ocr.bufIndx >= OCR_BUFFER_SIZE)
                {
                    ocr.bufIndx = OCR_BUFFER_SIZE-1;
                    if(sys_data.diag > 0) uprintf("\r\nDEBUG: error in ocr driver bufIndx exceeds buf size, ocr.c\r\n");
                    wait_consoleTx();
                    ocr_close();  // Close Optode, power off
                    ocr.state = ST_NADA;
                    return(ST_NADA);
                }

            }

            ocr.new_tick10ms = Timer_10ms(false);
            if((ocr.new_tick10ms - ocr.old_tick10ms) >= 200)  //200 is 2sec, was 500msec = 50*10msec
            {
                if(sys_data.diag > 0) uprintf("\r\nERROR: OCR did not finish transmitting data, timeout\r\n");
                sprintf((char *)&ocr.buf[0], "OCR did not finish transmit data");
                wait_consoleTx();
                ocr_close();  // Close Optode, power off
                ocr.state = ST_NADA;
                return(ST_NADA);
            }
            ocr.state = ST_RX_DATA;
            return(ST_RX_DATA);     // return to same state

        case ST_REPEAT:
            if(ocr.dataCnt > 0)
            {
                ocr.dataCnt--;
                if(ocr.dataCnt > 0)
                {
                    ocr.state = ST_REQ_DATA;
                    return(ST_REQ_DATA);
                }
            }

            ocr_close();  // Close Optode, power off
            ocr.state = ST_OCR_CLOSE;
            return(ST_OCR_CLOSE);

        case ST_OCR_CLOSE:
            ocr_close();  // Close Optode, power off
            ocr.state = ST_NADA;
            return(ST_NADA);

        default:
            uprintf("\r\nERROR: OCR statemachine error - should not get to default\r\n");
            ocr_close();
            ocr.state = ST_NADA;
            return(ST_NADA);



    }


}





void ocr_comm_test(void)
{
    unsigned char inChar;
    unsigned char drvChar;
    unsigned int indx;
    int debugFlg;
    int cnt;

    debugFlg = 0;


    // Tested with Seabird / Satlantic OCR-504

    //uprintf("                               \t5860\t29\t-0.003\t16.892\t0.009\t998.802\t1472.435\t\r\n");
    uprintf("\r\n\r\n*Press CTRL-X to stop communicating with the OCR-504 Instrument.\r\n\r\n");
    uprintf("\r\n Instructions for OCR-504 Configuration (silent wake, polled, short frame, calibration enabled:\r\n\r\n");
    uprintf("  Press CTRL-C to start Config mode, look for [Auto]$ prompt\r\n\r\n");

    uprintf("    [Auto]$ set -?                 [ List config params]\r\n\r\n");

    uprintf("    [Auto]$ set initsm on          [SILENT MODE ON - suppress power on header]\r\n\r\n");

    uprintf("    [Auto]$ set initat off         [AUTOTELEMETRY OFF - polled by <ENTER> or <SPACE.]\r\n\r\n");

    uprintf("    [Auto]$ set frametype short    [ASCII Data, tab delimited, terminated CR-LF]\r\n\r\n");

    uprintf("    [Auto]$ set usecal on          [ Utilize factory calibration]\r\n\r\n");

    uprintf("    [Auto]$ save                   [ Save config settings ]\r\n\r\n");

    uprintf("    [Auto]$ show all               [ Show all config settings]\r\n\r\n");

    uprintf("    [Auto]$ exit                   [ Exit to polled sampling mode, press <ENTER> to sample]\r\n\r\n");

    uprintf("\r\n\r\nWhen properly setup, press <ENTER> for output:  SATFI42247      0.1297  0.0154  -0.0071 0.0060\r\n\r\n");

#ifdef OCR_SETUP

    [Auto]$ show all [AS SHIPPED FROM FACTORY]

    Sensor Type: irradiance
    Serial Number: 2247
    Frame Type: binary
    Header: SATDI4
    Telemetry Baud Rate: 57600 bps
    Maximum Frame Rate: AUTO
    Initialize Silent Mode: off
    Initialize Power Down: off
    Initialize Automatic Telemetry: on
    Network Mode: off
    Network Address: 001
    Network Baud Rate: 19200 bps
    Averaging: off
    Immersed: on
    Calibrated Output: off
    Sensor Latency: 0
    Cal Coefficients:
     Optical Channel 1:
            a0:2146709830.0 [2146709830]
            a1:1.66144579217e-007 [1.66144e-07]
            im:1.161 [1.161]

     Optical Channel 2:
            a0:2147299079.0 [2147299079]
            a1:1.99579905307e-007 [1.99579e-07]
            im:1.410 [1.41]

     Optical Channel 3:
            a0:2147102221.6 [2147102221]
            a1:2.12413218205e-007 [2.12413e-07]
            im:1.365 [1.365]

     Optical Channel 4:
            a0:2147428518.5 [2147428518]
            a1:3.40295031944e-006 [3.40295e-06]
            im:1.359 [1.359]


     [Auto]$ set -?

    Usage: set [parameter] [value]

    set telbaud [telemetry baud rate (bps)]
    set maxrate [maximum frame rate (Hz)]
    set initsm [initialize silent mode (on|off)]
    set initpd [initialize power down (on|off)]
    set initat [initialize auto telemetry (on|off)]
    set netmode [network mode (on|off)]
    set netadd [network address (1-255)]
    set netbaud [network baud rate (bps)]
    set avg [on|off]
    set usecal [on|off]
    set immersed [on|off]
    set latency [value]
    set frametype [binary|short|long]
    set a0ch[1-4] [value]
    set a1ch[1-4] [value]
    set imch[1-4] [value]


    [Auto]$ set initsm on  [SILENT MODE ON - suppress power on header]

    [Auto]$ set initat off   [AUTOTELEMETRY OFF - polled by <ENTER> or <SPACE.]

    [Auto]$ set frametype short   [ASCII Data, tab delimited, terminated CR-LF]

    [Auto]$ set usecal on       [ Data uses factor calibration]

    [Auto]$ save

    Configuration parameters saved.



    [Auto]$ show all

    Sensor Type: irradiance
    Serial Number: 2247
    Frame Type: short
    Header: SATFI4
    Telemetry Baud Rate: 57600 bps
    Maximum Frame Rate: AUTO
    Initialize Silent Mode: on
    Initialize Power Down: off
    Initialize Automatic Telemetry: off
    Network Mode: off
    Network Address: 001
    Network Baud Rate: 19200 bps
    Averaging: off
    Immersed: on
    Calibrated Output: on
    Sensor Latency: 0
    Cal Coefficients:
     Optical Channel 1:
            a0:2146709830.0 [2146709830]
            a1:1.66144579217e-007 [1.66144e-07]
            im:1.161 [1.161]

     Optical Channel 2:
            a0:2147299079.0 [2147299079]
            a1:1.99579905307e-007 [1.99579e-07]
            im:1.410 [1.41]

     Optical Channel 3:
            a0:2147102221.6 [2147102221]
            a1:2.12413218205e-007 [2.12413e-07]
            im:1.365 [1.365]

     Optical Channel 4:
            a0:2147428518.5 [2147428518]
            a1:3.40295031944e-006 [3.40295e-06]
            im:1.359 [1.359]


    [Auto]$ sample
    Usage: sample [ADC channel ((1-4)|vreg|temp|all)]

    [Auto]$ sample all

    Power voltage regulated: 196
    Temperature sensor: 152

    Optical Channel 1: 2147255872
    Optical Channel 2: 2147361600
    Optical Channel 3: 2147094144
    Optical Channel 4: 2147425216


#endif


    //set up the ocr
    ocr_init();
    ocr_open();               // power on ocr
    ROM_SysCtlDelay(100);       //100 is a guess


    UARTEchoSet(false);
    while(1)
    {
        if( ocr_rxBytesAvail() )      // ocr
        {
            uprintf( "%c", ocr_getc() );
        }


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

            if((inChar == 24) || (inChar == 25) || (inChar == 26)  )  // Ctrl-X or Ctrl-Y or Ctrl-Z
            {
                UARTEchoSet(true);
                break;
            }
            else
            {
                ocr_putc(inChar);       // else send to OCR
            }
        }  // if(UARTRxBytesAvail())


    } // while(1)



    ocr_close();  // Close up the ocr


}


