/*
 * apf_util.c
 *
 *  Created on: May 10, 2024
 *      Author: tm
 */


#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <sys/types.h>
//#include "stat.h"       // for struct stat down below

#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 "apf.h"
#include "test.h"

#include "apf.h"
#include "apf_util.h"

extern int    Zcoefs, Ecoefs, Zeros;
/* Application Build Info */
char bfile[20] = __FILE__;
char bdate[20] = __DATE__;
char btime[20] = __TIME__;


struct tm DS3234_tm;    // DS3234 time of day as struct tm
struct tm *tp;          // scratchpad struct tm

struct apfGlobals apf;
struct apfRtcTime rtc;

char  logfname[64];
FILE  *dat_file;
FILE  *err_file;

long   size, avail;
ldiv_t hdiv, mdiv;

float  DataMean, DataStdDev;
float  sysTemperature, sysHumidity;
float  sysVoltage, sysCurrent;


extern double ZeissCoefs[ZCOEFS];
extern double LambdaData[260];





unsigned int check_storage_remaining(void)
{
    // APF TODO - actually check size
    uprintf("todo check_storage_remaining() apf_util.c");
    return(1000000000L);
}


//*****************************************************************************
// File Routines
//*****************************************************************************


FILE *OpenApfLogFile( unsigned int select )     // was uint8_t select
{
    char ebuf[ERRBUFSIZE];
    FILE   *fptr;
    unsigned int avail;

//fpos_t fsize;

    CheckFileSize( ERRORLOG_FILE );

    memset(logfname, '\0', sizeof(logfname));

    avail = check_storage_remaining();

    if( avail < 5000L )
    {
        if( apf.sys_last_error != (int)FLASH_CARD_FULL )
        {
            sprintf(ebuf, "FLASH Card is Full with %ld Bytes Remaining", avail);
            LogErrorMsg(ebuf, (int)FLASH_CARD_FULL, apf.sys_message_enable);
        }

        return( FNULL );
    }

    if( select == ISUS_DATA_FILE ) {
        if( apf.sys_por_ctr < 9999 )
            sprintf(logfname,"C:\\ISUS\\PROF%04lu.log", apf.sys_por_ctr);
        else
            sprintf(logfname,"C:\\ISUS\\PROF9999.log", apf.sys_por_ctr);
    }
    else if( select == DURA_DATA_FILE ) {
        if( apf.sys_por_ctr < 9999 )
            sprintf(logfname,"C:\\DURA\\PROF%04lu.log", apf.sys_por_ctr);
        else
            sprintf(logfname,"C:\\DURA\\PROF9999.log", apf.sys_por_ctr);
    }


    fptr = fopen(logfname, "a+");
    if(fptr != FNULL)
    {
        return(fptr);
    }
    else
    {
        sprintf(ebuf, "File Open Failure on file: %s", logfname);
        LogErrorMsg(ebuf, (int)FILE_OPEN_FAILURE, apf.sys_message_enable);
        return( FNULL );
    }


#ifdef OLDCODE
    //check if ERROR.LOG has grown too big...
    CheckFileSize( ERRORLOG_FILE );

    memset(logfname, '\0', sizeof(logfname));

    //check if FLASH card is going to run out of space soon
    pdcfinfo("C:", &size, &avail);
    if( avail < 5000L ) {
        if( sys_last_error != (int)FLASH_CARD_FULL ) {
            sprintf(ebuf, "FLASH Card is Full with %ld Bytes Remaining", avail);
            LogErrorMsg(ebuf, (int)FLASH_CARD_FULL,sys_message_enable);
        }
        return( FNULL );
    }

    if( select == ISUS_DATA_FILE ) {
        if( sys_por_ctr < 9999 )
            sprintf(logfname,"C:\\ISUS\\PROF%04lu.log", sys_por_ctr);
        else
            sprintf(logfname,"C:\\ISUS\\PROF9999.log", sys_por_ctr);
    }
    else if( select == DURA_DATA_FILE ) {
        if( sys_por_ctr < 9999 )
            sprintf(logfname,"C:\\DURA\\PROF%04lu.log", sys_por_ctr);
        else
            sprintf(logfname,"C:\\DURA\\PROF9999.log", sys_por_ctr);
    }

    fptr = fopen(logfname, "a+");
    if(fptr != FNULL)
        return(fptr);
    else{
        sprintf(ebuf, "File Open Failure on file: %s", logfname);
        LogErrorMsg(ebuf, (int)FILE_OPEN_FAILURE, sys_message_enable);
        return( FNULL );
    }
#endif
}



int LogErrorMsg(char *emsg, int ecode, uint8_t outp)
{

    uprintf("replace DS3234 fxn in LogErrorMsg apf_util.c");        //APFTODO
#ifdef APFTODO
    if( (ecode <= -100) && (ecode >= -199) ) {
        apf.sys_error_time = RTCGetTime( NULL, NULL );
        tp = localtime(&apf.sys_error_time);
        //DS3234_WrSRAM(SYS_LASTERRTIME_PTR, sizeof(unsigned long), (unsigned long*)&apf.sys_error_time);

        ++apf.sys_error_ctr;
        //DS3234_WrSRAM(SYS_ERRORCTR_PTR, sizeof(unsigned long), (unsigned long*)&sys_error_ctr);

        apf.sys_last_error=ecode;
        //DS3234_WrSRAM(SYS_LASTERROR_PTR, sizeof(int), (int*)&sys_last_error);
    }
    else if( (ecode <= -200) && (ecode >= -299) ) {
        apf.isus_error_time = RTCGetTime( NULL, NULL );
        tp = localtime(&apf.isus_error_time);
        //DS3234_WrSRAM(ISUS_LASTERRTIME_PTR, sizeof(unsigned long), (unsigned long*)&apf.isus_error_time);

        ++apf.isus_error_ctr;
        //DS3234_WrSRAM(ISUS_ERRORCTR_PTR, sizeof(unsigned long), (unsigned long*)&apf.isus_error_ctr);

        apf.isus_last_error=ecode;
        //DS3234_WrSRAM(ISUS_LASTERROR_PTR, sizeof(int), (int*)&apf.isus_last_error);
    }
    else if( (ecode <= -300) && (ecode >= -399) ) {
        apf.dura_error_time = RTCGetTime( NULL, NULL );
        tp = localtime(&apf.dura_error_time);
        //DS3234_WrSRAM(DURA_LASTERRTIME_PTR, sizeof(unsigned long), (unsigned long*)&apf.dura_error_time);

        ++apf.dura_error_ctr;
        //DS3234_WrSRAM(DURA_ERRORCTR_PTR, sizeof(unsigned long), (unsigned long*)&apf.dura_error_ctr);

        apf.dura_last_error=ecode;
        //DS3234_WrSRAM(DURA_LASTERROR_PTR, sizeof(int), (int*)&apf.dura_last_error);
    }
    else {
        rtc.current_time = RTCGetTime( NULL, NULL );
        tp = localtime(&rtc.current_time);
    }


    if( (err_file = fopen("C:\\ERROR.LOG", "a+")) == FNULL ) {
        apf.sys_error_time = RTCGetTime( NULL, NULL );
        tp = localtime(&apf.sys_error_time);
        //DS3234_WrSRAM(SYS_LASTERRTIME_PTR, sizeof(unsigned long), (unsigned long*)&apf.sys_error_time);

        ++apf.sys_error_ctr;
        //DS3234_WrSRAM(SYS_ERRORCTR_PTR, sizeof(unsigned long), (unsigned long*)&apf.sys_error_ctr);

        apf.sys_last_error = (int)FILE_OPEN_FAILURE;
        //DS3234_WrSRAM(SYS_LASTERROR_PTR, sizeof(int), (int*)&apf.sys_last_error);
        return( ERROR );
    }

    fprintf(err_file, "E, %02d/%02d/%02d %02d:%02d:%02d, %d, %s\n", tp->tm_mon+1, tp->tm_mday, tp->tm_year+1900, tp->tm_hour, tp->tm_min, tp->tm_sec, ecode, emsg);

    fclose(err_file);

    if( outp == TRUE )
        printf("%02d/%02d/%02d %02d:%02d:%02d, %d, %s\n", tp->tm_mon+1, tp->tm_mday, tp->tm_year+1900, tp->tm_hour, tp->tm_min, tp->tm_sec, ecode, emsg);
#endif
    return( OK );

}

long CalcRecsPending(unsigned int select)       // uint8_t select
{
    char   *sbuf;
    char   *FileName[] = {"C:\\OFFLOAD.DAT", "C:\\ERROR.LOG"};
    FILE   *fptr;
    long ctr;


    if( ( select < 0 ) || ( select > 1 ) )
        return( ERROR );

    if( (fptr = fopen(FileName[select], "r")) == FNULL)
        return( OK );

    if( (sbuf = calloc((size_t)DATBUFSIZE, sizeof(char))) == NULL ) {
        fclose(fptr);
        return( ERROR );
    }

    ctr = 0L;
    while( (fgets(sbuf, (size_t)DATBUFSIZE, fptr) != NULL) && (!feof(fptr)) ) {
        ++ctr;
    }

    free(sbuf);
    fclose(fptr);

    return( ctr );

}

