#ifdef MERGELATER
/*
 * ph_sender.c
 * Library for front-end sender of pH data, e.g. front-end mFET collecting data to be sent to back end mpHox
 *
 *  Created on: Nov 19, 2021
 *      Author: Irene Hu
 */

#include "ph_front.h"

#define PRINTOUT // for printing things out to main comms

extern unsigned long Timer_1ms(bool reset);

//******************************************************************************
//* Initialize and UART wrapper
//* references to uart are in this section only
//******************************************************************************

void phf_init(void)
// similar to other devices, init function now only sets up the uart port
{
    uart3_init();

    uart3_setup(PH_BAUD, 16000000);

    uart3_echo_set(0);
}

int phf_open(void)
// setup function
// figure out later if need this
// return 0 if success, 1 if fail
{
    return 1;
}

unsigned char _phf_getc(void)
{
    return(uart3_rx_byte());
}

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

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

void _phf_flushRx(void)
{
    uart3_rx_bufr_flush();
}

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


//******************************************************************************
//* Public Methods
//******************************************************************************



int phf_measOnce(void)
// measures once and sends back data
// meant to be called upon receipt of MO cmd by some other function
// ack is sent by the calling function
// returns 0 if success, 1 if not
{
    struct pH_ptdata pHDatStruct;
    pHDatStruct.sync = PH_SYNCBYTE;
    pHDatStruct.id = PH_IDPTD;
    pHDatStruct.count = 0;

#if defined(PRINTOUT) && defined(PRINT_PH_TIMING)
    time_t currentTime = ROM_HibernateRTCGet();
#endif

    // measure stuff copied from sample.c, also using modified ads1248_iso.c
#if BOARD_MFET >= 1 || BOARD_MPHOX >= 1  || BOARD_MSC == 2 // if using a nanofet, this entire thing just doesn't work, i guess
    dbg_printf("About to open ADC\n");
    openADS1248_iso();              // turn on isolated power to 24bit A/D converter
    ROM_SysCtlDelay(500*MILLISECOND);         // new, 3 Aug 2021 - BUG fix (Crash) - IH I am still getting this crash!!  bumped to 500 ms
    dbg_printf("About to init ADC GPIO\n");
    ADS1248_gpio_init();            // defd in ADS1248_iso.c  (CRASH HAPPENS HERE - first call to fast_sampling is good, next call crashes

    // no battery or env monitoring

    ADS1248_gpio_ADG1609_mux(3); // for Vrsi
    ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog

    dbg_printf("Ready to start measuring\n");

    // since this is a testing function, call it the way I do in continuous measurement
    startmeas_ADS1248_iso(1, 6, 1, PH_ADCFREQ_VRS); // Vrsi, 20 Hz
    while(iso_DRDY());
    pHDatStruct.Vrs = readonce_ADS1248_iso();
    pHDatStruct.Vtherm = pollADS1248_iso_once(0, 6, 1, PH_ADCFREQ_VTHERM);

#ifdef PRINTOUT
    ph_printpHDataHdr(NULL, 1);
    uprintf("\n");

#ifdef PRINT_PH_TIMING
    uprintf("0\t", difftime(ROM_HibernateRTCGet(), currentTime));
    // difftime for subtracting time_t
    // https://stackoverflow.com/questions/45614595/how-to-subtract-two-time-t-values-difftime-returns-double-instead-time-t
#endif

    ph_printpHData(&pHDatStruct, NULL, 1);
    uprintf("\n");
#endif

    //dbg_printf("Read in %" PRId32 " for Vrsi and %" PRId32 " for VTherm\n", pHDatStruct.Vrs, pHDatStruct.Vtherm);
    //dbg_printf("Read in %.6f for Vrsi and %.6f for VTherm\n", pHDatStruct.Vrs * COUNTSTOVOLTS, pHDatStruct.Vtherm * COUNTSTOVOLTS);


    closeADS1248_iso();

    pHDatStruct.checksum = ph_calcChecksum(&pHDatStruct);
    _phf_sendpHThermData(&pHDatStruct);
#endif

    return 0;

}