int SendRecords(unsigned int select, fpos_t *fpsrc)     // uint8_t select
{
    char   *sbuf;
    char   *FileName[] = {"C:\\OFFLOAD.DAT", "C:\\ERROR.LOG"};
    FILE   *fptr;
    fpos_t fptmp;


    if( ( select < 0 ) || ( select > 1 ) )
        return( ERROR );

    if( (fptr = fopen(FileName[select], "r")) == FNULL)
        return( ERROR );

    //set file pos to passed value
    if( *fpsrc != 0 ) {
        if( fsetpos(fptr, fpsrc) != OK ) {
            fclose(fptr);
            return( ERROR );
        }
    }

    if( (sbuf = calloc((size_t)DATBUFSIZE, sizeof(char))) == NULL ) {
        fclose(fptr);
        return( ERROR );
    }

    if( fgets(sbuf, (size_t)DATBUFSIZE, fptr) != NULL ) {
        SerPuts(sbuf);
        fflush(stdout);
    }

    free(sbuf);

    //read current file pos
    fgetpos(fptr, fpsrc);

    //read EOF file pos
    fseek(fptr, 0L, SEEK_END);
    fptmp=ftell(fptr);

    fclose(fptr);

    //does the current file pos and EOF match?
    if( *fpsrc == fptmp ) {
        remove( FileName[select] );
        SerPuts("EOF\n");
        fflush(stdout);
        return( TRUE );
    }

    return( OK );

}

int CheckFileSize(unsigned int select)
{
    char   *ebuf;
    char   *FileName[] = {"C:\\OFFLOAD.DAT", "C:\\ERROR.LOG"};
    FILE   *fptr;
    fpos_t fsize;


    if( ( select < 0 ) || ( select > 1 ) )
        return( ERROR );

    if( (fptr = fopen(FileName[select], "r")) == FNULL)
        return( OK );

    //read EOF file pos
    if( fseek(fptr, 0L, SEEK_END) != OK ) {
        fclose(fptr);
        return( ERROR );
    }

    fsize=ftell(fptr);

    fclose(fptr);

    if( select == 0 ) {
        if( fsize > (fpos_t)apf.sys_sf_limit*1000L ) {
            remove("C:\\OFFLOAD.DAT");
            if( (ebuf = calloc((size_t)ERRBUFSIZE, sizeof(char))) == NULL )
                return( ERROR );
            sprintf(ebuf, "OFFLOAD.DAT Too Big %ld Bytes - File Removed", fsize);
            LogErrorMsg(ebuf, (int)OFFLOAD_FILE_TOO_BIG,apf.sys_message_enable);
            free(ebuf);
            return( TRUE );
        }
        else
            return( OK );
    }

    else if( select == 1 ) {
        if( fsize > (fpos_t)apf.sys_ef_limit*1000L ) {
            remove("C:\\ERROR.LOG");
            if( (ebuf = calloc((size_t)ERRBUFSIZE, sizeof(char))) == NULL )
                return( ERROR );
            sprintf(ebuf, "ERROR.LOG Too Big %ld Bytes - File Removed", fsize);
            LogErrorMsg(ebuf, (int)ERROR_FILE_TOO_BIG, apf.sys_message_enable);
            free(ebuf);
            return( TRUE );
        }
        else
            return( OK );
    }

    else{
        return( ERROR );
    }

}

//int LoadIsusECoefs(double *Lambda, double **Ecoefs, double *Zeros, double *Tcoefs, double *CalTemp, char *CalDate)
int LoadIsusECoefs(double *Lambda, double **Ecoefs, double *Zeros, double *Tcoefs, double *CalTemp, char *CalDate)
{
    FILE *coef_file;
    char *srchptr, *dataptr;
    char data[512];
    int i, j, ret;
    int got_date, month, day, year;
    int got_temp;
    double sw_calib_temp;

    //hard code Tcoefs for now...
    for(i = 0; i < TCOEFS; i++) {
        if(i == 0)
            Tcoefs[i] = 1.1500276;
        else if(i == 1)
            Tcoefs[i] = 0.0284;
        else if(i == 2)
            Tcoefs[i] = -0.3101349;
        else if(i == 3)
            Tcoefs[i] = 0.001222;
        else
            Tcoefs[i] = 0.0;
    }

    /* open Extinction Coefficients and Zero Scan file */
    coef_file = fopen("C:\\ISUS\\ECOEFZER.CAL", "r");
    if(coef_file == FNULL)
        return( -1 );

    got_date = got_temp = FALSE;

    // starting at 0 we end at 256, the count we want...
    for(i = 0; i < 256; ) {
        if(fgets(data, sizeof(data), coef_file) == NULL) {
            printf("\n  NULL ret in Ext. Coef / Zero Data!\n");
            return( -2 );
        }
        else{
            if(got_date == FALSE) {
                srchptr = memchr(data, 'H', 1);
                if(srchptr != NULL) {
                    srchptr=srchptr+2;
                    ret = sscanf(srchptr,"%d/%d/%d,,,,\n",&month, &day, &year);
                    if(ret == 3) {
                        got_date = TRUE;
                        sprintf(CalDate,"%02d/%02d/%02d", month, day, year);
                        continue;
                    }
                }
            }
            if(got_temp == FALSE) {
                srchptr = memchr(data, 'H', 1);
                if(srchptr != NULL) {
                    srchptr=srchptr+2;
                    ret = sscanf(srchptr,"CalTemp,%lf,,,\n",&sw_calib_temp);
                    if(ret == 1) {
                        got_temp = TRUE;
                        *CalTemp = sw_calib_temp;
                        continue;
                    }
                }
            }
            srchptr = memchr(data, 'E', 1);
            if(srchptr != NULL) {
                ++i;
                j=0;
                dataptr = strtok(srchptr, ",");
                while ((dataptr = strtok(NULL, ",")) != NULL) {

                    switch( j ){

                        case 0:
                            if(Lambda != NULL)                                  //skip value, if Lambda array has not already been initialized via ZCoef values
                                Lambda[i] = strtod(dataptr, NULL);
                            break;

                        case 1:
                            Ecoefs[i][0] = strtod(dataptr, NULL);
                            break;

                        case 2:
                            Ecoefs[i][1] = strtod(dataptr, NULL);
                            break;

                        case 3:
                            Ecoefs[i][2] = strtod(dataptr, NULL);
                            break;

                        case 4:
                            Zeros[i] = strtod(dataptr, NULL);
                            break;

                        default:
                            break;

                    }
                    ++j;
                }

                if(j != 5) {
                    printf("\n  Bad data at %d in ECoef File!\n", i);
                    printf("%s\n", srchptr);
                    fclose(coef_file);
                    return( -3 );
                }
            }
        }
    } //end for loop

    if(got_date == FALSE)
        sprintf(CalDate, "NODATEFOUND");

    if(got_temp == FALSE)
        *CalTemp = 20.0;

    fclose(coef_file);
    return(i);

}

int LoadIsusZCoefs(double *ZeissCoefs)
{
    FILE   *coef_file;
    char   *coef_ptr;
    char buff[150];
    int i;

    /* open Zeiss Coefficients file */
    coef_file = fopen("C:\\ISUS\\ZCOEFDAT.CAL", "r");
    if(coef_file == FNULL) {
        //printf("\n  Can't open ZCOEFDAT.CAL!\n");
        return( -1 );
    }
    else{
        i=0;
        do {
            fgets(buff, sizeof(buff), coef_file);
            if( (strchr(buff,'/')) || (strchr(buff,'*')) )
                continue;
            coef_ptr = strstr(buff,"C");
            if(coef_ptr != NULL) {
                coef_ptr += 3;
                if( (strtod(coef_ptr, NULL) != 0.0) && (i < 5) ) {
                    ZeissCoefs[i] = strtod(coef_ptr, NULL);
                    i++;
                }
            }
        } while( !feof(coef_file) );
        if(i == 3) {
            ZeissCoefs[3]=0.0; //clear possible residual from an "new" spec with 3 coefs
            ZeissCoefs[4]=0.0; //clear possible residual from an "new" spec with 3 coefs
        }
        if(i == 4)
            ZeissCoefs[4]=0.0;  //clear possible residual from an "old" spec with 5 coefs
    } // end else

    fclose(coef_file);
    return(i);      //should return 5 (MMS-UV) or 4 (MMS-UV-II) or 3-4 (MMS-UV-II NEW MODELS)

}

int LoadDuraFetIIITCoefs(double *Coefs)
{
    FILE   *coef_file;
    char   *coef_ptr;
    char buff[150];
    int i;

    // open Steinhart-Hart coefficients
    coef_file = fopen("C:\\DURA\\SHHCOEFS.CAL", "r");
    if(coef_file == FNULL) {
        printf("\n  Can't open SHHCOEFS.CAL!\n");
        return( -1 );
    }
    else{
        i=0;
        do {
            fgets(buff, sizeof(buff), coef_file);
            if( (strchr(buff,'/')) || (strchr(buff,'*')) )
                continue;
            coef_ptr = strstr(buff,"A");
            if(coef_ptr != NULL) {
                coef_ptr += 3;
                if( (strtod(coef_ptr, NULL) != 0.0) && (i < 4) ) {
                    Coefs[i] = strtod(coef_ptr, NULL);
                    i++;
                }
            }
        } while( !feof(coef_file) );
    } // end else

    fclose(coef_file);

    return(i);      //should return 4

}