int phf_measCont(void)
// measure continuously - in a polled mode, sends back last measured data upon receipt of GM
// meant to be called upon receipt and parsing of MC cmd by some other function
// ack is sent by the calling function
// stops when receives stops command and sends ack, shuts down ADC and exits function
// returns 0 if success, 1 if not
{

    struct pH_ptdata pHDatStruct;
    pHDatStruct.sync = PH_SYNCBYTE;
    pHDatStruct.id = PH_IDPTD;
    pHDatStruct.count = -1; // so it gets incremented to 0 after first read
    // all data, incluidng this count, will have issues if phb asks for a measurement before first read is done

    char rcvd[3];
    rcvd[2] = '\0'; // make it a null terminated string, to compare to the string literal #defined in ph_base

    int stopFlg = 0;

#if defined(PRINTOUT) && defined(PRINT_PH_TIMING)
    Timer_1ms(TRUE); // reset timer
#endif

    // measure stuff copied from sample.c, also using modified ads1248_iso.c
#if BOARD_MFET >= 1 || BOARD_MPHOX >= 1  || BOARD_MSC == 2 // if using a nanofet, this entire thing just doesn't work, i guess
    openADS1248_iso();              // turn on isolated power to 24bit A/D converter
    ROM_SysCtlDelay(100*MILLISECOND);         // new, 3 Aug 2021 - BUG fix (Crash)
    ADS1248_gpio_init();            // defd in ADS1248_iso.c  (CRASH HAPPENS HERE - first call to fast_sampling is good, next call crashes

    ADS1248_gpio_ADG1609_mux(3); // for Vrsi
    ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog

    startmeas_ADS1248_iso(1, 6, 1, PH_ADCFREQ_VRS); // Vrsi, 20 Hz

#ifdef PRINTOUT
    ph_printpHDataHdr(NULL, 1);
    uprintf("\n");
#endif

    while(!stopFlg) {

        // DRDY pin goes low when a conversion is ready, and is sent high by reading conversion (clocking SCK) or resetting (eg if initiate new meas)
        while(iso_DRDY()) { // defined in ads1248_iso.c - means we're still waiting for conversion
            // wait for poll and send info upon receipt
            if (phf_rxBytesAvail() >= 2) { // \0 doesn't get transmitted, it's just 2 chars
                // check for >= 2 (not just 2) to combine the unknown cmd code
                 // 1 character on the port will just sit there; if there's a timing mismatch, it'll get flushed when another 2 chars come

                rcvd[0] = _phf_getc();
                rcvd[1] = _phf_getc();

                if (strcmp(rcvd, PH_STOPMEAS) == 0) {
                    _phf_sendAck();
                    stopFlg = 1;
                    dbg_printf("Received %s\n",PH_STOPMEAS);
                } else if (strcmp(rcvd, PH_GETMEAS) == 0) {
                    // no printout here, it would be too many and take too much time
                    _phf_sendpHThermData(&pHDatStruct);
                    // well ok, we can put a printout for now
                    //dbg_printf("Received %s\n",PH_GETMEAS);
                    _phf_flushRx(); // in case it missed one and now has 2 piled up
                } else {
                    dbg_printf("Unknown cmd: %#x %#x\n", rcvd[0], rcvd[1]);
                    while (phf_rxBytesAvail() > 0) { // in case there are more
                        dbg_printf("%#x ", _phf_getc()); // this flushes buffer
                    }
                    dbg_printf("\n");
                    _phf_sendNack();
                }

            }
        }

        // a Vrsi reading is now ready- will store and overwrite previous, regardless of if it was queried by and sent off to phb
        // similar to ADCs that just keep on going whether or not you read the number
        // ADC readings may get "skipped" once in a while depending on how much slower than 20 Hz phb is asking for them
        // no averaging or combining of measurements if phb is slow - something for later, maybe
        pHDatStruct.Vrs = readonce_ADS1248_iso();
        // quick 100 Hz measurement of Vtherm, corresponding to the 20 Hz Vrs measurement just read in
        pHDatStruct.Vtherm = pollADS1248_iso_once(0, 6, 1, PH_ADCFREQ_VTHERM);
        startmeas_ADS1248_iso(1, 6, 1, PH_ADCFREQ_VRS); // set it going for Vrs again

        (pHDatStruct.count)++;
        // count represents how many ADC meas it's taken, if phb doesn't ask for data fast enough, may see phb skip a count
        // want to know if/when this happens, so tie to a new ADC measurement
        // no other place to put this, send loop is in front but should get "skipped" the first time; so started count at -1

        pHDatStruct.checksum = ph_calcChecksum(&pHDatStruct);

        // printout for each ADC read
        // ok to put here again - it DOES still spend enough time converting that it can wait for instructions
#ifdef PRINTOUT
#ifdef PRINT_PH_TIMING
        uprintf("%.4f\t",(double)Timer_1ms(FALSE)/1000);
#endif
        ph_printpHData(&pHDatStruct, NULL, 1);
        uprintf("\n");
#endif

    }

    // stopflag is up

    closeADS1248_iso();
    dbg_printf("Exiting continuous measurement function\n");

    return 0;


#endif
}