#define ABORT           0x03
#define BKSP            0x08
#define REDISP          0x12
#define RESTRT          0x15


/*******************************************************************************
**      QueryDateTime           Query user for the Date and Time
**
**      Return TRUE for all replies except ctrl-C.  Print prompt string (verbatim)
**      followed by the default reply (either the current system calander time if
**      defTime is TRUE or the calander time contained in the tm structure.
**      Returns result in struct tm, but does not set the system clock.
**
**      NOTES:
**              1.      carriage return is not echoed.
**              2.      ctrl-C always return FALSE
**              3.      input format is compatable with CrossCut's Paste Time & Date (cmd-D)
**
**      Typical Usage:
**              struct tm       t;
**              if (! QueryDateTime("\nCurrent Date and Time", TRUE, &t))
**                      ... error processing for ctrl-C ...
**              SetTimeTM(&t, NULL);    \* set the system time *\
*******************************************************************************/
short QueryDateTime(char *prompt, short defTime, struct tm *tm)
        {
        char            buf[40];
        char            def[40];
        time_t          secs;

        while (1)
                {
                printf(prompt);
                if (defTime)
                        secs = time(NULL);
                else
                        secs = mktime(tm);

                strftime(def, sizeof(def), "%m/%d/%Y %H:%M:%S", localtime(&secs));

                printf(" [%s] ? ", def);

                if (! InputLine(buf, (short) sizeof(buf)))
                        return (FALSE);

                if (! *buf)                     /* just return keyed */
                        strcpy(buf, def);       /* copy default and fall through */

                /* *c is NULL ptr for the "/" and ":" seperators */
                if (sscanf(buf, "%d%*c%d%*c%d%*c%d%*c%d%*c%d",
                        &tm->tm_mon, &tm->tm_mday, &tm->tm_year,
                        &tm->tm_hour, &tm->tm_min, &tm->tm_sec))
                        {
                        tm->tm_mon--;           /* adjust to month 0 - 11 */
                        if(tm->tm_year >= 2000)
                           tm->tm_year = (tm->tm_year - 2000) + 100;
                        else
                           tm->tm_year = (tm->tm_year - 1900);
                        return (TRUE);
                        }

                if (*prompt != '\n')
                        putchar('\n');  /* reprompt and try again */
                }

                return (TRUE);

        }       /* QueryDateTime() */


/*******************************************************************************
**      QueryYesNo              Query user for a yes or no reply.
**
**      Return TRUE only for a Yes reply (which may be return only default if defYes
**      is TRUE).  Print prompt string (verbatim) followed by (Yes/No) followed by
**      default reply character inside square brackets, followed by a question mark.
**
**      NOTES:
**              1.      carriage return is not echoed.
**              2.      ctrl-C always return FALSE
*******************************************************************************/
//short QueryYesNo(ptr prompt, short defYes)
short QueryYesNo(char *prompt, short defYes)
        {
        char    reply;
        char    buf[100];

        strncpy(buf, prompt, sizeof(buf) - 10);
        strcat(buf, " (Yes/No)");
        if (! QueryChar(buf, defYes ? 'Y' : 'N', "YN", &reply))
                return (FALSE);
        return ((short) (reply == 'Y'));

        }       /* QueryYesNo() */


/*******************************************************************************
**      QueryChar               Query user for a character reply.
**
**      Return TRUE for all replies except ctrl-C.  Print prompt string (verbatim)
**      followed by optional default character inside square brackets, followed by
**      a question mark.  Return default character if just return pressed, otherwise
**      scan reply accepting only characters from scanSet.
**
**      NOTES:
**              1.      carriage return is not echoed.
**              2.      If the scanSet contains no lower case characters, the input will be
**                      converted to upper case.
**              3.      Same as 2 but opposite case sense.
**
*******************************************************************************/
//short QueryChar(ptr prompt, short defChar, ptr scanSet, char *reply)
short QueryChar(char *prompt, short defChar, char *scanSet, char *reply)
{
    char    c, buf[2];
    short   forceUpper = FALSE, forceLower = FALSE;
    char *pss;
    pss = scanSet;      //ptr             pss = scanSet;

    if (scanSet)
        {
        forceUpper = forceLower = TRUE;
        while (c = *pss++)
        if (isupper(c))
            forceLower = FALSE;
        else if (islower(c))
            forceUpper = FALSE;
        }

    while (1)
        {
        printf(prompt);
        if (defChar)
            printf(" [%c]", *reply = defChar);
//              printf(" ? ");

        if (! InputLine(buf, (short) sizeof(buf)))
            return (FALSE);

        if ((! *buf) && defChar)
            return (TRUE);

        if (forceUpper)
            *reply = toupper(*buf);
        else if (forceLower)
            *reply = tolower(*buf);
        else
            *reply = *buf;

        if (scanSet)
            if (strchr(scanSet, *reply))
                return (TRUE);

        if (*prompt != '\n')
            putchar('\n');  /* reprompt and try again */
        }

}       /* QueryChar() */



/*******************************************************************************
**      QueryNum                Query user for a numeric value.
**
**      Return TRUE for all replies except ctrl-C.  Print prompt string (verbatim)
**      followed by optional default value (if defFmt in non-NULL and not a NULL
**      string) inside square brackets, followed by a question mark.  Return default
**      value if just return pressed, otherwise scan reply using scanFmt string.
**
**      NOTES:
**              1. defFmt and scanFmt are scanf specifiers (e.g. "%ld", "lu", "%lx")
**              2. carriage return is not echoed.
*******************************************************************************/
int QueryNum(char *prompt, char *defFmt, char *scanFmt, unsigned long *value)     // ptr prompt
        {
        char    buf[20];

        while (1)
                {
                printf(prompt);
                if (defFmt)
                        if (*defFmt)
                                {
                                printf(" [");
                                printf(defFmt, *value);
                                printf("]");
                                }
                printf(" ? ");

                if (! InputLine(buf, (short) sizeof(buf)))
                        return (FALSE);

                if (! *buf)                     /* just return keyed */
                        return (TRUE);

                if (sscanf(buf, scanFmt, value))
                        return (TRUE);

                if (*prompt != '\n')
                        putchar('\n');  /* reprompt and try again */
                }

        }       /* QueryNum() */


/*******************************************************************************
**      QueryFloat              Query user for a float value.
**
**      Return TRUE for all replies except ctrl-C.  Print prompt string (verbatim)
**      followed by optional default value (if defFmt in non-NULL and not a NULL
**      string) inside square brackets, followed by a question mark.  Return default
**      value if just return pressed, otherwise scan reply using scanFmt string.
**
**      NOTES:
**              1. defFmt and scanFmt are scanf specifiers (e.g. "%f", "%e" )
**              2. carriage return is not echoed.
*******************************************************************************/
int QueryFloat(char *prompt, char *defFmt, char *scanFmt, float *value)
{
char    buf[20];

    while (1)
        {
        printf(prompt);
        if (defFmt)
                if (*defFmt)
                        {
                        printf(" [");
                        printf(defFmt, *value);
                        printf("]");
                        }
        printf(" ? ");

        if (! InputLine(buf, (short) sizeof(buf)))
                return (FALSE);

        if (! *buf)                     /* just return keyed */
                return (TRUE);

        if (sscanf(buf, scanFmt, value))
                return (TRUE);

        if (*prompt != '\n')
                putchar('\n');  /* reprompt and try again */
        }

}       /* QueryFloat() */


/*******************************************************************************
**      InputLine               Input line from keyboard with minimal editing features
**
**      Returns TRUE for all input except ctrl-C and returs NULL terminated string
**      in buffer.  Does not echo or include the terminating return character.
**
**      Typical Usage:
**              char    myline[40];
**              if (! InputLine(myline, sizeof(myline)))
**                      ... error processing for ctrl-C ...
**
**
**      Edit Commands:
**              ctrl-C 0x03             cancel operation, return FALSE
**              ctrl-H 0x08             backspace and erase
**              ctrl-R 0x12             re-display current line
**              ctrl-U 0x15             clear line and start again
**
*******************************************************************************/
int InputLine(char *linebuf, short linelen)
{
    short   i;
    char    ch;
    char    *bufptr;

    bufptr = linebuf;

    while (1)
        {
        fflush(stdout);
//                i = SerTimedGetByte(30000L);    //30sec timeout
//        i = SCIRxGetCharWithTimeout(30000L);    //30sec timeout
        uprintf("SCIRxGetCharWithTimeout needed, apf_util.c\r\n");
        if(i == -1)
        {
            printf("\n\nInput Timeout!\n");
            return(FALSE);
        }
        else
        {
            ch = (char) i;
        }
        switch (ch)
            {
            case '\r' :
            case '\n' :
                *bufptr = '\0';
                return (TRUE);

            case BKSP :
                if (bufptr > linebuf)
                    {
                    bufptr--;
                    putchar(BKSP);
                    }
                break;

            case '\0' :
            case ABORT :
                *linebuf = '\0';
                return (FALSE);

            case REDISP :
                putchar('\n');
                for (i = 0; &linebuf[i] < bufptr; i++)
                    putchar(linebuf[i]);
                break;

            case RESTRT :
                while (bufptr > linebuf)
                    {
                    bufptr--;
                    putchar(BKSP);
                    }
                break;

                *linebuf = '\0';
                return (FALSE);

            default :
                if (bufptr < linebuf + linelen-1)
                    {
                    *bufptr++ = ch;
                    putchar(ch);
                    }
                else
                    {
                    bufptr[-1] = ch;
                    putchar(BKSP);
                    putchar(ch);
                    }
                break;
            }
        }

}       /* InputLine() */


/*******************************************************************************
**      kbhit           Return TRUE if keyboard character available.
*******************************************************************************/
#ifdef DEFDINUSER_IO
int kbhit(void)     //was short
    {

//        return (SerByteAvail());
    return (SCIRxQueuedCount());
    }       /* kbhit() */
#endif

/*******************************************************************************
**      kbflush         Flush any keyboard characters pending and return TRUE if any
**                              were available.
*******************************************************************************/
//short kbflush()
int kbflush(void)
    {
    short   avail = kbhit();

    while (kbhit())
//                SerGetByte();
            //SCIRxGetChar();
        uprintf("kbflush needs imp, apf_util.c\r\n");

    return (avail);

    }       /* kbflush() */


//int TUGetsTmout(TUPort *tup, char *buf, unsigned short buflen, unsigned short seconds)
int TUGetsTmout(char *buf, unsigned short buflen, unsigned short seconds)
{
    register int c;
    register int nchars;
    //RTCTimer TmOut;

    //RTCCountdownTimerSetup( &TmOut, (1000000L * seconds) );         // set timeout

    uprintf("TUGetsTmout is damaged, RTCTimer is not active, apf_util.c\r\n");

    nchars = 0;
    buf[0] = '\0';
#ifdef APFTODO
    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 );
#endif
    return( nchars );

}

//spectrometer command interpreter only breaks on ^M
//int TUPuts(TUPort *tup, char *str)
int TUPuts(char *str)
{

    while( *str ) {
        if( (*str == '\n') || (*str == '\r') )
        {
            uprintf("TUPuts broken, apf_util.c\r\n");
            //TUTxPutByte(tup, '\r', FALSE);
            break;
        }
        //TUTxPutByte(tup, *str++, FALSE);
    }

    //TUTxWaitCompletion(tup);

    return( TRUE );

}



//================================================================================================

//#ifdef APFTODO



/******************************************************************************\
**  pdx_access      POSIX-like access funtion
**
**  access modes (_A_RDONLY, _A_HIDDEN,...) defined in <dirent.h>
\******************************************************************************/

int pdx_access(const *path, int amode)
{
    uprintf("pdx_access in apf_util.c is not implemented\r\n");
#ifdef APFTODO
    struct stat stbuf;

    if (stat(path, &stbuf) == -1)
        return -1;

    return (stbuf.st_attr & amode) ? 0 : -1;

#endif
}               //____ pdx_access() ____//


//******************************************************************************
// Serial I/O Routines
///*****************************************************************************