void phf_sortInstructions(void)
// listening function to receive and sort inputs
// meant to be called by main()
{
    time_t currentTime;
    struct tm *time_struct;
    char buff[256];

    char rcvd[3];
    rcvd[2] = '\0'; // make it a null terminated string, to compare to the string literal #defined in ph_base

    while(1) {

        if (phf_rxBytesAvail() >= 2) { // \0 doesn't get transmitted, it's just 2 chars
            // check for >= 2 (not just 2) to combine the unknown cmd code
            // 1 character on the port will just sit there; if there's a timing mismatch, it'll get flushed when another 2 chars come

            rcvd[0] = _phf_getc();
            rcvd[1] = _phf_getc();

            currentTime = ROM_HibernateRTCGet();
            time_struct = localtime(&currentTime);
            strftime(buff, sizeof(buff),TIMESTAMP_FMT, time_struct);

            dbg_printf("\n[%s] ", buff);

            if (strcmp(rcvd, PH_MEASONCE) == 0) {
                _phf_sendAck();
                dbg_printf("Received %s from back-end controller\n", PH_MEASONCE);
                phf_measOnce();
            } else if (strcmp(rcvd, PH_MEASCONT) == 0) {
                _phf_sendAck();
                dbg_printf("Received %s from back-end controller\n", PH_MEASCONT);
                phf_measCont();
            } else {
                dbg_printf("Unknown cmd: %#x %#x\n", rcvd[0], rcvd[1]);
                while (phf_rxBytesAvail() > 0) { // in case there are more
                    dbg_printf("%#x ", _phf_getc()); // this flushes buffer
                }
                dbg_printf("\n");
                _phf_sendNack();
            }

            //dbg_printf("Returning to while(1) loop; %d chars in buffer.\n",phf_rxBytesAvail());

        }

        // poll for exit sequence to change mode
        // this is not very robust to wrong characters or leaving chars in buffer
        // just keep entering ctrl-x's until it works; if it takes fewer than 3, that's ok
        // not worth implementing a timer thing (ctrl x's need to show up within n seconds)
        if(UARTRxBytesAvail() >= 3)
        {
            if(UARTgetc() == CTRL_X && UARTgetc() == CTRL_X && UARTgetc() == CTRL_X)
            {
                dbg_printf("3 x ctrl-x received from main UART; switching mode.\n");
                edit_main_behavior();
                // this will put it to sleep and re-wake it to call main() again, if mode was changed
                // or else return it directly here to continue
            }
            UARTFlushRx(); // for any extra bytes in buffer
        }
    }
}


//******************************************************************************
//* Private Methods
//******************************************************************************


void _phf_sendAck()
// send an Ack Ack
{
    _phf_putc(PH_ACK);
    _phf_putc(PH_ACK);
    return;
}

void _phf_sendNack()
// send an Ack Ack
{
    _phf_putc(PH_NACK);
    _phf_putc(PH_NACK);
    return;
}

void _phf_sendpHThermData(struct pH_ptdata *pHDatStruct)
// send pH+thermistor data
// returns 0 if success, 1 if fail
{
    //uprintf("Check memory alignment: pH_data struct has a size of %d bytes\n", sizeof(struct pH_ptdata));
    // 16 bytes before packing
    //_phf_write((const char *)pHDatStruct, sizeof(struct pH_ptdata));
    // cannot use write cmd because it turns LF into CRLF, was inserting 0xd in front of 0xa
    char *iterator = (char *)pHDatStruct;
    int i;
    for (i = 0; i < 14; i++) {
        _phf_putc(iterator[i]);
    }

}

#endif