unsigned short SerGetsTmout(char *buf, unsigned short buflen, unsigned short seconds)
{
    register int c;
    register unsigned short nchars;


    uprintf("SerGetsTmout needs implementation, apf_util.com\r\n");
#ifdef APFTODO
    RTCTimer TmOut;

    RTCCountdownTimerSetup( &TmOut, (1000000L * seconds) );         // set timeout

    nchars = 0;
    buf[0] = '\0';

    while(  RTCCountdownTimeout(&TmOut) != true ) {
        if ( SCIRxQueuedCount() ) {
            switch( c = SCIRxGetByte( 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
#endif
    return( nchars );

}

int SerPuts(char *str)
{

    uprintf("SerPuts needs imp, apf_util.c\r\n");
#ifdef APFTODO
    while (*str) {
        if (*str == '\n')
            SCITxPutChar('\r');
        SCITxPutChar(*str++);
    }
#endif
    return( TRUE );

}

int safegets(char *buffer, int n)
{
    char *ptr;               // ptr used for finding '\n'

    fgets(buffer,n,stdin);   // Get n chars
    buffer[n+1]='\0';        // Set last char to null
    ptr=strchr(buffer,'\n'); // If string contains '\n'
    if(ptr!=NULL)            // Change char to '\0'
        ptr[0]='\0';

    //SCIRxFlush();            // Flush the UART buffer

    return strlen(buffer);   // Return the length

}

/**
 * @file
 * @brief Implementation of #strupr() function.
 *
 * @date 06.08.2011
 * @author Gerald Hoch
 */

char *strupr (char *string)
{
    char * cp;

    for (cp=string; *cp; ++cp)
    {
        if ('a' <= *cp && *cp <= 'z')
            *cp += 'A' - 'a';
    }

    return(string);
}

int MatchACK(char *buf)
{
    char   *srchptr;

    if( (srchptr=strchr(buf,0x0D)) != NULL ) // If string contains CR Change char to '\0'
        *srchptr='\0';
    if( (srchptr=strchr(buf,0x0A)) != NULL ) // If string contains LF Change char to '\0'
        *srchptr='\0';

    strupr(buf);

    if( (strstr(buf, "ACK") != NULL) && (strlen(buf) == 3) )
        return( ACK );
    else if( (strstr(buf, "NAK") != NULL) && (strlen(buf) == 3) )
        return( NAK );
    else
        return( ERROR );

}

//******************************************************************************
// Time Routines
//******************************************************************************

int SyncNextSample( void )
{
//char   ebuf[ERRBUFSIZE];
//unsigned long  secsperday=86400;
    double delta;
#ifdef APFTODO
    // where are we now
    rtc.current_time = RTCGetTime( NULL, NULL );
#endif
    uprintf("SyncNextSample needs imp, apf_util.c\r\n");

    //no sample taken yet!
    if( (apf.isus_reset_flag == TRUE) && (apf.dura_reset_flag == TRUE) ) {
        rtc.alarm_time = rtc.current_time + ((unsigned long)apf.sys_apf_tmout * 3600); //hours to live
        return( 1 );
    }
    else{
        delta = difftime(rtc.alarm_time, rtc.current_time);

        //if delta is too far positive (in the future) then reset
        //if delta is too far negative missedSleeps in main() will take care of it

        if( delta > (double)apf.sys_apf_tmout * 3600.0 )
            rtc.alarm_time = rtc.current_time + ((unsigned long)apf.sys_apf_tmout * 3600);  //hours to live
        return( 2 );
    }

}

void CheckRtcDelta(void)
{
    char ebuf[ERRBUFSIZE];
    double delta;

    uprintf("CheckRtcDelta needs imp apf_util.c");
#ifdef APFTODO
    /* get the current times from CF2 and Dallas DS3234 */
    rtc.CF2_secs    = RTCGetTime( NULL, NULL );
    rtc.DS3234_secs = DS3234_GetTime();

    if( fabs((delta=difftime(rtc.CF2_secs, rtc.DS3234_secs))) > 5.0 ) {
        // update CF2 RTC with DS3234 RTC value, which has a much better drift rate
        RTCSetTime(rtc.DS3234_secs, 0);
        sprintf(ebuf, "RTC Absolute Delta (CF2 minus DS3234) exceeded 5 secs - delta = %+.1lf", delta);
        LogErrorMsg(ebuf, (int)RTC_DELTA_EXCEEDED, apf.sys_message_enable);
    }
#endif
}

int DayOfYear(int yy, int mm, int dd)
{
    int K;

    /* Check for leap year */
    if ((yy % 4 == 0) && ((yy < 1583) || (yy % 100 != 0) || (yy % 400 == 0)))
        K = 1;
    else
        K = 2;

    return (275 * mm / 9) - K * ((mm + 9) / 12) +  (dd - 30);

}

int DayOfWeek(int yy, int mm, int dd)
{

    if (mm < 3) { // convert months to 2...14
        mm += 12;
        yy -= 1;
    }

    return (((dd + (((mm + 1) * 26) / 10) + yy + (yy / 4) + (6 * (yy / 100)) + (yy / 400)) - 1) % 7);
}


#ifdef OLDCODE
void DelaySecs( unsigned short secs )
{
    RTCDelayMicroSeconds( (unsigned long)secs * 1000000UL );
}

void DelayMilliSecs( unsigned short msecs )
{
    RTCDelayMicroSeconds( (unsigned long)msecs * 1000UL );
}
#endif

/*****************************************************************\
**  sleep       delay for absolute or relative (since last) time
**  returns:
**      0       ok
**      1       missed the last sleep interval
**      -1      overflowed the 1.2 hour limit
**  NOTE: THIS ROUTINE IS NOT REENTRANT !
\*****************************************************************/

short Sleep(unsigned long us, bool absolute)
{
    uprintf("Sleep needs imp, apf_util.c\r\n");
#ifdef APFTODO
    static RTCTimer rt;
    static unsigned long lasttime;
    unsigned long donetime;
    short error = 0;

    if (absolute)
    {
reset:
        RTCElapsedTimerSetup(&rt);
        lasttime = RTCElapsedTime(&rt);
        if (error)
            return error;
    }

    donetime = us + lasttime;
    if (donetime < us || donetime < lasttime)
    {
        error = -1;     // we'll overflowed the 1.2h limit
        goto reset;
    }

    lasttime = donetime;            // for next invocation
    if (donetime < RTCElapsedTime(&rt))
        return 1;       // we missed the next interval

    while ((lasttime = RTCElapsedTime(&rt)) < donetime)
        ;

    return error;
#endif

}               //____ sleep() ____//


//******************************************************************************
// Output Routines
//******************************************************************************

void OutputIsusHeader(FILE *fptr)
{
    int i;

    if(fptr == FNULL)
        return;

    uprintf("OutputIsusHeader needs imp, apf_util.c\r\n");

#ifdef APFTODO
    pdcfinfo("C:", &size, &avail);
    DS1683_RdElapsedTimer( &apf.isus_lamp_elp );
    DS1683_RdEventCounter( &apf.isus_lamp_evt );
    hdiv = ldiv(apf.isus_lamp_elp, 3600L);
    mdiv = ldiv(hdiv.rem, 60L);

    fprintf(fptr, "H, Datalogger Serial Num , SN:%04hu\n", apf.sys_serial_num );
    fprintf(fptr, "H, Application      Name , %s\n", strupr(bfile) );
    fprintf(fptr, "H, App Build        Date , %s, %s\n", bdate, btime);
    tp = localtime( &apf.sys_reset_time );
    fprintf(fptr, "H, Power Up Time   (GMT) , %02d/%02d/%02d %02d:%02d:%02d\n", tp->tm_mon+1, tp->tm_mday, tp->tm_year+1900, tp->tm_hour, tp->tm_min, tp->tm_sec);
    rtc.current_time = RTCGetTime( NULL, NULL );
    tp = localtime( &rtc.current_time );
    fprintf(fptr, "H, Current  Time   (GMT) , %02d/%02d/%02d %02d:%02d:%02d\n", tp->tm_mon+1, tp->tm_mday, tp->tm_year+1900, tp->tm_hour, tp->tm_min, tp->tm_sec);
    tp = localtime( &rtc.alarm_time );
    fprintf(fptr, "H, Alarm    Time   (GMT) , %02d/%02d/%02d %02d:%02d:%02d\n", tp->tm_mon+1, tp->tm_mday, tp->tm_year+1900, tp->tm_hour, tp->tm_min, tp->tm_sec);
    fprintf(fptr, "H, Power Active  Timeout , %hu\n", apf.sys_apf_tmout);
//    fprintf(fptr, "H, Persistor CF2-1M Info , S/N:%ld - BIOS:%d.%02d - PicoDOS:%d.%02d\n", BIOSGVT.CFxSerNum, BIOSGVT.BIOSVersion, BIOSGVT.BIOSRelease, BIOSGVT.PICOVersion, BIOSGVT.PICORelease);
    fprintf(fptr, "H, Compact FLASH    Size , %ld\n", size);
    fprintf(fptr, "H, Compact FLASH    Left , %.2f%%\n", (float)(((float)avail/(float)size)*100.0));
    fprintf(fptr, "H, Power Cycle   Counter , %lu\n", apf.sys_por_ctr);
    fprintf(fptr, "H, System Reset  Counter , %lu\n", apf.sys_reset_ctr);

    fprintf(fptr, "H, System Error  Counter , %lu\n", apf.sys_error_ctr);
    fprintf(fptr, "H, Last System     Error , %d\n",  apf.sys_last_error);
    tp = localtime( &apf.sys_error_time );
    fprintf(fptr, "H, Last System ErrorTime , %02d/%02d/%02d %02d:%02d:%02d\n", tp->tm_mon+1, tp->tm_mday, tp->tm_year+1900, tp->tm_hour, tp->tm_min, tp->tm_sec);

    fprintf(fptr, "H, ISUS  Error   Counter , %lu\n", apf.isus_error_ctr);
    fprintf(fptr, "H, Last ISUS       Error , %d\n", apf.isus_last_error);
    tp = localtime( &apf.isus_error_time );
    fprintf(fptr, "H, Last ISUS Error  Time , %02d/%02d/%02d %02d:%02d:%02d\n", tp->tm_mon+1, tp->tm_mday, tp->tm_year+1900, tp->tm_hour, tp->tm_min, tp->tm_sec);

    fprintf(fptr, "H, ISUS Sample   Counter , %lu\n", apf.isus_sample_ctr);
    tp = localtime( &apf.isus_sample_time );
    fprintf(fptr, "H, Last Sample Rec. Time , %02d/%02d/%02d %02d:%02d:%02d\n", tp->tm_mon+1, tp->tm_mday, tp->tm_year+1900, tp->tm_hour, tp->tm_min, tp->tm_sec);

    fprintf(fptr, "H, Fiberlite    Odometer , %02ld:%02ld:%02ld\n", hdiv.quot, mdiv.quot, mdiv.rem);
    fprintf(fptr, "H, Fiberlite      Cycles , %hu\n", apf.isus_lamp_evt);
    fprintf(fptr, "H, Spec Intensity LampON , %hu\n", apf.isus_ref_limit);
    fprintf(fptr, "H, Spec Integration Time , %lu\n", apf.isus_spec_period);
    fprintf(fptr, "H, Spec Pre  scans taken , %hu\n", apf.isus_pre_scans);
    fprintf(fptr, "H, Spec Lite scans taken , %hu\n", apf.isus_scan_num);
    fprintf(fptr, "H, Spec Dark scans taken , %hu\n", apf.isus_dark_num);
    if(Zcoefs <= 0)
        fprintf(fptr, "H, Zceof File    Error   , ZCoefs = %d\n", Zcoefs);
    if(Ecoefs != 256)
        fprintf(fptr, "H, Eceof File    Error   , ECoefs = %d\n", Ecoefs);
    else
//        fprintf(fptr, "H, Calibration      Date , %s\n", CalDate);
//    fprintf(fptr, "H, Sw Calibration   Temp , %.2lf\n", SwCalTemp);
//    fprintf(fptr, "H, Wavelength Fit  Range , %.3f <-> %.3f\n", LambdaData[apf.isus_pixel_beg], LambdaData[apf.isus_pixel_end]);
//    fprintf(fptr, "H, Pixel Fit       Range , %d <-> %d\n", apf.isus_pixel_beg, apf.isus_pixel_end);
    fprintf(fptr, "H, Fitted Concentrations , %d\n", apf.isus_fit_concs);
    fprintf(fptr, "H, Baseline        Model , ");
    if(apf.isus_bsl_model == 1)
        fprintf(fptr, "(ax + b)\n");
    if(apf.isus_bsl_model == 2)
        fprintf(fptr, "(ax^2 + bx + c)\n");
    if(apf.isus_bsl_model == 3)
        fprintf(fptr, "exp(ax + b)\n");
    if(apf.isus_bsl_model == 4)
        fprintf(fptr, "exp(ax^2 + bx + c)\n");
    fprintf(fptr, "H, Br Temp  Compensation , ");
    if(apf.isus_tcomp_mode == TRUE)
        fprintf(fptr, "ENABLED\n");
    else
        fprintf(fptr, "DISABLED\n");
    fprintf(fptr, "H, Bromide Term in Model , ");
    if(apf.isus_salfit_mode == TRUE)
        fprintf(fptr, "will be FIT (to absorbance data)\n");
    else
        fprintf(fptr, "will be FIXED (to external CTD value)\n");

    if(Zcoefs > 0) {
        fprintf(fptr, "H, Zeiss Coefficient Vals, ");
        for(i = 0; i < 5; i++) {
            if(i != 4)
                fprintf(fptr,"%e,", ZeissCoefs[i]);
            else
                fprintf(fptr,"%e\n", ZeissCoefs[i]);
        }
    } //end Zcoefs if
#endif
}

void OutputDuraHeader(FILE *fptr)
{

    if(fptr == FNULL)
        return;

    uprintf("OutputDuraHeader needs imp, apf_util.c\r\n");
#ifdef APFTODO
    pdcfinfo("C:", &size, &avail);

    fprintf(fptr, "H, Datalogger Serial Num , SN:%04hu\n", apf.sys_serial_num );
    fprintf(fptr, "H, Application      Name , %s\n", strupr(bfile) );
    fprintf(fptr, "H, App Build        Date , %s, %s\n", bdate, btime);
    tp = localtime(&apf.sys_reset_time);
    fprintf(fptr, "H, Power Up Time   (GMT) , %02d/%02d/%02d %02d:%02d:%02d\n", tp->tm_mon+1, tp->tm_mday, tp->tm_year+1900, tp->tm_hour, tp->tm_min, tp->tm_sec);
    //rtc.current_time = RTCGetTime( NULL, NULL );
    tp = localtime(&rtc.current_time);
    fprintf(fptr, "H, Current  Time   (GMT) , %02d/%02d/%02d %02d:%02d:%02d\n", tp->tm_mon+1, tp->tm_mday, tp->tm_year+1900, tp->tm_hour, tp->tm_min, tp->tm_sec);
    tp = localtime(&rtc.alarm_time);
    fprintf(fptr, "H, Alarm    Time   (GMT) , %02d/%02d/%02d %02d:%02d:%02d\n", tp->tm_mon+1, tp->tm_mday, tp->tm_year+1900, tp->tm_hour, tp->tm_min, tp->tm_sec);
    fprintf(fptr, "H, Power Active  Timeout , %hu\n", apf.sys_apf_tmout);
    //fprintf(fptr, "H, Persistor CF2-1M Info , S/N:%ld - BIOS:%d.%02d - PicoDOS:%d.%02d\n", BIOSGVT.CFxSerNum, BIOSGVT.BIOSVersion, BIOSGVT.BIOSRelease, BIOSGVT.PICOVersion, BIOSGVT.PICORelease);
    fprintf(fptr, "H, Compact FLASH    Size , %ld\n", size);
    fprintf(fptr, "H, Compact FLASH    Left , %.2f%%\n", (float)(((float)avail/(float)size)*100.0));
    fprintf(fptr, "H, Power Cycle   Counter , %lu\n", apf.sys_por_ctr);
    fprintf(fptr, "H, System Reset  Counter , %lu\n", apf.sys_reset_ctr);

    fprintf(fptr, "H, System Error  Counter , %lu\n", apf.sys_error_ctr);
    fprintf(fptr, "H, Last System     Error , %d\n",  apf.sys_last_error);
    tp = localtime( &apf.sys_error_time );
    fprintf(fptr, "H, Last System ErrorTime , %02d/%02d/%02d %02d:%02d:%02d\n", tp->tm_mon+1, tp->tm_mday, tp->tm_year+1900, tp->tm_hour, tp->tm_min, tp->tm_sec);

    fprintf(fptr, "H, DURA  Error   Counter , %lu\n", apf.dura_error_ctr);
    fprintf(fptr, "H, Last DURA       Error , %d\n", apf.dura_last_error);
    tp = localtime( &apf.dura_error_time );
    fprintf(fptr, "H, Last DURA Error  Time , %02d/%02d/%02d %02d:%02d:%02d\n", tp->tm_mon+1, tp->tm_mday, tp->tm_year+1900, tp->tm_hour, tp->tm_min, tp->tm_sec);

    fprintf(fptr, "H, DURA Sample   Counter , %lu\n", apf.dura_sample_ctr);
    tp = localtime( &apf.dura_sample_time );
    fprintf(fptr, "H, Last Sample Rec. Time , %02d/%02d/%02d %02d:%02d:%02d\n", tp->tm_mon+1, tp->tm_mday, tp->tm_year+1900, tp->tm_hour, tp->tm_min, tp->tm_sec);
    fprintf(fptr, "H, AtoD Reads per Sample , %hu\n", apf.dura_atod_readings);
    fprintf(fptr, "H, AtoD Reading    Delay , %hu\n", apf.dura_atod_delay);
    fprintf(fptr, "H, Samps per AtoD  Recal , %lu\n", apf.dura_samps_per_cal);
#endif
}

void DisplaySystemInfo(void)
{
    char SpecFirmware[128];
    char   *srchptr = NULL;
    uint8_t spec_was_on;
    int ret, nchars;
    float volts, amps, temp, humi, dew_point;

    spec_was_on = apf.isus_spec_pwr;

    ret = mms_specPwrOn();

    uprintf("DisplaySystemInfo needs imp, apf_util.c\r\n");
#ifdef NOCODE

    if( ret == TRUE ) {
        TUPuts( SpecPort, "V\r");
        nchars = TUGetsTmout(SpecPort, SpecFirmware, sizeof(SpecFirmware), 2);
        if( nchars > 0 ) {
            if( (srchptr=strstr(SpecFirmware, "MBARI")) == NULL )
                sprintf(SpecFirmware, "Can't find MBARI!");
        }
    }
    else if( ret == TIMEOUT )
        sprintf(SpecFirmware, "Power On Timeout!");
    else if( ret == ERROR )
        sprintf(SpecFirmware, "TPU UART Error!");
    else
        sprintf(SpecFirmware, "Mystery Power On Error!");


    if( spec_was_on == FALSE )
        mms_specPwrOff();

    uprintf("\n\n  MBARI Serial Number : %04hu\n", sys_serial_num);

    uprintf("\n  CF2 App: %s Date: %s %s\n", strupr(bfile), bdate, btime);
    //printf("  CF2 S/N: %ld - BIOS:%d.%02d - PicoDOS:%d.%02d\n", BIOSGVT.CFxSerNum, BIOSGVT.BIOSVersion, BIOSGVT.BIOSRelease,
      //     BIOSGVT.PICOVersion, BIOSGVT.PICORelease);

    //pdcfinfo("C:", &size, &avail);
    uprintf("  CF Card: Size=%ld Avail=%.2f%%\n\n", size, (float)(((float)avail/(float)size)*100.0));

    DisplayTimes();

    //INA219_ReadVoltageCurrent(&volts, &amps);
    uprintf("\n  System Batt Voltage = %.3f\n", volts);
    uprintf("  System Load Current = %.2e\n", amps);

    //HIH6130_ReadTempHumidity(&temp, &humi);
    dew_point=calc_dewpoint(humi, temp);
    uprintf("  Housing Temperature = %+06.2fC = %+06.2fF\n",temp, CtoF(temp) );
    uprintf("  Housing    Humidity = %5.1f%%  = %5.1fC (DP)\n", humi, dew_point);

    uprintf("  Power Cycle   Count = %lu\n", sys_por_ctr);
    uprintf("  System Reset  Count = %lu\n", sys_reset_ctr);

    uprintf("  System Error  Count = %lu\n", sys_error_ctr);
    uprintf("  Last System   Error = %d\n",  sys_last_error);
    uprintf("  Last Error     Time = %s", ctime( &sys_error_time) );

    uprintf("  ISUS Error    Count = %lu\n", isus_error_ctr);
    uprintf("  Last ISUS     Error = %d\n",  isus_last_error);
    uprintf("  Last Error     Time = %s", ctime( &isus_error_time) );

    uprintf("  DURA Error    Count = %lu\n", dura_error_ctr);
    uprintf("  Last DURA     Error = %d\n",  dura_last_error);
    uprintf("  Last Error     Time = %s", ctime( &dura_error_time) );

    //DS1683_RdElapsedTimer( &isus_lamp_elp );
    //DS1683_RdEventCounter( &isus_lamp_evt );
    hdiv = ldiv(apf.isus_lamp_elp, 3600L);
    mdiv = ldiv(hdiv.rem, 60L);
    printf("  Fiberlite  Odometer = %02ld:%02ld:%02ld = %lu secs\n", hdiv.quot, mdiv.quot, mdiv.rem, isus_lamp_elp);
    printf("  Fiberlite    Cycles = %hu\n", isus_lamp_evt);

    if( srchptr != NULL )
        printf("\n  Spectrometer Status = %s\n", srchptr);
    else
        printf("\n  Spectrometer Status = %s\n", SpecFirmware);

    if( Zcoefs > 0 )
        printf("\n  Zeiss Coef File Found %d coefs loaded.\n", Zcoefs);
    else
        printf("\n  Zeiss Coef File Not Found!\n");

    if( Ecoefs > 0 )
        printf("  Ecoef File Found %d coefs loaded.\n", Ecoefs);
    else
        printf("  Ecoef File Not Found!\n");

#if DURA_SENSOR_TYPE == DURA_III
    if( Tcoefs > 0 )
      printf("\n  Thermistor Coef File Found %d coefs loaded.\n", Tcoefs);
    else
      printf("\n  Thermistor Coef File Not Found!\n");

    if( CalVals == TRUE )
      printf("\n  DuraFET III EEPROM Calibration Values Loaded.\n");
    else
      printf("\n  DuraFET III EEPROM Calibration Values COULD NOT BE Loaded.\n");
#endif


#endif
}

void DisplayTimes(void)
{
    time_t loc_time;
    double diff;

    uprintf("DisplayTimes needs imp, apf_util.c\r\n");

#ifdef APFTODO
    /* get the current times from CF2 and Dallas DS3234 */
    rtc.CF2_secs    = RTCGetTime( NULL, NULL );
    rtc.DS3234_secs = DS3234_GetTime();

    loc_time = rtc.CF2_secs - (long)(sys_tzoffset*3600L);

    printf("  CF2 Power Up  (GMT): %s", ctime(&sys_reset_time) );

    printf("  CF2 RTC Time  (GMT): %s", ctime(&rtc.CF2_secs) );

    printf("  Adjusted Local Time: %s", ctime(&loc_time) );

    printf("  TZ Offset (GMT - LOCAL)  : %+.2lf hrs.\n", (difftime(rtc.CF2_secs, loc_time) / 3600.0));

    diff = difftime(rtc.CF2_secs, rtc.DS3234_secs);
    printf("  RTC delta (CF2 - DS3234) : %+.2lf secs.\n", diff);
#endif
}

void DisplayAlarmTime( void )
{

    uprintf("DisplayAlarmTime needs imp, apf_util.c\r\n");
#ifdef APFTODO
    printf("\n  Last ISUS Samp Time = %s", ctime(&isus_sample_time) );
    printf("\n  Last DURA Samp Time = %s", ctime(&dura_sample_time) );
    printf("\n  Current Wakeup Time = %s", ctime(&rtc.alarm_time) );
    rtc.current_time = rtc.alarm_time - (apf.sys_tzoffset * 3600);
    printf("  Adjusted Local Time = %s", ctime(&rtc.current_time) );
#endif
}

void DisplayChipSelectSettings(void)
{
    int i;
    unsigned short type, size;
    unsigned short CSPAR0_, CSPAR1_, CSBASE_DATA, CSOPTION_DATA;
    unsigned long addr;
    unsigned long CSBASE_ADDR, CSOPTION_ADDR;

    uprintf("DisplayChipSelectSettings needs imp, apf_util.c\r\n");

#ifdef APFTODO
    CSPAR0_ = (unsigned short) *((vunsigned short *)0xFFFA44);
    CSPAR1_ = (unsigned short) *((vunsigned short *)0xFFFA46);

    printf("\n CS Pin Assignment Reg 0 = 0x%0.4X\n", CSPAR0_);
    printf(" CS Pin Assignment Reg 1 = 0x%0.4X\n", CSPAR1_);
    for(i = 0; i <= 5; i++) {
        type = (CSPAR0_ & (0x000C << i*2)) >> 2*(i+1);
        printf(" CS%02d Pin Assignment = %d\n", i, type);
    }
    for(i = 0; i <= 4; i++) {
        type = (CSPAR1_ & (0x0003 << i*2)) >> i*2;
        printf(" CS%02d Pin Assignment = %d\n", i+6, type);
    }

    CSBASE_ADDR   = 0xFFFA4C;
    CSOPTION_ADDR = 0xFFFA4E;

    for(i = 0; i <= 10; i++) {
        CSBASE_DATA   = (unsigned short) *((vunsigned short *)(CSBASE_ADDR + (unsigned long)(i*4)));
        CSOPTION_DATA = (unsigned short) *((vunsigned short *)(CSOPTION_ADDR + (unsigned long)(i*4)));
        addr = (unsigned long)(CSBASE_DATA & 0xFFF8) << 8;
        size = (CSBASE_DATA & 0x0007);
        printf(" CS%02d Base Addr = 0x%0.8lX, Block Size = %d and Option Values = 0x%0.4X\n", i, addr, size, CSOPTION_DATA);
    }
#endif
}

void DisplayFormattedTime(time_t ptime)
{
    static char *wdays[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
    struct tm     *tmptr;

    tmptr = localtime(&ptime);

    tmptr->tm_wday = DayOfWeek( (tmptr->tm_year + 1900), (tmptr->tm_mon + 1), tmptr->tm_mday );
    tmptr->tm_yday = DayOfYear( (tmptr->tm_year + 1900), (tmptr->tm_mon + 1), tmptr->tm_mday );

    printf("%s %d %02d/%02d/%04d %02d:%02d:%02d", wdays[tmptr->tm_wday], tmptr->tm_yday,
           tmptr->tm_mon+1, tmptr->tm_mday, tmptr->tm_year + 1900,
           tmptr->tm_hour, tmptr->tm_min, tmptr->tm_sec);

}

void DisplayLambdaInfo(FILE *fptr)
{
    int i;

    if(fptr == FNULL)
        return;

    if( (Zcoefs > 0) || (Ecoefs == 256) ) {  //wavelength info SHOULD be loaded
        fprintf(fptr, "L,");
        for(i = 1; i <= 256; i++) {
            if(i != 256)
                fprintf(fptr, "%.1f,", LambdaData[i]);
            else
                fprintf(fptr, "%.1f\n", LambdaData[i]);
        }
    }

}

void DisplayByteVal(char *msgstr, uint8_t ByteVal)
{
    int i;
    uint8_t temp;

    temp = ByteVal;

    printf("%s = 0x%02Xh = ", msgstr, temp);

    for(i = 0; i < 8; i++) {
        if((temp & 0x80) != 0)
            printf("1");
        else
            printf("0");
        temp = temp << 1;
    }

    printf("b\n");

}


//******************************************************************************
// Math Routines
//******************************************************************************

int CalcAbs(double *ZeroVals, unsigned short *IntenVals, double *AbsVals, double DCMean, unsigned short fit_pixels)
{
    int i, ret;
    double Inten, Trans;

    ret = 0;

    //printf("CalcAbs Input %lf, %hu, %lf\n", ZeroVals[1], IntenVals[0], DCMean);

    for(i = 1; i <= fit_pixels; i++) {
        Inten = (double)IntenVals[i-1] - DCMean;
        if( Inten > 0.0 ) {
            Trans = ZeroVals[i] / Inten;
            AbsVals[i] = log10(Trans);
        }
        else{
            AbsVals[i] = -1.0;
            ++ret;
        }
    }

    if( ret == 0 )
        return( (int)fit_pixels );
    else
        return( ret );

}

void XformSwEcoefs(double **Ecoefs, double **XformedEcoefs, double *Lambda, double *Tcoefs, double CalTemp, double SamTemp)
{
    int i;
    double L_210, dAbsAtCalT, dAbsAtSamT;

    for(i = 1; i <= 256; i++) {

        if( Ecoefs[i][0] != 0.0 ) {
            L_210 = Lambda[i] - 210.0;

            dAbsAtCalT  = ( Tcoefs[0] + Tcoefs[1] * CalTemp ) *
                          exp( (Tcoefs[2] + Tcoefs[3] * CalTemp) * L_210 );

            dAbsAtSamT  = ( Tcoefs[0] + Tcoefs[1] * SamTemp ) *
                          exp( (Tcoefs[2] + Tcoefs[3] * SamTemp) * L_210 );

            XformedEcoefs[i][0] = Ecoefs[i][0] * ( dAbsAtSamT / dAbsAtCalT );
        }
        else{
            XformedEcoefs[i][0] = Ecoefs[i][0];
        }

        //printf("%lf, %le, %le, %lf, %lf\n", Lambda[i], Ecoefs[i][0], XformedEcoefs[i][0], CalTemp, SamTemp);
    } //end for loop

}

/* Luke's Linear Method, nice and simple!

   void XformSwEcoefs(double **Ecoefs, double **XformedEcoefs, double SolutionRefTemp, double SolutionTemp)
   {
   int  i;
   double deltaTemp;

    deltaTemp = SolutionRefTemp - SolutionTemp;

    for(i = 1; i <= 256; i++) {
      if(Ecoefs[i][0] != 0.0)
        XformedEcoefs[i][0] = Ecoefs[i][0] - (deltaTemp * Ecoefs[i][2]);
      else
        XformedEcoefs[i][0] = Ecoefs[i][0];
      printf("%le, %le, %le, %lf\n", Ecoefs[i][0], XformedEcoefs[i][0], Ecoefs[i][2], deltaTemp);
      }

   }

 */

void InitEcoefMatrix(double **SrcEcoefs)
{
    int i;

    for(i = 1; i <= 256; i++) {
        SrcEcoefs[i][0] = 0.0;
        SrcEcoefs[i][1] = 0.0;
        SrcEcoefs[i][2] = 0.0;
    }

}

void CopyEcoefs(double **SrcEcoefs, double **DstEcoefs)
{
    int i;

    for(i = 1; i <= 256; i++) {
        DstEcoefs[i][0] = SrcEcoefs[i][0];
        DstEcoefs[i][1] = SrcEcoefs[i][1];
        DstEcoefs[i][2] = SrcEcoefs[i][2];
    }

}

void CopySwEcoefs(double **SrcEcoefs, double **DstEcoefs)
{
    int i;

    for(i = 1; i <= 256; i++) {
        DstEcoefs[i][0] = SrcEcoefs[i][0];
    }

}


void InitLambdaArray(double *Lambda, double *ZeissCoefs)
{
    double p;
    double ZC0 = ZeissCoefs[0];
    double ZC1 = ZeissCoefs[1];
    double ZC2 = ZeissCoefs[2];
    double ZC3 = ZeissCoefs[3];
    double ZC4 = ZeissCoefs[4];

// both of these are 10 times slower than below. The pow() seems to be the issue.
//    for( i = 1; i <= 256; i++ ){
//      Lambda[i] = CellNumToLambda(i, ZeissCoefs);
//      Lambda[i] = ZC0 + ZC1*i + ZC2*pow(i, 2.0) + ZC3*pow(i, 3.0) + ZC4*pow(i, 4.0);
//      }

    for( p = 1.0; p <= 256.0; p++ ) {
        Lambda[(int)p] = ZC0 + ZC1*p + ZC2*p*p + ZC3*p*p*p + ZC4*p*p*p*p;
        //printf("%.0lf, %lf\n", p, Lambda[(int)p]);
    }

}

int MatchPixelsToLambda(double *Lambda, int lambda_beg, int lambda_end, unsigned short *pixel_beg, unsigned short *pixel_end)
{
    unsigned short i;
    double min1, min2;
    double delta1, delta2;

    min1=min2=delta1=delta2=10.0;

    for(i = 1; i <= 256; i++) {
        delta1 = fabs((double)(Lambda[i]-lambda_beg));
        delta2 = fabs((double)(Lambda[i]-lambda_end));
        if(delta1 < min1) {
            min1 = delta1;
            *pixel_beg = i;
        }
        if(delta2 < min2) {
            min2 = delta2;
            *pixel_end = i;
        }
    } //end for

    return( TRUE );

}

double CellNumToLambda(int cell, double *ZeissCoefs)
{
    double lambda = 0.0;

    lambda = ZeissCoefs[0] + ZeissCoefs[1]*cell
             + ZeissCoefs[2]*pow(cell, 2.0)
             + ZeissCoefs[3]*pow(cell, 3.0)
             + ZeissCoefs[4]*pow(cell, 4.0);

    return( lambda );

}

void FloatVectorMinMax(unsigned short end, float data[], float *min, float *max)
{
    unsigned short i;

    *max = data[0];
    *min = data[0];

    for(i = 0; i < end; i++) {
        if(data[i] > *max)
            *max = data[i];
        else if(data[i]< *min)
            *min = data[i];
    }

}

void FloatVectorMeanStdDev(unsigned short end, float data[], float *mean, float *stdev)
{
    unsigned short i;
    float sum, stdvar;

    sum = stdvar = 0.0;
    *mean = *stdev = 0.0;

    for(i = 0; i < end; i++)
        sum += data[i];
    *mean = (sum/end);

    for(i = 0; i < end; i++)
        stdvar += pow((data[i] - *mean), 2.0);
    stdvar /= (end - 1);
    *stdev = sqrt(stdvar);

}

void ShortVectorMinMax(unsigned short end, unsigned short data[], unsigned short *min, unsigned short *max)
{
    unsigned short i;

    *max = data[0];
    *min = data[0];

    for(i = 0; i < end; i++) {
        if(data[i] > *max)
            *max = data[i];
        else if(data[i]< *min)
            *min = data[i];
    }

}

void ShortVectorMeanStdDev(unsigned short end, unsigned short data[], float *mean, float *stdev)
{
    unsigned short i;
    float sum, stdvar;

    sum = stdvar = 0.0;
    *mean = *stdev = 0.0;

    for(i = 0; i < end; i++)
        sum += (float)data[i];
    *mean = (sum/end);

    for(i = 0; i < end; i++)
        stdvar += pow((data[i] - *mean), 2.0);
    stdvar /= (end - 1);
    *stdev = sqrt(stdvar);

}

float CtoF(float degC)
{
    return( 9.0/5.0 * degC + 32.0 );
}

/**
 * Evaluates p(x) for a polynom p.
 * Calculates the value of polynom p at x accordings to
 * Horners schema.
 * @param p polynom.
 * @param x value to be inserted into the polynom.
 * @return calculated polynom value.
 */
double poly(double x, int degree, double p[])
{
    double retval = 0.0;
    int i;

    for (i = degree; i >= 0; i--)
        retval = retval * x + p[i];
    return retval;
}

/* Conversion from resistance to temperature.
 * Calculates and returns temperature for given resistance.
 * @param t resistance (in Ohm).
 * @return corresponding temperature.
 */
double rtot(double r, double a[])
{
    double ti;

    ti = poly(log(r), 3, a);
    ti = 1.0 / ti + TABS;
    return ti;
}

/**
   Conversion from temperature to resistance.
 * Calculates and returns resistance for given temperature.
 * @param t temperature (in degree Celsius).
 * @return corresponding resistance.
 */
double ttor(double t, double a[])
{
    double r;
    double u, v, p, q, b, c, d;

    t = t - TABS;
    d = (a[0] - 1.0 / t) / a[3];
    c = a[1] / a[3];
    b = a[2] / a[3];
    q = 2.0 / 27.0 * b * b * b - 1.0 / 3.0 * b * c + d;
    p = c - 1.0 / 3.0 * b * b;
    v = -pow(q / 2.0 + sqrt(q * q / 4.0 + p * p * p / 27.0), 1.0 / 3.0);
    u =   pow(-q / 2.0 + sqrt(q * q / 4.0 + p * p * p / 27.0), 1.0 / 3.0);
    r  = exp(u + v - b / 3.0);
    return r;
}

unsigned short fCrc16Bit(const unsigned char *msg)
{
    unsigned short crc = 0xffff;

    uprintf("fCrc16Bit needs imp, apf_util.c\r\n");
#ifdef APFTODO
    while (*msg) {
        crc = updcrc((0xff & *msg), crc);
        msg++;
    }

    crc = updcrc(0,updcrc(0,crc));
#endif
    return( (crc & 0xffff) );

}

//#endif


void DisplayFile(void)
{

    uprintf("DisplayFile needs imp, apf_util.c\r\n");
#ifdef APFTODO
    char fnbuf[MAXINBUFF];
    char cmdbuff[MAXINBUFF];
    int ret;
    FILE *flash_file;

    printf("\nEnter Filename: ");
    ret = safegets(fnbuf, MAXREAD);
    if (ret != 0) {
        flash_file = fopen(fnbuf, "r");
        if (flash_file == FNULL) {
            printf("\nCould not locate file: %s\n", fnbuf);
            return;
        }
        fclose(flash_file);
    } else {
        printf("\nNo name was entered\n");
        return;
    }

    printf("\nOutputFileStart\n");
    sprintf(cmdbuff, "type %s", fnbuf);
    execstr(cmdbuff);
    printf("OutputFileEnd\n");
#endif
}

void RenameFile(void)
{
    uprintf("RenameFile needs imp, apf_util.c\r\n");
#ifdef APFTODO
    char fn1buf[MAXINBUFF];
    char fn2buf[MAXINBUFF];
    char legal[] = ":\\.-_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    int lchar, ret, i;
    size_t lentot;
    FILE *flash_file;

    printf("\nEnter Old Filename: ");
    ret = safegets(fn1buf, MAXREAD);
    if (ret != 0) {
        flash_file = fopen(fn1buf, "r");
        if (flash_file == FNULL) {
            printf("\nCould not locate file: %s\n", fn1buf);
            return;
        }
        fclose(flash_file);
    } else {
        printf("\nNo name was entered\n");
        return;
    }

    printf("\nEnter New Filename: ");
    ret = safegets(fn2buf, MAXREAD);
    if (ret != 0) {
        strupr(fn2buf);
        lentot = strlen(fn2buf);
        for (i = 0; i < lentot; i++) {
            lchar = fn2buf[i];
            if (strchr(legal, lchar) == NULL) {
                printf("\nIllegal char %c at %d in filename!\n", lchar,
                       i + 1);
                return;
            }
        }
    }                           // end ret if
    else {
        printf("\nNo name was entered\n");
        return;
    }

    if (strcmp(strupr(fn1buf), fn2buf) == 0) {
        printf("\nFilenames are the same!\n");
        return;
    }

    rename(fn1buf, fn2buf);

    flash_file = fopen(fn2buf, "r");
    if (flash_file == FNULL) {
        printf("\n%s could not be renamed!\n", fn1buf);
        return;
    }
    fclose(flash_file);
    printf("\n%s was renamed to %s!\n", fn1buf, fn2buf);
#endif
}

void EraseFile(void)
{
    uprintf("EraseFile needs imp, apf_util.c\r\n");
#ifdef APFTODO
    char fnbuf[MAXINBUFF];
    int ret;
    ulong input_var;
    FILE *flash_file;

    printf("\nEnter Filename: ");
    ret = safegets(fnbuf, MAXREAD);
    if (ret != 0) {
        flash_file = fopen(fnbuf, "r");
        if (flash_file == FNULL) {
            printf("\nCould not locate file: %s\n", fnbuf);
            return;
        }
        fclose(flash_file);
    } else {
        printf("\nNo name was entered\n");
        return;
    }

    printf("\n");
    input_var = 0;
    input_var = QueryYesNo(fnbuf, TRUE);
    if (input_var == TRUE) {
        printf("\nBe patient it could take awhile.\n");
        ret = remove(fnbuf);
        if (ret == 0)
            printf("\n%s Was Deleted!\n", fnbuf);
        else
            printf("\n%s Could NOT be Deleted!\n", fnbuf);
    }
#endif
}

void EraseFiles(void)
{

}

void ScanDir( void )
{
    uprintf("ScanDir needs imp, apf_util.c\r\n");
#ifdef APFTODO
    char name[128];
    char fnbuf[MAXINBUFF];
    char fpbuf[MAXINBUFF];
    struct dirent   de;
    struct stat fs;
    FILE *infp = NULL;
    int    i, ret;

    memset(fpbuf, '\0', sizeof(fpbuf));
    printf("\n\nEnter Filepath: ");
    ret = safegets(fpbuf, MAXREAD);
    if (ret == 0) {
        fpbuf[0] = 'C';
        fpbuf[1] = ':';
    }

    memset(fnbuf, '\0', sizeof(fnbuf));
    printf("\n\nEnter Filename: ");
    ret = safegets(fnbuf, MAXREAD);
    if (ret == 0) {
        fnbuf[0] = '*';
        fnbuf[1] = '.';
        fnbuf[2] = '*';
    }

    i=0;
    printf("\n\n");
    if (DIRFindFirst((char *)fpbuf, &de) != dsdEndOfDir)
    {
    do
    {
        if (DIRMatchName((char *) de.d_name, (char *)fnbuf)){
            if ((de.d_attr & (_A_SUBDIR | _A_VOLID)) == 0){
                memset(name, '\0', sizeof(name));
                snprintf(name, sizeof(name), "%s\\%s", fpbuf, (char *)de.d_name);
                if ((infp=fopen(name, "r"))!=NULL){
                    ++i;
                    stat(name, &fs);
                    printf("%3d  %24s %12ld  %s", i, (char *)fs.st_path, fs.st_size, ctime(&fs.st_mtime) );
                    fclose(infp);
                }
            }
        }
    } while (DIRFindNext(&de) != dsdEndOfDir);
    }

    DIRFindEnd(&de);
#endif
    return;
}

void FNameError(void)
{
    uprintf("Filename can only have 8 char NAME and 3 char EXTENSION!\n");
}

void RangeError(long val1, long val2)
{
    uprintf("\n  Invalid Entry, valid range = %ld - %ld\n", val1, val2);
}
